Chio/Docs
LOGIN · JOIN

EconomyFindings

The Hosted Profile

The multi-tenant cognition market deployment: a PostgreSQL store, an authenticated edge, isolated workers, and the ceilings each one enforces.

The cognition market ships in two deployments. The single-operator profile runs one venue on SQLite inside the trust-control plane, in one process. The hosted profile runs several tenants against one PostgreSQL database under forced row-level security, behind an authenticated HTTP edge, with job execution on separate Linux KVM hosts. Those tenants share the database, the edge replicas, and the worker hosts; row-level security and per-tenant ceilings are what hold them apart.

The two deployments answer a liveness question differently, and that difference decides where a status-gated purchase can happen. The single-operator venue holds the status feed's sparse map, so it can produce the portable non-inclusion proof such a purchase presents. The hosted journal retains a status epoch only as a signed sparse-map root and keeps no per-finding sparse proof, so once a tenant has any status epoch, catalog_non_live_finding_ids answers with every finding id it was asked about: a single read returns not_found and a catalog page comes back with those rows removed. The hosted edge carries no bid, ask, or reveal route either: purchase records, purchase results, and purchase terminals are coordinator-produced and have no public ingress here.


Supported topology

Four crates carry the hosted profile, and four binaries run it. The edge and the store link into one server process; the worker library links into a daemon that runs on hosts of its own.

PartCrateWhere it runs
PostgreSQL journal, tenancy, storage authority, retentioncrates/platform/chio-finding-market-store-postgresLinked into every process that opens the database, each under its own least-privilege role
HTTP routing, credential authentication, request admission, load sheddingcrates/platform/chio-finding-hosted-edgeLinked into the market server, listening on loopback behind a TLS proxy sidecar in the same pod
Firecracker-isolated execution and the guest frame protocolcrates/platform/chio-finding-workerLinked into the worker daemon on a dedicated Linux KVM host
Worker daemon: preflight, tenant rotation, tick reportingcrates/products/chio-finding-workerUnder systemd on the KVM host. SQLite is neither mounted nor admitted in either production role

Two crates, one name

The platform crate's package is named chio-finding-worker and lives at crates/platform/chio-finding-worker. The products crate is packaged as chio-finding-worker-daemon, sits at crates/products/chio-finding-worker, and ships a binary also named chio-finding-worker. The library is the one a profile validates against; the binary is the one systemd starts.

The binaries divide by credential. chio-finding-market-migrate, from crates/products/chio-finding-market-migrator, owns schema changes under a migration-only role and runs as its own Job; runtime pods never receive that credential. chio-finding-market-server serves the authenticated loopback API from stateless replicas. chio-finding-worker executes jobs under fenced leases in Firecracker isolation. chio-finding-market-canary qualifies a deployment against an exact release candidate from an attested ephemeral runner. The container, systemd, and Kubernetes contracts live under deploy/cognition-market/.


What the edge serves

The router carries three health routes outside the concurrency limiter and five guarded routes inside it. Liveness and readiness stay outside because the proxy probes them on this same pod, and shedding a probe would restart a live sidecar exactly while the edge is saturated.

RouteWhat it answers
GET /health/live, GET /health/readyLiveness, and a readiness answer that reaches the backend at most once per READINESS_ANSWER_LIFETIME
GET /health/metricschio_finding_market_edge_requests_total in Prometheus exposition format, labelled accepted, denied, and shed
GET /v1/releaseThe deployment id, candidate commit, artifact digest, and configuration revision the process is bound to
GET /v1/findings, GET /v1/findings/{finding_id}One bounded page, or one finding, for the buyer role. Each row is re-verified against its own signature and digest, and expired, voluntarily retracted, and enforcement-retracted findings drop out
POST /v1/findings/publishOne signed chio.finding.v1 artifact from the seller role
POST /v1/findings/events/{operation}Exactly six operations: listing, delivery, challenge, verified-fix, retraction, and penalty

Each operation fixes its own domain event kind, artifact schema, governed action name, and writing role, and anything outside that list resolves to no operation at all. Coordinator-produced records, which include admission, purchase, purchase terminals, adjudication, enforcement, settlement, status, and audit, have no public route. The challenge route accepts only the buyer_submission authorization branch, so a venue audit cannot enter through it, and a penalty write must be signed by the profile's pinned penalty authority and name itself in both issuedBy and governingOperatorId.

