[
  {
    "title": "Start a private evaluation",
    "url": "/docs/console-v1/quickstart.html",
    "text": "A synthetic-first guide to the separate private console. 1. Know which surface you are using This website and the Evidence Room are static. They do not connect to cloud accounts or customer data. The API-backed console is a separate private application; get its URL and access instructions from the operator. 2. Agree on scope before connecting anything Start with synthetic records. Agree on the source, account/project and Region, network, storage, retention, owner, time limit and budget before enabling a worker. This guide does not approve provisioning or spend. 3. Sign in and choose a supported source Use an operator-issued account; workspace signup is disabled by default. The current candidate accepts narrow AWS CloudTrail, Google Workspace and synthetic CloudWatch shapes. Saving a source is not proof that a provider is connected. 4. Import and verify Import native synthetic records or use an approved acquisition worker. Follow the operation receipt until it reports committed; HTTP 202 means only that the batch was accepted into the durable inbox. 5. Review an alert and case Validate a supported rule, then inspect its alert and cited evidence. Record human triage. Case workflows can make limited local case changes after a person approves the exact plan; they do not contain cloud resources."
  },
  {
    "title": "Sign-in and permissions",
    "url": "/docs/console-v1/authentication.html",
    "text": "How accounts, workspaces and source tokens are scoped. Session protocol POST /api/v1/session accepts username and password. The response includes user and expires_at; the opaque salad_session cookie is HttpOnly, SameSite=Strict, Path=/, and expires after eight hours. Secure is set when configured. PostgreSQL stores session digests, not plaintext cookies. GET /api/v1/session resolves the current user; DELETE revokes the current session. No API key or OAuth client-credentials grant is implemented for general console access. CSRF applies before login too Every non-GET/HEAD session-protocol mutation—including login and signup—requires Origin exactly equal to the configured console origin and X-Console-CSRF: 1. Except DELETE, it also requires Content-Type: application/json even for a bodyless POST; send {} for preflight, token rotation and enable/disable requests. A browser's same-origin fetch does not automatically add an Origin to every GET; GET needs neither CSRF nor JSON headers. Do not bypass this protocol by relaxing the origin check. Gated evaluation workspaces GET /api/v1/session/options is public. POST /api/v1/session/signup requires workspace_name, username and password; password_confirmation is optional but must match if present. Usernames are lowercased ASCII [a-z0-9_.@+-], 3–64 bytes. Passwords are 12–128 UTF-8 bytes, not characters. Workspace names are nonblank, control-character-free and at most 128 UTF-8 bytes; names may collide. Tenant/role fields are rejected. A new isolated workspace receives its own operator role and no inherited evidence, rules, cases, sources or inventory. Duplicate username and the 32-workspace cap use generic workspace_creation_unavailable. No email verification is claimed. Password and access limits Passwords are salted Argon2id hashes. Login/signup share a PostgreSQL limit of 20 attempts per minute; at most two password jobs run concurrently per process. Bootstrap accounts have a stricter 16-byte password minimum. An operator must explicitly rotate the configured bootstrap password version as well as the password; changing a secret alone does not reset the stored account. Existing expiring sessions survive password rotation. Production TLS/SSO and broader account lifecycle controls remain separate qualification gates. Source tokens are not agent admin keys A session operator rotates a token with POST /api/v1/sources/{id}/token. It is shown once; only its SHA-256 hash persists. Rotation revokes the prior token. Bearer authentication permits only POST ingestion for that exact source and GET operation status belonging to that source and tenant. It grants no source configuration, query, rule, case or approval authority. Bearer ingestion does not require browser cookies, Origin or CSRF. Supplying a bearer token selects source-token authentication rather than falling back to a cookie. Human authority Costs, source-token rotation and approval/rejection require the operator role. Other documented session routes still enforce tenant scope. Workspace operators do not gain another workspace's authority. Keep human approval sessions outside agent automation. System One is planned advisory support; inference is currently disabled, cannot authorize actions, and never gates deterministic delivery."
  },
  {
    "title": "Add sources and ingest events",
    "url": "/docs/console-v1/sources.html",
    "text": "Supported inputs, importing native records and what connection status means. Supported native shapes—not blanket connectors The implemented source kinds are aws_cloudtrail (CreateAccessKey with required access-key response evidence only), google_workspace (login failure/success and Drive download, one activity per native record), and cloudwatch_sample_service (synthetic auth.login denied, numeric schema_version:1, no actor/sensitive audit payload). Other CloudTrail event types and arbitrary Workspace admin events are not implied. GCP Cloud Logging, Azure Activity Log and other provider families remain planned. All current mappings are partial. Minimal onboarding sequence Choose the source kind; preview exact permissions, allowed account/customer identity, selected Region, data and storage scope; configure a manual import or attach-existing worker; run preflight; send an approved canary; inspect native evidence and operation lane receipts; then inspect source health. Saving a source does not make it connected. Canary evidence is not verification of provider credentials. OAuth self-service and automatic resource provisioning are not complete. Transport configuration Allowed config keys are transport, log_groups, queue_url, application and non-secret credential_reference. Supported transports are manual, aws_sqs_cloudtrail, aws_cloudwatch and google_workspace, with a matching kind. CloudWatch requires an explicit 1–10 log-group allowlist (each at most 512 bytes), including manual sample imports; SQS requires queue_url. Workspace application is login, drive or admin, but choosing admin does not add unsupported mappings. Keep provider credentials in the separately scoped acquisition worker, never a source API payload. Read preflight literally POST /api/v1/sources/{id}/preflight with JSON headers and {}. Manual sources can report ready_for_import. Provider paths report external_worker_required with provider_verified:false. A validated canary can report canary_received; list status may become receiving when retained events exist. None of these are a claim that the API performed live provider identity checks. Ingest with a scoped source token NATIVE_BATCH_FILE must contain approved native records under records (CloudTrail Records is also accepted), not a generic invented event. SOURCE_ID is the UUID returned at source creation. SOURCE_TOKEN is the secret issued once by the operator. Do not log the Authorization header. Maximum 1,000 records and 8 MiB request. The endpoint retains exact request bytes plus record ordinal/provenance. 202 is not source acknowledgement The accepted response records durable PostgreSQL inbox/receipt state and accepted/replayed/quarantined counts. Poll GET /api/v1/operations/{operation_id} with the same token until status is committed. Inspect hot/archive/stream lane receipts. Do not advance a durable cursor or acknowledge SQS on HTTP 202. Pending, failed or outcome-unknown dependencies are not permission to acknowledge. Invalid records need durable raw-batch/quarantine disposition. Replay and retained limits Deduplication binds tenant/source/native key and content digest. Identical native replay does not duplicate alert, case, workflow or audit effects; changed content under the same key is conflict/quarantine, not overwrite. Replayed requests still consume raw-batch/retained-byte capacity. Each evaluation tenant is capped at 10,000 unique normalized events, 10,000 raw batches and 256 MiB retained request bytes. These are safety limits, not retention or throughput promises."
  },
  {
    "title": "Events and evidence",
    "url": "/docs/console-v1/schemas.html",
    "text": "Supported event shapes, retained originals and provenance. Pinned target, partial coverage OCSF 1.1.0 is the normalization target. Current handwritten mappings are partial, not generated coverage of the OCSF catalog. Native source/account/customer identity, event keys and timestamps are validated against configured scope. Invalid or unsupported data is durably quarantined; do not assume every producer event normalizes successfully. Evidence fields Query event items include id, source_id, source_key, event_time_ms, class_uid, status_id, activity_name, actor, ocsf and raw_reference. UUIDs identify console entities; public API timestamps are epoch milliseconds unless a producer-native payload preserves its own representation. GET /api/v1/events/{id} is tenant-authorized and includes raw_base64 and raw_digest from the retained request batch. The batch may contain multiple records; use record ordinal and provenance, not an assumption that one batch equals one event. Raw references can be null while archive delivery is pending. CloudWatch sample bounds Worker envelopes contain message, event_id, timestamp_ms, ingestion_time_ms, log_group and optional log_stream. The native JSON message must satisfy the supported synthetic shape, log-group allowlist, numeric schema_version and five-minute occurrence/timestamp skew checks. A successful sample does not qualify arbitrary application logs or sensitive audit payloads. Narratives cite evidence, not confidence theater A deterministic alert narrative includes summary, observed_facts, citations, timeline, uncertainty, suggested_review and inference status. citations/evidence_ids reference retained event UUIDs. Check the original native evidence, rule version and scope before asserting intent. A rule match is not proof of compromise, an ATT&CK tag is candidate metadata, and a missing field is not evidence that an activity did not occur. Inference is disabled and delivery_independent:true. Retention is a deployment policy Customer-owned raw evidence is canonical. ClickHouse query retention is not the same as raw-byte retention or Iceberg historical reach. Qualify storage encryption/access, holds, archival/retrieval, snapshot maintenance, deletion propagation, backup and restore in the approved deployment. This evaluation does not make regulatory compliance, immutability or unlimited retention claims."
  },
  {
    "title": "Search recent and archived events",
    "url": "/docs/console-v1/queries.html",
    "text": "Supported filters and the separate historical query path. Hot filters POST /api/v1/events/query accepts start_time_ms, end_time_ms, source_id, class_uid, status_id, text and limit. Unknown fields—including sql—are rejected. Time defaults to the last 24 hours; maximum range is 31 days. limit defaults to 100 with a maximum of 500. text is at most 256 UTF-8 bytes and is a case-insensitive substring over activity_name or actor, not arbitrary JSON/full-text search. Tenant scope is injected server-side. Execution bounds The hot path uses parameterized ClickHouse SQL with a five-second engine limit, 256 MiB memory bound, 64 MiB read-byte bound, two threads and shared query concurrency control. The response includes items, scope:hot and query:{sql,rows,elapsed_ms}. SQL is a preview of the authorized operation, not a credential or an executable permission grant. A row cap alone is not a scan-cost guarantee; dependency errors and resource limits must remain visible. Historical scope is explicit POST /api/v1/history/query uses the authorized PyIceberg archive path over Iceberg/Parquet. Only start_time_ms, end_time_ms, source_id and limit are supported with the same time/row bounds. class_uid, status_id and text are explicitly rejected as unsupported_history_filter; no silent fallback to hot data. Archive unavailability fails explicitly. Historical event retrieval is not historical audit retrieval. Presto/Trino integration and an advanced SQL editor/gateway are planned, not connected. Python standard-library example Use only an authorized read/query session. SALAD_SESSION contains the opaque cookie value from your own private environment; never place it in source or print it. Set the origin variables to your operator-provided values. The example prints evidence IDs, not raw records or the cookie. Node standard-library example Node.js 18+ has built-in fetch; no third-party SDK or package is required. Do not reuse a human approval session as an autonomous agent credential. This GET only lists alerts in the authorized workspace."
  },
  {
    "title": "Rules, alerts and cases",
    "url": "/docs/console-v1/detections.html",
    "text": "The supported rule subset and how alerts link to cases. Signals are not a new API endpoint Signals is the product-level view of observations and rule matches. The current API exposes retained events, rules, alerts and cases; there is no /signals endpoint. A matched event becomes a durable alert with a rule/version and cited evidence; its case holds investigation state. An alert is not automatically a confirmed incident. Triage records a human disposition and immutable application audit attribution. Strict Sigma-like subset Allowed top-level keys: id, title, level, tags, logsource and detection. logsource contains product and service; product is aws or google_workspace and service must be an implemented source kind. detection contains selection and condition:selection. Selection allows integer class_uid/status_id and exact string activity_name/provider/source/actor. All fields are conjunctive. Unsupported keys, modifiers, arrays, Boolean expressions, count, correlation, joins and windows fail closed. A timeframe key does not establish backend support. This is deliberately not full Sigma. A stateless native CloudTrail rule Validate this YAML with POST /api/v1/rules/validate as {yaml:...}. It is a rule example, not a claim that a live source is connected. YAML is at most 64 KiB; title at most 256 UTF-8 bytes; at most six selection fields and 32 tags. Store a validated rule with POST /api/v1/rules; persistence alone does not mean enabled. Actual pipeline state matters Enable/disable calls coordinate Arroyo pipeline state. An enabled claim requires observed job state Running; a background observer and GET /rules reconcile state. Durable creation intent and deterministic-name reconciliation prevent blind repeated creates after ambiguity. Disable requests checkpoint-stop and remain pending/unknown until terminal. Stateful/windowed semantics remain planned until replay, deduplication and late-data behavior are separately qualified. Durable delivery boundary Long-lived Arroyo pipelines use Kafka-compatible input/output. Detection offsets commit only after the PostgreSQL alert/case/narrative/local-outbox/audit transaction commits or an existing result is reconciled. An HTTP webhook alone is not the durable alert boundary. Broker, checkpoint and metadata durability are deployment responsibilities; the single-node topology does not establish production recovery or HA. Review, triage, then manage the case GET /alerts/{id} includes deterministic narrative and evidence. POST /alerts/{id}/triage records disposition and note: new, investigating, true_positive, false_positive, benign, insufficient_evidence or closed. Cases use open/investigating/closed and optimistic version checks. ATT&CK views reflect declared tags with evidence context—not confirmed coverage of every technique. External ticket delivery is planned; the current outbox is local-console delivery only. AI is off; planned System One advice cannot suppress delivery or authorize response."
  },
  {
    "title": "Human review and case actions",
    "url": "/docs/console-v1/workflows.html",
    "text": "Limited local case changes require review and approval. What can execute today Reusable workflows support only case.assign, case.set_priority and case.add_note. Definitions have 1–20 typed steps. Assignee is nonempty and at most 128 UTF-8 bytes; notes are nonempty and at most 4096 bytes; priority is low, medium, high or critical. No scripts, network URLs, external tickets or cloud containment. This is real local case management, not a simulated cloud action. Create a bounded workflow POST /api/v1/workflows using a cookie session and the same-origin/CSRF/JSON protocol. Review the returned workflow id/version before preview. Preview has no case effects POST /api/v1/workflows/{id}/preview with {case_id:...} creates a persisted plan, not an action on the case. The response includes plan_id/id, digest, steps, case_version, workflow_version, policy_version, expires_at and status:awaiting_approval. Plans expire after ten minutes. The digest binds the exact preview; do not reconstruct or guess it. Human approval is a separate decision An authenticated human operator checks the evidence, intended effects, current case revision and expiry before POST /api/v1/actions/{id}/approve with digest and expected_version (the preview case_version). The server rechecks case/workflow/policy versions, authority, expiry and state inside the transaction. Missing/stale revision or mismatched digest fails with 409; preview again after reviewing changes. POST /actions/{id}/reject requires digest and operator role. No blind retry on timeout GET /api/v1/actions lists persisted plans and receipts; locate the plan by id. There is no GET /actions/{id}. Repeated identical approval does not execute twice; an opposite decision conflicts. A verified receipt records committed outcome, actor, digest and resulting case revision. After timeout, reconcile the persisted action before resubmitting; outcome_unknown means uncertainty, not success or permission to create another plan. Inference/model output cannot approve. Case editing is versioned too PATCH /api/v1/cases/{id} requires expected_version. Allowed fields are title, status, assignee, priority and note. open↔investigating, open/investigating→closed and closed→open are supported; closed→investigating is not. Missing/stale versions return 409. Read again and review concurrent work; never overwrite by inventing a version."
  },
  {
    "title": "Private deployment and data retention",
    "url": "/docs/console-v1/deployment.html",
    "text": "Private deployment and data retention; production qualification is in progress. Private evaluation profile The implemented deployment candidate uses a private-compatible Compose stack: Rust API/static console, PostgreSQL operational state, ClickHouse hot analytics, Redpanda durable fan-out, Arroyo streaming, an internal archive service, PyIceberg with a PostgreSQL SQL catalog, and S3-compatible storage. Local evaluation may use a local object store. A container volume is not customer S3 and does not establish S3 compliance. No datastore ports should be exposed. Operator access is private/loopback; public ingress is not required. Full in-VPC path The entire product—including authenticated UI/API, state, catalog, checkpoints, audit/observability and optional inference—has an in-VPC deployment requirement/path with customer-controlled storage and no mandatory vendor control plane. Hosted egress is opt-in. Current inference is disabled. A static product site can be hosted separately without receiving SIEM evidence; these docs do not authorize hosting or deployment. What the evaluator must qualify Agree on project, selected Region, source scope, networking, permissions, egress, secrets handling and exact cost change set before apply. Pin artifacts and record digests. Qualify tenant isolation, source acknowledgement, independent lane recovery, broker offsets, Arroyo metadata/checkpoints, backup/restore and process restart. The single-node evaluation is not HA. Local tests and one bounded synthetic run are not production cloud qualification. Retention, holds and recovery Define raw and normalized retention separately. Qualify Iceberg snapshots/maintenance, Parquet retrieval, object policy, holds and deletion propagation; PostgreSQL raw inbox safety caps are not a long-term retention promise. Specify recovery-point/recovery-time goals and test restore. No generated full OCSF coverage, compliance certification, tamper-proof audit or automatic disaster recovery claim is made. Acquire without leaking credentials Provider-native short-lived credentials remain in separately scoped acquisition workers. The console receives non-secret references and a source-scoped ingestion token, not provider access keys. Attach-existing and manual evaluation paths are distinct from future provisioning/OAuth self-service. Approve destinations and egress before introducing any external delivery integration."
  },
  {
    "title": "Costs and operational status",
    "url": "/docs/console-v1/costs.html",
    "text": "What is estimated, measured, billed or unavailable. Cost API boundary GET /api/v1/costs is operator-only and reads a fixed server-configured JSON snapshot, schema log-salad-cost-inventory-v1, maximum 1 MiB. A snapshot tenant_id must match the session tenant. No path comes from the request. The API makes no provider inventory or billing calls. Unreadable, oversized or invalid configured snapshots fail explicitly. Four different claims Estimated: a model based on assumptions and usage inputs, not a bill. Observed: measured inventory/usage at a stated time and scope, not automatically billing truth. Billed: explicitly sourced billing evidence for a stated period, not an extrapolated estimate. Unavailable: not connected, missing or unknown—not zero. The labels are provenance categories; they are not a claim that every snapshot has all four, or a new enum enforced on every snapshot field. Default is unavailable Without a configured snapshot the response has as_of:null, clusters:[], summary:{status:unavailable} and a limitation that cloud inventory and billing are not connected. An empty list is not free infrastructure. Keep unknown resources separate from known totals, and show the snapshot timestamp before comparing values. Budget communications are not connected; no automated email, webhook or provider budget enforcement is promised. Plan the whole resource lifecycle Evaluate compute, retained block volumes, object bytes/requests, archive maintenance, data transfer and private endpoint hourly/data processing charges. Stopping idle compute can leave storage and endpoints billable. Set an approved evaluation budget, owner, duration and manual stop/review plan. Prices and savings depend on approved deployment scope; this website publishes no fixed price or cost guarantee. Status is evidence Overview counts and lane status belong to the private console, not this static website. not_observed, unavailable, pending and outcome_unknown must remain visible. No live badge is derived from a rendered diagram. Inspect persisted operation receipts, sink evidence and timestamps before asserting health or completion."
  },
  {
    "title": "Troubleshooting",
    "url": "/docs/console-v1/troubleshooting.html",
    "text": "Check receipts and persisted state before retrying. 401 or expired session Confirm the private console origin and cookie jar, not the static docs origin. Reauthenticate when the eight-hour cookie expires; logout revokes one session. An invalid bearer token does not fall back to a valid cookie. Never paste passwords, cookies or tokens into an issue report. 403 same_origin_required For login/signup and session mutations send Origin exactly equal to the configured origin, X-Console-CSRF:1 and application/json. DELETE may omit JSON. Bodyless POST still needs the header; send {}. Do not add wildcard CORS or disable CSRF. A source-token scope denial is different: use only the source's own ingest path and its own operation receipts. Registration unavailable or throttled Check /session/options. Signup is disabled by default; duplicates and the 32-workspace cap intentionally use a generic error. Validate ASCII username length and UTF-8 password/workspace-name byte lengths. Login/signup share 20 attempts per minute; wait rather than retrying aggressively. A new workspace begins empty and cannot query another workspace's evidence. Accepted but still pending HTTP 202 proves durable inbox acceptance only. Poll /operations/{id}; inspect each lane status, attempts, last_error and receipt. Do not acknowledge upstream until committed. Recover or reconcile the failing dependency before source progress. A durable quarantine disposition can commit without normalized events; inspect accepted/replayed/quarantined counts, not just HTTP success. Replay or native-key conflict Identical source-key/content replay should not duplicate durable detections. Different content under a retained key is quarantined; preserve the original and examine producer identity/key behavior. Do not rewrite the original record to force acceptance. Replays still retain request receipts and consume inbox byte/batch limits; evaluation_inbox_capacity needs operator review, not unbounded retry. History unavailable or unsupported filter Historical queries accept time/source/limit only. Remove unsupported class/status/text filters only if that still answers the authorized question. Confirm archive availability; never replace historical scope with a hot query without telling the reviewer. A narrower hot result is not evidence that no historical event exists. Rule not enabled or outcome_unknown Validate the strict stateless subset first. GET /rules reconciles observed state; inspect desired versus observed pipeline state and safe errors. Running is required for enabled. Ambiguous pipeline creation must reconcile its durable intent/name, not blindly create another pipeline. Disable may remain pending until checkpoint stop reaches a terminal state. 409 approval or case conflict Read the current case and persisted action list. Recheck digest, case_version, workflow_version, policy and expiry. A changed case requires renewed review and preview; never change expected_version merely to force approval. After an unknown HTTP outcome inspect the stored receipt before retry. A repeated matching decision is reconciled; an opposite decision conflicts. Cost unavailable or query limit Unconfigured inventory/billing is unavailable, not zero. An invalid snapshot fails explicitly. Narrow time and row bounds after query resource errors; a row limit alone does not guarantee low scan cost. Preserve safe error codes and operation IDs for the operator, with no raw records, credentials or provider identifiers in general diagnostics."
  },
  {
    "title": "Current capabilities and limits",
    "url": "/docs/console-v1/limits.html",
    "text": "Implemented candidate behavior versus planned or unavailable features. Implementation snapshot This documentation describes console-v1 at source revision 23fdccfaa88f69e858769f1dad70f82739e2740f. The source of behavior is the implemented API/auth/query/rule/workflow modules and console-v1 contract. Public docs are a curated projection, not a dump of internal runbooks. Implemented candidate is not qualified deployment, generally available service, or proof that a connector is live in your environment. Supported candidate surface Same-origin opaque cookie sessions; explicitly gated isolated evaluation signup; source-scoped bearer ingestion/status; partial native-to-OCSF mapping; bounded hot queries with SQL preview; time/source historical filters through PyIceberg; strict stateless scalar rules; deterministic cited narratives; versioned cases and approved local case workflows; local-console outbox; operator-configured cost snapshot. Planned or separately unqualified Production HA/TLS/SSO and account lifecycle, generated full OCSF coverage, stateful/windowed Sigma, advanced SQL editor, Presto/Trino integration, OAuth self-service, broad cloud/SaaS connectors, external ticket delivery, budget communications, cloud containment and production retention/holds/recovery. System One advisory is planned with no action authority; actual inference is disabled. Unrestricted raw SQL is not offered. Machine-readable entry points Use /llms.txt, /docs/console-v1/openapi.json and /docs/console-v1/capabilities.json. Source-versioned Markdown pages and the publication manifest are linked in the docs. Machine clients should check contract_version, source_revision, stage and supported/planned boundaries before selecting an operation. There is no published third-party SDK, agent MCP endpoint, unrestricted SQL API or hidden /signals endpoint in this surface. Safety bounds, not service promises Maximum 8 MiB/1,000 records per ingestion, 500 rows/31 days per query, 10,000 unique events and raw batches per tenant, 256 MiB retained request bytes, 1–20 workflow steps and ten-minute plan expiry. These are evaluation safety limits, not measured throughput, production retention, pricing or performance guarantees. See the capabilities manifest for exact numeric bounds."
  },
  {
    "title": "API reference",
    "url": "/docs/console-v1/api.html",
    "text": "# Console v1 API reference\n\nSource snapshot: 23fdccfaa88f69e858769f1dad70f82739e2740f. Private evaluation.\n\nUse OpenAPI: /docs/console-v1/openapi.json. Never send requests to the static documentation server.\n\n## GET /health\n\nHealth. Public state-database reachability; not end-to-end pipeline qualification.\n\nAuthority: public. Response: Health.\n\n## POST /api/v1/session\n\nSign in. Create an eight-hour opaque cookie session. Origin, CSRF and JSON required even before login.\n\nAuthority: public. Response: Session.\nRequest schema: Login.\n\n## GET /api/v1/session\n\nCurrent session. Resolve the server-assigned workspace and role.\n\nAuthority: session. Response: CurrentSession.\n\n## DELETE /api/v1/session\n\nSign out. Revoke this individual session; Origin and CSRF required.\n\nAuthority: session. Response: Status.\n\n## GET /api/v1/session/options\n\nEvaluation registration options. Public configuration flag, not database health or production SaaS availability.\n\nAuthority: public. Response: SessionOptions.\n\n## POST /api/v1/session/signup\n\nCreate isolated evaluation workspace. Disabled by default; 32-workspace cap. No caller-selected tenant/role. Generic workspace_creation_unavailable on duplicate username or cap.\n\nAuthority: public. Response: Session.\nRequest schema: Signup.\n\n## GET /api/v1/overview\n\nWorkspace overview. Tenant-scoped counts and observed pipeline state. Inference is disabled.\n\nAuthority: session. Response: Overview.\n\n## GET /api/v1/costs\n\nRead cost snapshot. Operator only. Fixed configured snapshot, maximum 1 MiB. No provider/billing API calls; unavailable is not zero.\n\nAuthority: operator. Response: Costs.\n\n## GET /api/v1/sources\n\nList sources. Saved or receiving is not provider credential verification.\n\nAuthority: session. Response: SourceList.\n\n## POST /api/v1/sources\n\nCreate scoped source. Persist configuration, not a connected-provider claim.\n\nAuthority: session. Response: Source.\nRequest schema: CreateSource.\n\n## POST /api/v1/sources/{id}/preflight\n\nInspect source readiness. Schema and canary checks. Provider transports report external_worker_required and provider_verified:false.\n\nAuthority: session. Response: Preflight.\n\n## POST /api/v1/sources/{id}/token\n\nRotate source token. Operator only. Returned once; previous token revoked. This response is a secret and must not be logged.\n\nAuthority: operator. Response: SourceToken.\n\n## POST /api/v1/sources/{id}/ingest\n\nAccept native records. Maximum 1000 records and 8 MiB request. HTTP 202 is durable inbox acceptance, not external sink completion. Poll operation status before acknowledging the source. CloudTrail Records wrapper is also accepted.\n\nAuthority: source. Response: IngestReceipt.\nRequest schema: Ingest.\n\n## GET /api/v1/operations/{id}\n\nReconcile ingestion status. Source token is limited to operations belonging to its source and tenant. Acknowledge only committed, after inspecting lane receipts.\n\nAuthority: source. Response: Operation.\n\n## POST /api/v1/events/query\n\nQuery hot events. Typed parameterized tenant-filtered ClickHouse; 500 rows, 31 days, five-second engine limit; no raw SQL.\n\nAuthority: session. Response: HotQueryResult.\nRequest schema: HotQuery.\n\n## POST /api/v1/history/query\n\nQuery historical events. Authorized PyIceberg path. Only time/source/limit filters. Dependency failure is explicit, never silently served from hot data.\n\nAuthority: session. Response: HistoryQueryResult.\nRequest schema: HistoryQuery.\n\n## GET /api/v1/events/{id}\n\nRead retained evidence. Tenant-authorized OCSF and raw request bytes/provenance. Raw batch bytes can contain multiple records.\n\nAuthority: session. Response: Evidence.\n\n## GET /api/v1/rules\n\nList and reconcile rules. May reconcile observed Arroyo job state. Running is required for enabled; saved is not running.\n\nAuthority: session. Response: RuleList.\n\n## POST /api/v1/rules/validate\n\nValidate strict rule subset. Unsupported rule syntax returns valid:false; validation does not deploy.\n\nAuthority: session. Response: RuleValidation.\nRequest schema: RuleInput.\n\n## POST /api/v1/rules\n\nCreate versioned rule. Persist validated rule; enabled:true additionally requests actual deployment.\n\nAuthority: session. Response: Rule.\nRequest schema: RuleInput.\n\n## POST /api/v1/rules/{id}/enable\n\nEnable rule pipeline. Durable intent and ambiguous-create reconciliation. Inspect status; do not blindly repeat an unknown create.\n\nAuthority: session. Response: Rule.\n\n## POST /api/v1/rules/{id}/disable\n\nCheckpoint-stop rule. Pending/unknown until observed terminal job state.\n\nAuthority: session. Response: Rule.\n\n## GET /api/v1/alerts\n\nList alerts. Durable rule matches, not proof of malicious activity.\n\nAuthority: session. Response: AlertList.\n\n## GET /api/v1/alerts/{id}\n\nAlert narrative and evidence. Deterministic facts, citations, uncertainty and review guidance; inference disabled.\n\nAuthority: session. Response: Alert.\n\n## POST /api/v1/alerts/{id}/triage\n\nRecord human triage. Attribute disposition and note with audit.\n\nAuthority: session. Response: Alert.\nRequest schema: Triage.\n\n## GET /api/v1/cases\n\nList cases. Tenant-scoped local case state.\n\nAuthority: session. Response: CaseList.\n\n## GET /api/v1/cases/{id}\n\nRead case revision. Read current version before editing or approving a plan.\n\nAuthority: session. Response: Case.\n\n## PATCH /api/v1/cases/{id}\n\nUpdate case. Missing/stale expected_version returns 409. open↔investigating; open/investigating→closed; closed→open.\n\nAuthority: session. Response: Case.\nRequest schema: CasePatch.\n\n## GET /api/v1/attack\n\nDeclared ATT&CK metadata. Candidate rule/alert metadata, not confirmed technique detection or full coverage.\n\nAuthority: session. Response: Attack.\n\n## GET /api/v1/audit\n\nRead application audit. Append-only application behavior; production tamper resistance needs separate qualification.\n\nAuthority: session. Response: AuditList.\n\n## GET /api/v1/workflows\n\nList case workflows. Local case-management workflows only.\n\nAuthority: session. Response: WorkflowList.\n\n## POST /api/v1/workflows\n\nCreate typed workflow. One to twenty steps; only assignment, priority and note. No scripts, network URLs or cloud containment.\n\nAuthority: session. Response: Workflow.\nRequest schema: WorkflowInput.\n\n## POST /api/v1/workflows/{id}/preview\n\nPreview exact case plan. No case effects. Plan expires in ten minutes and binds case/workflow/policy versions and digest.\n\nAuthority: session. Response: Action.\nRequest schema: Preview.\n\n## GET /api/v1/actions\n\nReconcile action plans. Inspect persisted plan and receipt after ambiguity; there is no GET /actions/{id} endpoint.\n\nAuthority: session. Response: ActionList.\n\n## POST /api/v1/actions/{id}/approve\n\nApprove exact plan. Authenticated human operator. Exact digest and case version required. Repeated identical approval does not execute twice.\n\nAuthority: operator. Response: Action.\nRequest schema: Approve.\n\n## POST /api/v1/actions/{id}/reject\n\nReject exact plan. Operator role required; exact digest; opposite decisions conflict.\n\nAuthority: operator. Response: Action.\nRequest schema: Reject.\n"
  }
]
