docs(tasks): decompose wave 7 — the ops surface, the alkcall-backed op family behind the default-off feature
This commit is contained in:
1 parent
e84a874715
commit
c9829836b1
8 files changed
+852
-2
No files matched your search
@@ -0,0 +1,119 @@
|
||||
---
|
||||
id: ops-json-ops
|
||||
name: the JSON control plane — blobs/stat, blobs/have (+ the token-renewal form), blobs/delete
|
||||
status: pending
|
||||
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
|
||||
|
||||
- [ ] Three spec/handler pairs exported (stat, have, delete); input/
|
||||
output schemas + typed error schemas per alkcall ADR-016
|
||||
- [ ] 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)
|
||||
- [ ] delete: `Visibility::Internal`, the internal-authority-context
|
||||
requirement (not namespace-gated), external discovery NOT_FOUND
|
||||
- [ ] 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
|
||||
- [ ] The handlers touch only the store facade + the foundation's
|
||||
crate-internal renewal access (no backend side-door — the
|
||||
ADR-001 §4 rule)
|
||||
- [ ] 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
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
Reference in new issue
Block a user