A tenant is chosen by the Chio-Tenant-ID header, and a caller authenticates with either a capability token plus a Chio-DPoP proof or an API key pair, whichever the tenant's policy admits. Every failure returns the same body: chio.finding.hosted-error.v1 with a stable code, a fixed message, the caller's request id, and a retryable flag that is true only for rate_limited, authentication_capacity_unavailable, request_capacity_unavailable, and authentication_dependency_unavailable. A request id that is empty, over its byte bound, padded, or carrying a control character is replaced by invalid-request-id rather than echoed.


Tenancy and isolation

Every tenant-scoped operation opens a transaction and runs SELECT set_config('chio.tenant_id', $1, TRUE) before it touches a row, so the binding is transaction-local and cannot leak into a pooled connection's next user. Catalog reads take the same setting under SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY, so a page is answered from one snapshot. Either way an unknown tenant returns TenantNotFound and a tenant the operator disabled returns TenantDisabled, which keeps durable state intact while every subsequent scoped operation fails closed.

Row-level security is what enforces the binding. Every table in TENANT_SCOPED_TABLES carries ENABLE ROW LEVEL SECURITY and FORCE ROW LEVEL SECURITY, so the policy binds the table owner as well, plus one permissive policy for all commands, applying to PUBLIC, whose USING and WITH CHECK expressions are both exactly (tenant_id = NULLIF(current_setting('chio.tenant_id'::text, true), ''::text)). The startup audit rereads all of that from the catalog and adds one condition the schema alone cannot state: the runtime role must not own any of those tables.

A statement that runs without the setting finds that predicate evaluating to NULL for every row, so it reads nothing and writes nothing rather than erroring. The security-definer functions refuse louder: each compares its requested tenant against the session setting before anything else and raises 42501 with a message naming the mismatch, such as tenant context does not match authority transition.

The store audits its own credential before it serves anything. verify_runtime_role refuses a role that is a superuser or carries BYPASSRLS, CREATEROLE, CREATEDB, REPLICATION, INHERIT, or any role membership, then checks its database privileges, its per-table privileges, its function grants, and the RLS surface table by table. Any drift returns HostedMarketStoreError::Configuration and the process does not start. The migrator, worker, retention, and replicator credentials each get their own audit, and the migrator is the only one permitted to bypass row-level security or create schema objects. Every pool connects with PgSslMode::VerifyFull, applied over whatever the DSN asked for, against the certificate authority the profile names.

Privilege separation extends inside the schema. The monthly spend accumulator is maintained only by a security-definer trigger on the reservation table, and the runtime role holds SELECT on it and no write privilege at all, so a compromised runtime cannot forge a low total for its own tenant and pass the ceiling that trigger enforces.


Storage authority

Each tenant carries one row of authority state: which store is authoritative, an epoch, a mode, a mutations flag, the last replication and outbox sequences, and the digest of the transition that produced the row. A new tenant is initialized by trigger at authority sqlite, epoch 1, mode shadow, with mutations enabled. The constraint chio_finding_market_authority_state_consistency_v1 keeps the authority and the mode consistent: sqlite pairs only with shadow or frozen, and postgres only with rollback_window, authoritative, retired, or frozen.

ModeWhat it permits
shadowSQLite holds authority. PostgreSQL accepts signed replication events from it and appends signed replication checks; it admits no domain write of its own
frozenThe barrier state, reachable under either authority. mutations_enabled is false, replication events still land while SQLite holds authority, and it is the only mode cutover and rollback accept
rollback_windowPostgreSQL holds authority and admits domain writes, while a stored deadline still allows a return to SQLite
authoritativeAdmitted by the domain-write guard alongside rollback_window and retired, and accepted by freeze as a source mode. No transition sets it
retiredPostgreSQL holds authority, admits domain writes, and the rollback deadline has passed

A domain write reaches durable state only when the tenant's authority is postgres, mutations_enabled is true, and the mode is one of rollback_window, authoritative, or retired. The guard runs inside the append function under a row lock, so a freeze that lands mid-flight refuses the write rather than racing it.

