Milestone 27a authority contract
Authority hardening is implemented and Milestone 27a is Complete under the 2026-09-14 owner decision. Evidence, Rust sign-off, DD30 accepted risk and the approved absence of the M26d status-baseline comparison are recorded in audit/M27A_COMPLETION_EVIDENCE.md.
Caller delegation
Every REST mutation, including /v1/fs/echo-batch, requires request authentication
(Authorization: Bearer or x-cohesix-auth) and exactly one x-cohesix-ticket.
The gateway verifies the ticket MAC with the explicitly selected
--delegation-key-ref env:NAME or file:/absolute/path. The delegated claims must
have a subject, finite unexpired TTL, and write scopes. Role, mount, scope, rate,
operation and bandwidth restrictions intersect the configured gateway ceiling.
Each batch line consumes one operation. Refusals use EPERM or ELIMIT.
When a REST ticket specifies a mount, every mutation must also fall beneath its
canonical mount point; a broader role or write scope cannot widen that bound.
Caller quota state is keyed by the SHA-256 of the canonical signed ticket. Live
entries are not evicted to admit other clients. All writes retain the existing
serialized authenticated console path. Audit records name gateway_enforced,
the ticket hash, configured upstream credential class, concrete path and action,
and confirmed ACK, ERR, or an unconfirmed transport outcome. The VM still
verifies the gateway session; this is not VM-verified caller identity. Read-only
REST compatibility remains scoped to that session. Delegated quotas are local to
the gateway process; retain one gateway owner per issuer/transport ceiling.
Rust REST clients accept COH_REST_TICKET or an explicit caller ticket.
cohsh REST attach replaces its caller binding. Python RestBackend accepts
delegated_ticket= and the same environment source. Client parsing is only a
convenience check; only the gateway verifies the MAC. A client must not retry an
ambiguous raw write automatically. Explicit strict-intent retries reuse all bytes
and identity fields.
Strict Queen commands
The legacy /queen/ctl JSON command is unchanged in compatibility profiles.
/queen/intents/ctl accepts queen-intent/v1 with schema, id,
idempotency_key, issued_unix_ms, and cmd. cmd is a JSON string containing
one existing Queen control object. Production disables the legacy path and its
console SPAWN/KILL shortcuts before acknowledgement or dispatch. Compatibility
profiles retain all three entry points.
{"schema":"queen-intent/v1","id":"spawn-one","idempotency_key":"retry-one","issued_unix_ms":1000,"writer_epoch":1,"cmd":"{\"spawn\":\"heartbeat\",\"ticks\":3}"}
This is a structural example, not a current timestamp or deployment epoch.
Identifiers are single ASCII components of at most 128 bytes; empty values,
option prefixes, .., separators and controls are rejected. The envelope is at
most 2048 bytes, further bounded by the manifest. Unknown and duplicate fields
are refused. The dedupe reservation precedes policy approval consumption and the
side effect. An exact duplicate returns the retained outcome without consuming
another approval or repeating the effect. Changed fields under the same identity
produce EPERM idempotency-conflict. Capacity exhaustion returns ELIMIT;
completed identities are not evicted. Compatibility policy defaults hold 64
entries; Release A selects 512 on both QEMU and Pi. Release A schema 1.28 and
current schema 1.29 both permit 1–512 entries and project the selected capacity
into the Python SDK. Pressure
qualification must budget every distinct intent, including refusals and fault
preflight, before the first mutation. Increasing capacity changes no identity,
approval, fencing or audit semantics.
Each strict terminal journal record includes dedupe: "fresh" or
dedupe: "duplicate" alongside the unchanged full envelope and outcome.
Legacy journal records retain their existing format.
When audit is enabled, the complete encoded successful terminal must fit the
selected journal before policy approval or a side effect is attempted. An
oversized record returns ELIMIT without reserving an identity or creating a
Worker. Journal wrap may discard older whole records; it does not make a
retained intent fresh.
The table belongs to one VM authority lifetime. VM restart persistence belongs
to Milestone 29; restarting the VM is not an approved retry mechanism.
/proc/queen/dedupe contains a bounded NDJSON summary and at most sixteen recent
outcomes. Each identity hash is SHA-256 of id, one zero byte, then
idempotency_key; outcomes are ACK, ERR, or in_flight.
/proc/authority exposes the selected writer epoch and authority class.
Host execution and writer ownership
writer_epoch is an optional extension of compatibility host-ticket schemas and
is required by production policy. When present, it must equal the selected
manifest epoch. Local execution and relay enforce it independently of decision
freshness. Durable execution and relay journals retain an owner floor and refuse
configuration rollback. Promotion is refused while the old epoch has pending
recovery. Preserve the journal directory across process restarts.
Version-1 provider work now retains prepared, executing, receipt and terminal
state. A persisted receipt is republished exactly after ambiguous delivery.
Executing work without a receipt is deadlettered as replay-ambiguous, never
executed again. The version-1 journal is bounded to 256 identities and 1 MiB;
full state refuses new work rather than dropping replay protection. The existing
version-2 admission-sequence compaction remains supported. Provider identifiers,
target components, action-specific argument names and types, and manifest
allowlists are checked before dispatch.
Strict intents, host tickets, WAL entries, results and audit bodies can retain
an optional admission object: admission_id, intent_hash, policy_hash,
state_epoch, resource_generation, decision_expiry. Hashes are lowercase
SHA-256 hex. This is correlation only. No missing admission is fabricated and no
27a component issues a 28c admission decision. writer_epoch is separate.
Production profile and secret sources
Manifest schema 1.21 introduces [authority] and ticket secret_ref. The
compiler materializes the selected single-writer Release A source as follows:
mkdir -p out/release-a/resources/keys
cp /absolute/deployment/cas-verification.hex \
out/release-a/resources/keys/cas_verification_key.hex
cargo run -p coh-rtc --bin coh-rtc-authority-profile -- \
--base configs/root_task.toml \
--verification-key out/release-a/resources/keys/cas_verification_key.hex \
--writer-epoch 1 --out out/release-a/root_task.toml
Select that generated TOML as the manifest for every subsequent target build,
compiler invocation, host tool build and evidence run. The deployment public key
must be below the new profile output directory and differ from the published
fixture key. Keep that public key beside the manifest when moving the profile
between build hosts; use a fresh output directory for a new candidate rather
than replacing evidence inputs. Materialization enables
audit/replay, strict intents and required writer epochs, disables arbitrary
memory diagnostics and federation, and replaces ticket literals with
env:COH_TICKET_QUEEN_KEY, env:COH_TICKET_WORKER_HEARTBEAT_KEY,
env:COH_TICKET_WORKER_GPU_KEY, env:COH_TICKET_WORKER_BUS_KEY, and
env:COH_TICKET_WORKER_LORA_KEY. Supply deployment secrets before compiling the
root image. Secret references, not key values, appear in resolved JSON.
The root binary nevertheless contains the resolved ticket credentials: references
protect generated configuration, not the confidentiality of a compiled image.
Keep privately provisioned target images within the deployment’s credential
boundary. Public evaluation images require a separate explicitly shared keyset;
never publish an image compiled with an active private hive’s keys. Credential
rotation requires rebuilding and qualifying the target image, together with its
matching host configuration.
For cohsh, the GPU bridge and Python, TCP credential resolution is explicit
input first, then COH_AUTH_TOKEN_REF, then COH_AUTH_TOKEN, then
COHSH_AUTH_TOKEN; Python can finally inspect the selected manifest. Other
clients accept references through their documented token option or environment
variable; see the tool-specific catalog in HOST_TOOLS.md.
A selected reference is exactly env:NAME or
file:/absolute/path. Failure does not fall back. Secret reads are bounded to
4096 bytes; empty, malformed and generated placeholder credentials are refused.
Live credential values must be ASCII and contain no whitespace or controls.
bootstrap, changeme and Worker fixture literals cannot authenticate live
SwarmUI, GPU bridge or console clients. Explicit mock/replay constructors are
separate. File sources are read again for rotation at each new authentication.
CAS public verification material may be packaged; private signing material may
not. The release inventory names exact files and forbids the fixture private key.
The compiler writes configs/generated/cas_verification_key.hex from the same
selected public key embedded in the root image. Artifact records bind those
bytes, and release assembly copies them into the public resource slot. Assembly
rejects mismatches and the published fixture public key. It never re-reads a
mutable deployment key file as a substitute for the retained compiler artifact.
The GPU console frame bound defaults to 8192 bytes including its four-byte header; an
invalid peer length is rejected before allocation. Arbitrary root-console
hexdump is disabled by the generated default and rejected in production policy.
An explicit non-release bring-up profile may enable reads of 1–256 bytes only
within the HAL-classified immutable root code span. Reads of rodata, mutable
state, device mappings, crossing ranges or overflowing addresses are refused
before dereference. Bounded serial audit lines record admission and refusal.
Production failover and federation remain disabled in the single-host Release A
profile. The existing optional-hook failover watchdog is development tooling;
the durable --production transaction is documented in FAILOVER.md.
Host tests are not accepted physical cutover evidence. A production cutover requires
old-writer fencing, durable epoch promotion, uniquely correlated terminal
receipts, and health checks before and after routing changes.
Evidence and compatibility
Evidence packs capture /proc/authority and /proc/queen/dedupe alongside
existing audit, replay and host-ticket records. Python target profiles use
cohesix-python-profile/v2 to carry selected authority limits; a target-neutral
wheel default cannot establish a live target’s identity or production readiness.
Generated flags reject premature VM-verified delegation, production Worker or driver ledger binding, structured quarantine, host AI and production failover. This preserves accepted 26e task/driver authority and any independently accepted Milestone 29 storage bundle. Milestone 28d owns production ledger and quarantine projection; Milestone 28c owns per-intent admission.
The gateway authority microbenchmark measures status reads, delegated writes, duplicate/conflicting identities and stale epochs without client retries. Its latency, refusal, queue, cache and audit counters are host measurements and do not establish Pi throughput or target acceptance.
Release migration and historical errata
Existing immutable release snapshots retain their historical examples. Any
example using bootstrap, changeme, Worker fixture secrets, or the public
fixture CAS trust chain is development-only and must not be used for deployment.
Do not edit those snapshots to relabel their qualification. Provision private
sources and a deployment public key, rebuild from the selected manifest, and
retain new exact-image evidence.
release_bundle.sh --release-manifest <provisioned-source.toml> binds assembly
to that selected input. The retained resolved artifact must have production
authority enabled, strict intents, writer fencing, execution WAL and bounded
audit/replay. Both tested and build-only assembly reject a development profile;
build-only assembly still makes no target acceptance claim. Exact inventory
validation and scripts/authority_release_gate.py content scanning reject
unexpected files, private fixture key bytes under renamed paths and release
secret canaries. --allow-development is used only by source due diligence and
cannot authorize release assembly.
cas-tool pack --signing-key env:NAME or file:/absolute/path selects a bounded
hex Ed25519 signing key. Explicit input precedes COH_CAS_SIGNING_KEY_REF;
a missing selected source never falls back. Compatibility file paths remain
supported. The 10 MiB REST response cap applies to success and error bodies;
peer Content-Length cannot authorize an allocation above that bound.