Files
alkblobs/tasks/s1-s3-ops-authority-model.md
T
glm-5.3-flash 4074499977 ops(security): ADR-017 lands — the CAS-global-pool model statement, renewal namespace parity, the remote-putter role requirement (review-001 S-1/S-3, wave 10)
- The module doc's ACL section opens with ADR-017's two-sentence model
  statement (CAS global pool; a namespace grant is capability-to-ask,
  not data partitioning; isolation-by-threat-model = separate store
  instances, ADR-003), placed ahead of the namespace-as-resource
  naming
- The four ACL/miss-boundary texts adopt pool framing ("absent from
  the pool"): stat's declared error + handler miss, fetch's declared
  BLOB_MISSING description, fetch_miss's message; the sweep found no
  other partitioning claim in src/ops
- OpsContext::renew gains the namespace parameter and validates it
  against the mint record (RenewalTarget carries it) — confirm's
  refusal discipline's parity (ADR-017 §3); a mismatch answers
  UnknownToken (the decided mapping) with the mapping intact by
  construction (peek, never remove); have_renewal passes the payload's
  namespace
- The remote-putter role requirement (read+write; renewal and
  confirmation ride read; write ⊄ read untouched) named on the pin
  hand-over section (ADR-017 §4)
- Regression tests both columns: the server-less custodial wire
  parity test and the live-harness fleet parity probe (mapping
  intact; the row's expiry moves only on the correct-namespace
  renewal); the existing tokens.rs renewal unit tests updated to the
  new signature and the ACL matrix e2e green unmodified

Verification: cargo test (204), cargo test --all-features server-less
(450, pg skips clean) and against the live pglo-poc harness (450
green), clippy --all-targets -- -D warnings (both feature variants),
cargo fmt --check, cargo doc --no-deps
2026-10-15 21:00:52 +00:00

11 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
s1-s3-ops-authority-model S-1/S-3 — the ops authority model lands per ADR-017: the CAS-global-pool model statement, pool-framing texts, renewal namespace parity, the remote-putter role requirement completed
moderate low component implementation
wave-10
review-001
security
ops
adr-017

Description

Review-001 S-1 + S-3, decided together as OQ-14 and resolved to ADR-017 (docs/architecture/decisions/017-ops-authority-model-cas-global-pool.md, accepted 2026-10-15). This task lands the ADR's Decision section on the ops surface. The four clauses:

  1. The model statement (ADR-017 §1 + §2, second sentence). The ops module doc (src/ops/mod.rs — the ACL mapping section, "namespace-as-resource mapping") carries the ADR's two-sentence model statement: the pool is a CAS global pool; a namespace grant is capability-to-ask, not data partitioning; a deployment whose threat model requires data isolation between namespaces runs separate store instances (the topology fact, ADR-003). Placed so the next reader meets the naming before the per-namespace framing could re-imply partitioning.
  2. The texts stop lying (ADR-017 §2, first sentence). The ACL/miss boundary texts adopt CAS-pool framing — "absent from the pool"; the namespace named only as the ACL resource whose grant the caller presented. The current texts (post-split locations): src/ops/specs.rs:47 and :83 ("the digest is absent from the namespace's pool" — stat and have), src/ops/fetch.rs:363 (the declared BLOB_MISSING error description) and :507 (fetch_miss's message, "absent from its namespace's pool"). Any other ACL/miss-boundary text implying partitioning gets the same framing (sweep the ops modules for the pattern).
  3. Renewal authority: namespace parity (ADR-017 §3). The renewal form validates the presented namespace against the token's mint record — the same discipline confirm already uses (src/ops/tokens.rs:460-471, the mint records the namespace). The mint record is registry-internal, so the check belongs in [OpsContext::renew] (src/ops/tokens.rs:382 — currently takes no namespace): the signature gains the namespace, the registry's renewal target carries the minted namespace (the ticket has it — RenewalTarget gains the field), and a mismatch answers the validity-domain refusal shape. The handler arm (have_renewal, src/ops/specs.rs:185-211) passes the payload's namespace. Design point — the mismatch's outcome mapping: the RenewalOutcome vocabulary is the wire contract (every non-renewed variant answers present: false, never an error); the natural mapping is UnknownToken (a namespace-mismatched renewal is the same "not this token's domain" answer confirm's refusal is) — decide and record in Notes. The mapping must leave the registry mapping intact (confirm's refusal discipline).
  4. The write-only renewal duty dissolves into a named role requirement (ADR-017 §4). Doc-only: the ops module doc states the remote-putter role requirement — a principal performing remote puts into a fleet must hold read+write on its namespace; renewal (the have-token form) and confirmation (the have probe) both ride read. No new op, no per-payload action mapping, no authorization re-implementation (ADR-001's alkcall-ridden ACL). The ACL matrix's write ⊄ read algebra is untouched.

Unchanged by design: the payload schemas, the ACL matrix, the op family, the closed-by-default enforcement (OQ-09) — ADR-017's Neutral clause. The existing ACL matrix e2e must stay green unmodified.

Live harness

The fleet renewal forms run against the local dockerized postgres container (pglo-poc, postgres:16-alpine on :15432):

export ALKBLOBS_PG_HOST=localhost
export ALKBLOBS_PG_PORT=15432
export ALKBLOBS_PG_USER=postgres
export ALKBLOBS_PG_PASSWORD=poc
export ALKBLOBS_PG_DB=blobs

Server-less, the pg tests skip cleanly; acceptance requires green against the live harness (the AGENTS verification matrix's shape).

Acceptance Criteria

  • The module doc carries the ADR-017 model statement (CAS global pool; grant = capability-to-ask; separation = separate stores) and the remote-putter read+write role requirement
  • The ACL/miss boundary texts use pool framing (stat, have, fetch's miss + declared BLOB_MISSING description); no remaining text claims namespace-partitioned data
  • OpsContext::renew validates the presented namespace against the mint record (parity with confirm); a mismatched renewal answers present: false with the mapping intact; the outcome mapping recorded in Notes
  • Regression tests: the parity check (wrong-namespace renewal answers present: false, a subsequent correct-namespace renewal succeeds — mapping intact) on the custodial form server-less, and the fleet form against the live harness
  • The existing ACL matrix e2e green unmodified (no schema or ACL behavior change)
  • Gates green: cargo test (default), cargo test --all-features server-less, cargo test --all-features + live harness, clippy --all-targets -- -D warnings across the feature variants, cargo fmt --check

References

  • docs/architecture/decisions/017-ops-authority-model-cas-global-pool.md (the Decision section, clauses 1-4 — read line by line)
  • docs/reviews/001-storage-surface-general-review.md (S-1, S-3 — pre-split coordinates)
  • docs/plans/implementation.md (§Wave 10; §Review gates — the security gate)
  • src/ops/mod.rs (the module doc's ACL section — the model statement's home; the pin hand-over sections — the role requirement's home)
  • src/ops/specs.rs (stat/have texts; have_renewal)
  • src/ops/fetch.rs (fetch_miss, the BLOB_MISSING description)
  • src/ops/tokens.rs (OpsContext::renew, RenewalTarget, confirm — the parity discipline's contrast)
  • src/ops/tests.rs (the ACL matrix e2e; the fleet renewal forms — the live-harness column)

Notes

  • The mismatch's outcome mapping (decided): UnknownToken. A namespace-mismatched renewal answers the validity-domain refusal — present: false, never an error, the same "not this token's domain" answer confirm's refusal is. Recorded on RenewalOutcome::UnknownToken (src/ops/tokens.rs:78-84), the renew doc (ADR-017 §3 named in the composition), and the have_pair doc ("invalid, foreign, or namespace-mismatched — the validity-domain refusals").
  • Check ordering: the namespace parity check sits between the token lookup and the digest check — the mint record is part of the token's domain, so the parity refusal precedes the one-token-one-row digest question.
  • Mapping intact by construction: the renewal peeks the ticket (renewal_target clones it out under the lock); it never removes — unlike confirm, which removes-then-restores on a refused match. No restore code needed; the parity check retires nothing, and the subsequent correct-namespace renewal succeeds (asserted in all three regression shapes: the tokens.rs unit test, the server-less wire test, the live fleet form).
  • Text sweep result: exactly four ACL/miss-boundary sites carried the partitioning framing — specs.rs stat's declared error and handler miss (both "absent from the namespace's pool"), fetch.rs's declared BLOB_MISSING description, and fetch_miss's message (both "absent from its namespace's pool"). All now read "the digest is absent from the pool (…)" / "absent from the pool"; no other ops text claimed namespace-partitioned data (delete's "the digest is absent: nothing deleted" never did).
  • Signature change: OpsContext::renew(namespace, token, digest) — the have handler arm (have_renewal) passes the payload's namespace (extracted beside digests at the handler ingress); RenewalTarget carries the mint record's namespace. No wire change: the payload schemas are untouched; the namespace is already the ACL resource path.
  • Role requirement placement: the remote-putter read+write duty sits in the ops module doc's blobs/put pin hand-over section as a named design point (ADR-017 §4) — the contract's have-probe duty cited, the role-level-duty-not-grant-implication boundary stated, the put-without-read consequence recorded.
  • One transient flake in verification: the first live-harness full run tripped store::sweep::postgres_fleet_sweep_tests::sql_arbitration_refuses_a_foreign_pin_row_on_the_direct_path (a 300ms wall-clock expiry window sampled once, sweep.rs:1966 — the documented cadence-flake class riding the default-parallelism load, unrelated to this task's changes). It passes in isolation; the default-parallelism full-suite re-run was green end to end. No --test-threads reduction used.

Summary

ADR-017's four clauses landed on the ops surface. (1) + (4): the ops module doc's ACL section now opens with the two-sentence model statement — CAS global pool; a namespace grant is capability-to-ask, not data partitioning; isolation-by-threat-model runs separate store instances (ADR-003's topology fact) — placed ahead of the namespace-as-resource naming so the next reader meets the model before the per-namespace framing; the pin hand-over section carries the remote-putter role requirement (read+write; renewal and confirmation ride read; write ⊄ read untouched). (2): the four ACL/miss-boundary texts adopted pool framing ("absent from the pool"); a grep sweep of src/ops found no other partitioning claim. (3): OpsContext::renew gained the namespace parameter and validates it against the mint record (RenewalTarget carries it) — the same discipline confirm uses, answering UnknownToken on mismatch with the mapping intact by construction (peek, never remove); the blobs/have renewal arm passes the payload's namespace. Regression tests added in both columns: the server-less custodial wire test (wrong-namespace probe → present: false, correct-namespace renewal → present: true, mapping intact through both, confirm's discipline reachable) and the live-harness fleet form (the parity probe before the live renewal; the row's expiry moves only on the correct- namespace renewal). The ACL matrix e2e stayed green unmodified.

Gates: cargo test (204), cargo test --all-features server-less (450, pg skips clean) and against the live pglo-poc harness (450, green), clippy --all-targets -- -D warnings across both feature variants, cargo fmt --check, cargo doc --no-deps — all pass.