OperationFromToAlso required
freezeEither authority, unchanged; mode shadow, rollback_window, or authoritativeSame authority; mode frozen; mutations_enabled falseThe request carries no rollback window
cutoversqlite, mode frozenpostgres, mode rollback_window, mutations enabledThe requested rollback window ends exactly 604800 seconds after the transition's creation time
rollbackpostgres, mode frozensqlite, mode shadow, mutations enabled, stored window clearedA stored rollback window exists and the transition is created no later than its deadline
retire_sqlitepostgres, mode rollback_windowpostgres, mode retired, mutations enabledThe stored rollback deadline has passed, and the request carries no new window
The four operations chio_finding_market_apply_authority_transition applies, with the authority and mode each one moves between. Every row additionally requires a matching epoch, sequence, and configuration revision, and a signed replication check reporting zero lag and equal projection digests.
sourcecrates/platform/chio-finding-market-store-postgres/migrations/0012_authority_replication.sql:1035-1088at fe56570

A transition is one signed chio.finding.hosted-authority-transition.v1 envelope applied under a tenant advisory lock, and each one raises the authority epoch by exactly one, which both a table constraint and the function require. Presenting the identical envelope twice returns the replay outcome instead of moving the epoch again; anything that fails a precondition returns a rejection and leaves the row untouched. Each applied transition is inserted into chio_finding_market_authority_transitions, where a trigger rejects any later UPDATE or DELETE, so the authority history is append-only. The replication credential that applies these barriers is separate from the runtime credential and cannot invoke public market commands.


Capacity ceilings

Every ceiling below is an enforced constant or a setting the profile validates before the process starts. The ones that refuse work fail closed, and none of them degrades a guarantee to keep going. The admission, spend, and job ceilings are per tenant; the request ceilings bound one edge replica.

What it boundsValueConstant or settingWhen it binds
Unexpired proof nonces one tenant may hold at once1_000..=10_000_000identity.nonceCapacityA sweep runs first; if the count still stands, the admission returns Capacity and the caller reads authentication_capacity_unavailable, HTTP 503, retryable
Retained request admissions per live-proof slot64RETAINED_BINDINGS_PER_NONCE_SLOTThe same capacity refusal. A recorded admission is never evicted to make room, because evicting one would break the retry it exists to serve
Interval after which an admission sweeps expired proof state3_600 secondsDPOP_SWEEP_INTERVAL_SECSNo refusal. The sweep runs inside the admitting transaction, and capacity pressure triggers it early
Monthly spend units per tenant1..=MAX_I_JSON_INTEGERHostedTenantLimitsThe accumulator trigger raises chio_finding_market_spend_period_ceiling_v1 inside the inserting statement, which the store maps to Capacity
Concurrent jobs per tenant1..=1_024HostedTenantLimitsNo refusal. It caps the batch one worker tick claims for that tenant, together with the tick's job budget and the host-wide instance count
Queued jobs per tenant, counting pending, leased, and failed1..=database.maxJobsPerTenantHostedTenantLimitsJob creation returns Capacity. A profile whose tenant value exceeds the global one refuses to start rather than being clamped
Retained jobs per tenant, counting every state1..=10_000_000database.maxJobsPerTenant, bounded by MAX_TENANT_JOBSJob creation returns Capacity, checked under a tenant advisory lock so the count and the insert cannot interleave
Rows in one catalog page, and finding ids in one liveness query100, defaulting to 50MAX_CATALOG_PAGEA larger limit returns Invalid("catalog limit"), which the caller reads as invalid_request, HTTP 400
In-flight requests per edge replica1_024MAX_CONCURRENT_REQUESTSThe request sheds before a handler runs, carrying request_capacity_unavailable, HTTP 503, retryable, and its own request id
Request body4 MiBMAX_HTTP_BODY_BYTESThe router's body-limit layer stops the request before a handler sees it, and the handler's canonical-body check refuses the same bound again
How long one readiness answer is reused1 secondREADINESS_ANSWER_LIFETIMENo refusal. One backend check runs at a time, and a probe arriving while the answer has aged out and a check is already in flight reports not ready

Live-proof capacity is one operator sizing decision applied to every tenant's admissions, with no per-tenant override, and both the profile and the authenticator refuse a value below 1_000, so the store's wider acceptance is unreachable through configuration. The shed count sits beside the accepted and denied counts on /health/metrics, which is absent from the Service and whose network policy admits only namespaces labelled chio.world/market-metrics-scraper, so traffic volume reaches a scraper without becoming publicly routable.

