- stat_pair/have_pair/delete_pair exported as spec/handler pairs the
embedder assembles (OpsContext-bound); input/output + typed error
schemas per alkcall ADR-016 with namespace-as-resource ACL, the read
action on stat/have, closed-by-default (OQ-09) verified by test
- stat rides Store::stat (the miss answering the typed BLOB_MISSING,
never {len: null}); the non-token have is the pure has probe with
index-corresponded present[]; delete is Visibility::Internal —
external discovery NOT_FOUND, the operator authority context carried
as the registration-time composition authority (not namespace-gated),
GC_REFUSED/BLOB_MISSING typed, fail-fast
- the have renewal form rides the foundation's OpsContext::renew: the
one-digest arity enforced at the schema (if/then) and as the typed
INVALID_RENEWAL_FORM; digests wire-form hex via the key layer's
ingress (INVALID_DIGEST); the fleet arms tested against the harness
server (env-driven, skipping cleanly server-less): the live row
renews with the expiry observed moving, the expired row answers
present: false with the expiry frozen (no renewal), the foreign
token is the validity-domain refusal, and mint_custodial refuses
under fleet
Gates: cargo test (default 73/19/3), cargo test --features ops
(92/19/3), cargo test --all-features against the harness server
(246/125/4), clippy -D warnings across default/ops/all-features plus
the pg-pure checks, cargo fmt --check, cargo doc --no-deps clean.
209 lines
11 KiB
Markdown
209 lines
11 KiB
Markdown
---
|
|
id: ops-json-ops
|
|
name: the JSON control plane — blobs/stat, blobs/have (+ the token-renewal form), blobs/delete
|
|
status: completed
|
|
depends_on: [ops-foundation, ops-call-harness]
|
|
scope: moderate
|
|
risk: medium
|
|
impact: component
|
|
level: implementation
|
|
tags: [wave-7, ops, json, acl, tokens]
|
|
---
|
|
|
|
## Description
|
|
|
|
The three JSON control ops (ops-surface.md §Op family), each exported
|
|
as a spec/handler pair the embedder assembles — riding alkcall's
|
|
`OperationSpec` + JSON Schema validation (alkcall ADR-016) and its ACL
|
|
machinery at op entry (convention 6: this module never re-implements
|
|
an authorization check):
|
|
|
|
- **`blobs/stat`** `{namespace, digest}` → `{len}` — Query; the
|
|
**read** action; the handler calls `Store::stat` (the fall-through
|
|
general rule, ADR-012 §6.1); a miss is the typed missing-error
|
|
schema (not a `{len: null}`).
|
|
- **`blobs/have`** `{namespace, digests[], token?}` → `{present[]}` —
|
|
Query; **read-gated** (an existence probe over arbitrary digests is
|
|
a discovery surface — gated exactly like fetch, not public);
|
|
`present[]` corresponds to `digests[]` by index; content never
|
|
traverses this op (hashes only). **The renewal form** (ADR-012 §2):
|
|
when `token` is present, exactly one digest accompanies it — the
|
|
handler verifies the token maps to that digest's pin row (the
|
|
foundation's token layer), calls the crate-internal `pin_renew(key,
|
|
owner)` via the foundation's store-core access, and answers
|
|
`present[]` as usual; an expired or foreign row answers
|
|
`present: false` and no renewal occurs — the putter's backstop is
|
|
re-put. Without `token`, the pure existence probe (ADR-008's `has`
|
|
discipline) over the facade's `has`. **The non-fleet renewal form**:
|
|
the token is the held guard's handle — the probe answers present
|
|
from the custody (nothing expires; ADR-012 §2's generalization);
|
|
the custody/conversion lifecycle is the foundation's.
|
|
- **`blobs/delete`** `{namespace, digests[]}` — Mutation;
|
|
**`Visibility::Internal`**, evaluated under the internal authority
|
|
context per alkcall ADR-017 (internal calls switch authority
|
|
context, never skip ACL): requires the embedder's operator/admin
|
|
authority context, **not a namespace grant**; the `namespace` field
|
|
exists for audit/triage scoping, not gating. The handler calls
|
|
`Store::delete` (the arbitration-then-delete path; a `GcRefuse`
|
|
refusal surfaces as the typed error schema). External discovery of
|
|
an Internal op returns NOT_FOUND (alkcall ADR-017's visibility
|
|
discipline).
|
|
- **The ACL mapping** (ops-surface.md §ACL mapping; OQ-09's
|
|
resolution): **namespace = resource** — `resource_type:
|
|
"blob-namespace"`, `resource_id_path` selecting the payload's
|
|
`namespace` field; stat/have = the **read** action; **unlisted
|
|
namespaces deny by default** (closed-by-default: no ACL entry ⇒ no
|
|
read, no write — a grant per namespace is the deferred cost,
|
|
deliberately paid over accidental exposure).
|
|
- **Schemas** (alkcall ADR-016): input/output JSON Schema per op +
|
|
typed error schemas; the namespace field's syntax (non-empty UTF-8
|
|
string, embedder-validated — the minting of namespaces is the
|
|
embedder's act); the digest wire form is **hex** (the canonical
|
|
digest hex — the same form `blobs/put`'s response returns; parsed
|
|
via the key layer's hex ingress, malformed → the typed invalid
|
|
error, rejects-never-guesses).
|
|
- **Tests through the harness** (`ops-call-harness`): stat round-trip
|
|
+ the miss shape; have's index correspondence (present/absent
|
|
mixed); the renewal form's three answers (live row renews →
|
|
present: true; expired row → present: false, no renewal; foreign
|
|
token → present: false); delete under the internal authority
|
|
context (an external caller gets NOT_FOUND; an internal
|
|
operator-context call deletes); the closed-by-default ACL matrix
|
|
(an unlisted namespace denies read; a granted identity reads).
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [x] Three spec/handler pairs exported (stat, have, delete); input/
|
|
output schemas + typed error schemas per alkcall ADR-016
|
|
- [x] The ACL mapping: namespace-as-resource with the
|
|
resource_id_path; the read action on stat/have;
|
|
closed-by-default verified by test (unlisted namespace denies)
|
|
- [x] delete: `Visibility::Internal`, the internal-authority-context
|
|
requirement (not namespace-gated), external discovery NOT_FOUND
|
|
- [x] have's renewal form: one digest + token; verify-mapping →
|
|
`pin_renew`; expired/foreign → `present: false` with no
|
|
renewal; the non-fleet form answers from the held custody
|
|
- [x] The handlers touch only the store facade + the foundation's
|
|
crate-internal renewal access (no backend side-door — the
|
|
ADR-001 §4 rule)
|
|
- [x] Harness tests green; `cargo test` (default) green;
|
|
`cargo test --features ops` green; clippy/fmt green on both
|
|
shapes; `cargo doc --no-deps` clean
|
|
|
|
## References
|
|
|
|
- docs/architecture/ops-surface.md (§Op family — the three JSON ops;
|
|
§ACL mapping)
|
|
- docs/architecture/decisions/001-substrate-posture-and-ops-placement.md
|
|
§2/§4
|
|
- docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md
|
|
§2 (the have payload shape + the renewal form's three-step handler
|
|
duty)
|
|
- docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md
|
|
(the `has` discipline the non-token form preserves)
|
|
- docs/architecture/open-questions.md OQ-09 (closed-by-default, the
|
|
risk-asymmetry rationale)
|
|
- alkcall (upstream checkout): ADR-016 (operation error schemas),
|
|
ADR-017 (the privilege model — internal switches context, never
|
|
skips ACL), `src/registry/spec.rs` (`AccessControl`,
|
|
`resource_id_path`)
|
|
- tasks/ops-foundation.md (the token layer + the renewal access the
|
|
have handler rides), tasks/ops-call-harness.md (the harness)
|
|
|
|
## Notes
|
|
|
|
> Landed in `src/ops.rs` (the ops module's "JSON control plane"
|
|
> section, appended to the foundation's substrate) + `src/lib.rs`
|
|
> re-exports (`stat_pair`/`have_pair`/`delete_pair` and the four
|
|
> domain codes `BLOB_MISSING`/`INVALID_DIGEST`/`INVALID_RENEWAL_FORM`/
|
|
> `GC_REFUSED`). Each export is `pub fn X_pair(ctx: Arc<OpsContext>) ->
|
|
> (OperationSpec, Handler)` — the embedder assembles; the harness's
|
|
> assembly (extended: `assemble_registrations` now carries the
|
|
> registration-side composition authority and scoped composition env,
|
|
> ADR-017/019 — the pair-level `assemble` shape is unchanged).
|
|
>
|
|
> **Schemas (alkcall ADR-016):** input/output JSON Schema per op — the
|
|
> namespace field's syntax enforced at the schema (`minLength: 1`, the
|
|
> non-empty-UTF-8 rule); the digest wire form hex with the canonical
|
|
> pattern (`^[0-9a-f]{40}$|^[0-9a-f]{64}$`, the key layer's
|
|
> lowercase-only ingress also enforced at the handlers —
|
|
> rejects-never-guesses). The have schema carries the renewal form's
|
|
> arity as `if`/`then` (token ⇒ digests minItems/maxItems 1) — verified
|
|
> live at the wire (`INVALID_INPUT` on the two-digest+token shape) —
|
|
> and re-enforced at the handler (`INVALID_RENEWAL_FORM`, the
|
|
> typed error for non-registry dispatch paths, exercised by direct
|
|
> handler invocation). Typed error schemas: `BLOB_MISSING`
|
|
> (stat's miss — details `{digest}`; a `{len: null}` was never an
|
|
> option), `INVALID_DIGEST` (the ingress), `INVALID_RENEWAL_FORM`
|
|
> (have's arity), `GC_REFUSED` (delete's `Error::GcRefuse`).
|
|
>
|
|
> **The ACL mapping (OQ-09's resolution, verified by test):**
|
|
> namespace-as-resource — `resource_type: "blob-namespace"`,
|
|
> `resource_id_path: "$.namespace"`, the read action on stat/have;
|
|
> closed-by-default proven on the wire (an unlisted namespace denies
|
|
> the granted identity's probe; a granted namespace reads; the
|
|
> anonymous call answers the authentication required gate). delete:
|
|
> `Visibility::Internal`, `AccessControl` left un-gated (not
|
|
> namespace-gated — the field is audit/triage scoping), the
|
|
> operator-admin authority context realized as the **composition
|
|
> authority the embedder declares at registration** (the pair exports
|
|
> it authority-agnostic); external discovery is the registry's
|
|
> NOT_FOUND (tested); the internal path proven through a composant op
|
|
> (`blobs/compose-delete` test stub, scoped env → delete) whose
|
|
> grantless caller composes — the check ran against the declared
|
|
> operator authority, the namespace grant not the gate. GcRefuse and
|
|
> Missing surface as the typed errors (fail-fast; no atomic multi-
|
|
> delete was specced — the preceding digests' deletions stand, and the
|
|
> doc says so).
|
|
>
|
|
> **The renewal form** (ADR-012 §2's three-step duty, riding the
|
|
> foundation's `OpsContext::renew` — no new store access, no backend
|
|
> side-door): the non-fleet arms answer from custody (renew →
|
|
> present: true; unknown/foreign/mismatched → present: false, never an
|
|
> error; the malformed-token ingress maps to the unknown-token answer);
|
|
> the fleet arms ran against the harness server (env-driven
|
|
> `ALKBLOBS_PG_HOST/...`, skipping cleanly server-less — the fleet
|
|
> column's SKIP posture adapted in-crate): the live row renews with
|
|
> the row's expiry observed moving (the independent `gc_pins`
|
|
> instrument), the expired row answers `present: false` with the
|
|
> expiry frozen at the last renewal (no renewal occurred — the
|
|
> never-resurrect discipline), and the peer mint's foreign token
|
|
> answers `present: false` the same way (the validity domain = the
|
|
> minting node). The foundation's noted `mint_custodial`-refused-under-
|
|
> fleet arm is asserted in the same test. The put-side arms (mint the
|
|
> token from a wire-carried put) ride the put's handler (ops-put).
|
|
|
|
## Summary
|
|
|
|
> Completed 2026-10-13 (wave 7). The JSON control plane's three
|
|
> spec/handler pairs landed in `src/ops.rs` under feature `ops`:
|
|
> `blobs/stat` (Query/read — `Store::stat`, the miss as the typed
|
|
> `BLOB_MISSING`), `blobs/have` (Query/read — the pure existence probe
|
|
> over `Store::has` with index-corresponded `present[]`, engine
|
|
> failures folding to present: false, and the token-renewal form
|
|
> riding `OpsContext::renew` with the one-digest arity enforced at the
|
|
> schema (`if`/`then`) and the handler), and `blobs/delete`
|
|
> (Mutation/`Visibility::Internal` — external discovery NOT_FOUND; the
|
|
> operator authority context via the registration-time composition
|
|
> authority; not namespace-gated; `Store::delete` with `GC_REFUSED`/
|
|
> `BLOB_MISSING` as the typed errors, fail-fast). ACL: namespace-as-
|
|
> resource, the read action, closed-by-default (verified by test);
|
|
> digests wire-form hex parsed via the key layer's ingress
|
|
> (rejects-never-guesses); domain error codes `BLOB_MISSING`/
|
|
> `INVALID_DIGEST`/`INVALID_RENEWAL_FORM`/`GC_REFUSED` declared per op
|
|
> with their details schemas. Five harness tests added (stat
|
|
> round-trip/miss/ingress, have's index correspondence + closed-by-
|
|
> default matrix, the renewal form's arms incl. the arity gate at both
|
|
> the wire and the handler, delete's NOT_FOUND + internal composition
|
|
> + refusal arms) plus one fleet harness-server test (the three
|
|
> renewal answers with the row-expiry instrument; the foreign token;
|
|
> the custodial-mint refusal under fleet) — env-driven, skipping
|
|
> cleanly server-less (SKIP posture). Gates green: `cargo test`
|
|
> (default 73/19/3), `cargo test --features ops` (92/19/3),
|
|
> `cargo test --all-features` against the harness server (246/125/4 —
|
|
> one pre-existing fleet-timing row flaked once under full-suite load
|
|
> and passed on the isolated + full reruns, untouched by this task's
|
|
> diff: the fleet column reads no ops code), clippy
|
|
> `--all-targets -- -D warnings` on the default/ops/all-features
|
|
> shapes plus the pg-pure checks, `cargo fmt --check`,
|
|
> `cargo doc --no-deps` clean on the default and ops builds. |