The other profile's ceilings explain when an operator reaches for this one. A single-operator venue serves discovery from a companion pool bounded by MAX_READ_COMPANIONS, and its serving-owner lease makes exactly one process the writer. A deployment that needs more concurrent writers wants the PostgreSQL profile, not a larger bound there.


The worker

A job is a row in chio_finding_market_jobs holding a canonical JSON payload, its digest, and a job_kind. That kind is an operator-chosen identifier bounded by MAX_JOB_KIND_BYTES, not a closed vocabulary: what constrains it is the signed worker capability, which must name the same job_kind as the job it authorizes. The state column is closed, at pending, leased, completed, failed, and exhausted, with table constraints tying the lease columns, the result columns, and the error code to it.

One tick claims a bounded batch for one tenant under a fenced lease, renews that lease on a heartbeat while the guest runs, and sorts each job into one of five outcomes: Completed, GuestRejected, Retried, Exhausted, or Cancelled. A guest that returns a result whose exit classification is not Succeeded still completes the job durably; the attested result records the refusal.

A failed execution takes one of two paths. If the job has already used its attempt budget, the worker calls exhaust_job with the error code and the job stops there. Otherwise it calls fail_job with the same code and a delay of retry_base_secs * 2^(attempt_count - 1), with the exponent capped at 10 and the delay capped at 3,600 seconds, and the row returns to failed to be claimed again when it comes due.

The budget itself is the smaller of the worker profile's maxAttempts and the attempt limit inside the signed job capability, so a profile cannot grant more attempts than the capability authorized, and a capability whose attempt limit fails to verify exhausts the job at once rather than retrying it. Shutdown is the third path: a canceled execution relinquishes its lease so another worker can claim the job immediately, and a lease already lost to expiry leaves the row where the next claim finds it.

Isolation is part of the contract rather than the deployment's discretion. The worker stages digest-pinned guest assets into a unique jail, starts Firecracker only through its jailer, and exchanges bounded canonical JSON frames over virtio-vsock; the guest supervisor owns the vsock endpoint and runs the untrusted workload in a cgroup with a hard file-descriptor limit. Profile validation refuses unless requireDefaultSeccomp is true and networkEnabled is false, and it refuses a lease duration that does not outlive the execution timeout, so a lease cannot expire under a running guest.


Operator commands

Two subcommands of chio finding operator act on a hosted deployment. Both read a strict canonical private JSON profile and both refuse before touching a listener, a pool, a rail, or a remote signer.

bash
chio finding operator validate-hosted --profile /etc/chio/hosted.json

chio finding operator evaluate-canary \
    --profile /etc/chio/hosted.json \
    --observation /run/chio/canary-observation.json

validate-hosted closes the deployment boundary offline. It requires the file to be a private regular file inside its byte bound and byte-identical to its own canonical form, validates the profile, then opens every referenced path, resolves every named secret environment variable, builds the authenticator, loads the API-key pepper, loads TLS, loads the trusted proxy, loads a signer for every role in FindingHostedSigningRole::ALL, loads the bond observer and the impairment publisher, and on Linux builds the worker executor. A run that survives all of that prints hosted_profile: valid with the deployment id, endpoint, tenant count, and signer count, or the same facts as a chio.finding.hosted-profile-validation.v1 report under --json.

evaluate-canary judges one audit-authority-signed observation against the same profile and prints canary_decision: promote or canary_decision: rollback with one reason: binding, observation_window, freshness, availability, error_rate, latency, queue_age, or security_invariant. A rollback decision exits non-zero, so a promotion script can branch on the exit code alone.

Where the runtime refuses instead

Startup carries the checks a command cannot. The market server compares the deployed candidate commit and artifact digest in its environment against the profile's release block and fails closed unless both match, and every store connection verifies the embedded migration ledger and refuses to serve schema drift.

See also

  • The Cognition Market for the finding record, the six market flows, and the crates behind them. That page describes each flow as the single-operator deployment runs it.
  • Finding Status for the signed status epochs and the portable non-inclusion proof a status-gated purchase presents, which the single-operator store retains and this one does not.
  • Paid Reveal for the reversible hold, the digest gate, and the terminal states of the purchase chain that runs outside this deployment.
The Hosted Profile · Chio Docs