diff --git a/.ci/behavior-ownership/partition.v1.json b/.ci/behavior-ownership/partition.v1.json index be940f9bf..fb71dd007 100644 --- a/.ci/behavior-ownership/partition.v1.json +++ b/.ci/behavior-ownership/partition.v1.json @@ -252,6 +252,10 @@ "group": "shared", "target": "backend/app/modules/api_controls/service.py" }, + { + "group": "artifacts", + "target": "backend/app/modules/artifacts/api/review_packet.py" + }, { "group": "artifacts", "target": "backend/app/modules/artifacts/api/submission_admission.py" @@ -1533,7 +1537,7 @@ "target": "backend/scripts/validate_test_lane_evidence.py" } ], - "authority_digest": "fa372bfafa2649a9e94a4bea1d1a0009f4734e5073ff1766c41184ebf6da1801", + "authority_digest": "7ac9e6bbb24c63ce9cbef90541f4c0025ee8a0ebad01caf02f288ea047bff52f", "protected_base_commit": "7676ce4347db0c9694962a9b587a20765e16eac6", "schema": "workstream.behavior-ownership-partition.v1" } diff --git a/.commitrail/INDEX.md b/.commitrail/INDEX.md index c4bdfbd5a..e2aebd63a 100644 --- a/.commitrail/INDEX.md +++ b/.commitrail/INDEX.md @@ -8,13 +8,13 @@ for current product capability. |---|---|---| | [WS-DB-002](initiatives/WS-DB-002/OVERVIEW.md) | Complete | Shared UUIDv7 record generation, native-UUID relationships and fresh v0.1 baseline; natural-owner retry custody and aligned CI/local setup | | [WS-MCP-002](initiatives/WS-MCP-002/OVERVIEW.md) | Planned | Three self-service tools delivered through WS-MCP-002-02; 24 tools remain and WS-MCP-002-03 administrative reads are next | -| [WS-ARCH-001](initiatives/WS-ARCH-001/OVERVIEW.md) | Planned | ARCH-04E1A immutable route-neutral TASK source storage, detached facts and type-only accepted-effects contract are delivered; next build shared REV-04B/CON-03C/07 and REV-12A/CON fence foundations before 04E1B/04E2/04E3 routing and 04F remediation | -| [WS-ART-001](initiatives/WS-ART-001/OVERVIEW.md) | Planned | ARCH-04E1A source facts now retain canonical material lineage without publishing a route; 04F remediation and the later public intake cutover remain | -| [WS-AUTH-001](initiatives/WS-AUTH-001/OVERVIEW.md) | Planned | ARCH-04E1A source facts are delivered without routing authority; shared acceptance foundations and hidden 04E1B proof precede exact 04E2 activation and 04E3 live composition | -| [WS-CON-001](initiatives/WS-CON-001/OVERVIEW.md) | Planned | ARCH-04E1A source facts are delivered; REV-04B source/FinalAcceptance persistence, CON-03C/07 and the shared REV-12A/CON fence foundation are next before either acceptance trigger composes shared effects | -| [WS-AUTH-003](initiatives/WS-AUTH-003/OVERVIEW.md) | Planned | ARCH-04E1A source facts and source-neutral types are delivered without runtime composition; continue boundary recovery through the shared acceptance foundations and later 04E1B/04E2/04E3 route | -| [WS-POL-003](initiatives/WS-POL-003/OVERVIEW.md) | Planned | ARCH-04E1A source facts are delivered, but false activation remains unavailable until shared acceptance, exact routing authority, live composition and 04F remediation are proven | -| [WS-REV-001](initiatives/WS-REV-001/OVERVIEW.md) | Planned | ARCH-04E1A TASK source foundation delivered; REV-04B source/FinalAcceptance, CON-03C/07 and existing REV-12A/CON fence foundations are next; human hidden review work remains independently dependency-gated | +| [WS-ARCH-001](initiatives/WS-ARCH-001/OVERVIEW.md) | Planned | ARCH-04E1A immutable route-neutral TASK source storage, detached facts and type-only accepted-effects contract are delivered; next build REV-03B packet and REV-04A Review storage, then shared REV-04B/CON-03C/07 and REV-12A/CON fence foundations before 04E1B/04E2/04E3 routing and 04F remediation | +| [WS-ART-001](initiatives/WS-ART-001/OVERVIEW.md) | Planned | ART-07A1 metadata-only packet contract and ARCH-04E1A source facts are delivered; REV-03B packet storage, REV-04A Review storage and shared acceptance precede routing, 04F remediation and public intake | +| [WS-AUTH-001](initiatives/WS-AUTH-001/OVERVIEW.md) | Planned | ARCH-04E1A source facts are delivered without routing authority; REV-03B packet and REV-04A Review storage, shared acceptance foundations and hidden 04E1B proof precede exact 04E2 activation and 04E3 live composition | +| [WS-CON-001](initiatives/WS-CON-001/OVERVIEW.md) | Planned | ARCH-04E1A source facts are delivered; REV-03B packet and REV-04A Review storage, then REV-04B FinalAcceptance persistence, CON-03C/07 and the shared REV-12A/CON fence foundation are next before either acceptance trigger composes shared effects | +| [WS-AUTH-003](initiatives/WS-AUTH-003/OVERVIEW.md) | Planned | ARCH-04E1A source facts and source-neutral types are delivered without runtime composition; continue with REV-03B packet and REV-04A Review storage, then shared acceptance foundations and later 04E1B/04E2/04E3 route | +| [WS-POL-003](initiatives/WS-POL-003/OVERVIEW.md) | Planned | ARCH-04E1A source facts and ART-07A1 packet types are delivered; REV-03B packet and REV-04A Review storage come next, while false activation remains unavailable until shared acceptance, exact routing authority, live composition and 04F remediation are proven | +| [WS-REV-001](initiatives/WS-REV-001/OVERVIEW.md) | Planned | ARCH-04E1A TASK source foundation delivered; ART-07A1 packet types delivered; REV-03B packet and REV-04A Review storage, then REV-04B FinalAcceptance, CON-03C/07 and existing REV-12A/CON fence foundations are next; human hidden review work remains independently dependency-gated | | [WS-QUAL-002](initiatives/WS-QUAL-002/OVERVIEW.md) | Planned | Populate subsystem ownership before changed-line mutation work | | [WS-QUAL-003](initiatives/WS-QUAL-003/OVERVIEW.md) | Planned | Audit and prune test proof, add missing safety cases, decompose oversized test modules | | [WS-XINT-002](initiatives/WS-XINT-002/OVERVIEW.md) | Planned | Remaining ART/AUTH activation edges only | diff --git a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md index 8e414e82b..d02a15af9 100644 --- a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md @@ -8,6 +8,10 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), [`planning/chunk contracts`](pre-cutover/chunks/). - Disposition: Planned +- Delivered prerequisite: [ART-07A1](../WS-ART-001/WS-ART-001-07A1.md) supplies + metadata-only packet types; REV-03B packet storage and REV-04A Review storage + precede shared FinalAcceptance. No packet resolver or human runtime is live. + - Completed boundary: through 02H, [CP05](WS-ARCH-001-CP05.md), [CP06](WS-ARCH-001-CP06.md), [CP07](WS-ARCH-001-CP07.md), [ARCH-03A](WS-ARCH-001-03A.md), and [ARCH-04A consolidation](WS-ARCH-001-04A.md) canonical post-submit contracts/conformance. - Intent: keep product modules behind explicit ports and composition roots. @@ -22,7 +26,8 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), authority. The source table has no writer, reader, handler, current pointer, routing authority or acceptance effect implementation. False is proven only as a scalar DTO value because activation still rejects it. -- Next usable boundary: shared REV-04B source/FinalAcceptance persistence, +- Next usable boundary: REV-03B normalized packet persistence, then complete + REV-04A Review storage and shared REV-04B FinalAcceptance persistence, CON-03C/07 and the existing REV-12A/CON fence foundation before shared acceptance composition, then ARCH-04E1B/04E2/04E3 and ARCH-04F. Output-file authority remains unavailable for the zero-output catalogue. diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md b/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md index 66ee57e23..6b6e85444 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md @@ -41,7 +41,7 @@ public intake remains deferred to ARCH-02I. | [WS-ARCH-001-04D1](../WS-ARCH-001-04D1.md) | Canonical terminal ART material custody | L1 | Complete; valid retained history preserved; invalid upgrades refused | | [WS-ARCH-001-04D2](../WS-ARCH-001-04D2.md) | AUTH exact fixed-service post-submit activation (replaces XINT-06B) | L1 | Complete: exact input, execute and finalize authority; output write/bind remains unavailable | | [WS-ARCH-001-04E1A](../WS-ARCH-001-04E1A.md) | Route-neutral immutable source schema and shared accepted-effects types | L1 | Complete; no runtime writer/reader, routing authority, current pointer or effects implementation; false proof is scalar transport only | -| [WS-ARCH-001-04E](chunks/WS-ARCH-001-04E-canonical-allow-review.md) | TASK current routing: true to canonical `allow_review`, false/pass to shared acceptance | L1 | Delivered source 04E1A -> shared REV-04B/CON-03C/07 plus REV-12A/CON fence foundation -> hidden 04E1B -> AUTH 04E2 -> live 04E3, plus 04D2/OUTBOX-02; false activation also requires 04F remediation | +| [WS-ARCH-001-04E](chunks/WS-ARCH-001-04E-canonical-allow-review.md) | TASK current routing: true to canonical `allow_review`, false/pass to shared acceptance | L1 | Delivered source 04E1A -> REV-03B packet and REV-04A Review storage, then shared REV-04B/CON-03C/07 plus REV-12A/CON fence foundation -> hidden 04E1B -> AUTH 04E2 -> live 04E3, plus 04D2/OUTBOX-02; false activation also requires 04F remediation | | [WS-ARCH-001-03D](../WS-ARCH-001-03D.md) | Exact activated historical guide through hidden durable intake; obsolete lookup removed | L1 | Complete; hidden exact post-submit materialization, ARCH-04B2 output custody, ARCH-04C execution, ARCH-04D1/04D2 custody/authority and ARCH-04E1A source-only facts/types delivered; public cutover remains deferred | | [WS-ARCH-001-04F](chunks/WS-ARCH-001-04F-checker-remediation.md) | Contributor-correctable checker failures and same-lineage admission-backed replacement Submission | L1 | Planned after 04E; replaces XINT-05C, required before public 02I, not before REV begins from `allow_review` | diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md index f269d57dc..cf0da3705 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md @@ -57,7 +57,7 @@ checker-remediation boundary before public Submission cutover. | CON-02B | AUTH-OUTBOX-01 | Complete: shared hidden dispatcher/claim fencing, typed handlers and recovery | | AUTH-OUTBOX-02 | CON-02B exact hidden manifest | Exact dispatcher mechanics only; no feature authority | | [ARCH-04E1A](../WS-ARCH-001-04E1A.md) | ARCH-04C/04D2 | Complete: route-neutral immutable TASK source schema/detached facts and source-neutral accepted-effects types; no runtime writer/reader, handlers, current pointer, routing authority, acceptance implementation or REV dependency | -| ARCH-04E1B | ARCH-04E1A, CON-02B hidden contract; shared REV-04B + CON-03C/07 + REV-12A shared fence foundation for false | TASK hidden handlers; consume one shared acceptance operation on false/pass | +| ARCH-04E1B | ARCH-04E1A, CON-02B hidden contract; ART-07A1 types -> REV-03B/04A storage -> shared REV-04B + CON-03C/07 + REV-12A shared fence foundation for false | TASK hidden handlers; consume one shared acceptance operation on false/pass | | Scoped XINT-003-08B controller activation | Early existing REV-12A foundation and hidden shared acceptance/writer/observation proof | Existing Operator lifecycle-control action for the bounded shared manifest, not human runtime | | ARCH-04E2 | ARCH-04E1B; scoped XINT-003-08B controller activation for false | AUTH exact TASK routing authority | | ARCH-04E3 | ARCH-04E2, ARCH-04D2, AUTH-OUTBOX-02; shared acceptance proof for false | TASK live dispatch/routing composition: true to allow_review, false/pass to shared acceptance when proven | @@ -98,7 +98,7 @@ new permission requirement. Delivered supporting foundations are [ARCH-04B2](../WS-ARCH-001-04B2.md), [AUTH-OUTBOX-01/02](../../WS-AUTH-001/planning/PLAN.md#ws-auth-001-outbox-01--unavailable-dispatcher-contract), and [CON-02B](../../WS-CON-001/OVERVIEW.md#con-02b-current-dispatcher-contract). -The remaining routing sequence starts with shared REV-04B/CON-03C/07 and the +The remaining routing sequence starts with REV-03B packet and REV-04A Review storage, then shared REV-04B/CON-03C/07 and the existing REV-12A/CON fence foundation before shared acceptance composition, then [ARCH-04E1B/04E2/04E3](chunks/WS-ARCH-001-04E-canonical-allow-review.md#current-bounded-sequence) and ARCH-04F. ARCH-04E1A is delivered as the source-only predecessor. diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04E-canonical-allow-review.md b/.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04E-canonical-allow-review.md index f27366d24..bf77a15ba 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04E-canonical-allow-review.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04E-canonical-allow-review.md @@ -26,7 +26,10 @@ current TASK children do not implement REV/CON internals: consume the [canonical shared participants and authority contract](../../../../../docs/spec_review_lifecycle.md#finalacceptance). 04E1A's TASK manifest schema/detached facts and narrow accepted-effects Protocol are delivered after 04C, without REV dependency, runtime participant or handlers. -REV-04B can now reference that schema. Shared REV-04B/CON-03C/07 and the early +REV-04B can reference that schema only after its other source prerequisites: +[ART-07A1 packet types](../../../WS-ART-001/WS-ART-001-07A1.md) are delivered; +REV-03B normalized packet storage and complete REV-04A Review storage follow. +Shared REV-04B/CON-03C/07 and the early existing REV-12A/CON fence foundation are hard dependencies of false handler composition, not of this early schema or true admission. This breaks the source-FK dependency cycle. diff --git a/.commitrail/initiatives/WS-ART-001/OVERVIEW.md b/.commitrail/initiatives/WS-ART-001/OVERVIEW.md index 982ded3d4..29b8a9408 100644 --- a/.commitrail/initiatives/WS-ART-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-ART-001/OVERVIEW.md @@ -17,9 +17,11 @@ and the [capability ledger](../../../docs/roadmap_status.md). [ARCH-04D2](../WS-ARCH-001/WS-ARCH-001-04D2.md), without a runtime reader, writer or published route. Output-file authority remains unavailable for the zero-output catalogue. -- Next usable boundary: ARCH-04F checker remediation through existing ART ports, - after the shared acceptance and 04E routing sequence; public intake remains a - later cutover. +- Delivered contract: [ART-07A1](WS-ART-001-07A1.md) defines exact, metadata-only + reviewer packet membership. It supplies no resolver or byte authority. +- Next usable boundary: REV-03B normalized packet persistence, then REV-04A + Review storage before shared acceptance. ARCH-04F remediation and public + intake follow acceptance and routing composition. - Governing sources: artifact specifications, `ArtifactStore`, `ArtifactScratchManager`, code, migrations, and artifact tests. - Preserve: SHA-256/byte-count identity, reread verification, isolation, @@ -45,10 +47,13 @@ must prove exact approved lineage at preparation, consumption and binding. 1. ARCH-04B hidden exact Submission materialization, ARCH-04B2 hidden output custody, ARCH-04C hidden durable execution, ARCH-04D2 fixed-service authority and ARCH-04E1A source-only material lineage are delivered. -2. ARCH-04F owns checker-remediation resubmission using existing ART ports; +2. ART-07A1 metadata-only membership types are delivered. REV-03B packet + storage and complete REV-04A Review storage precede shared FinalAcceptance, + CON participation and the shared fence, then acceptance/routing composition. +3. ARCH-04F owns checker-remediation resubmission using existing ART ports; later reviewer-requested revision remains a separate REV boundary. Add those dependencies before public Submission cutover. -3. Perform ARCH-02I only after those replacement paths exist; historical +4. Perform ARCH-02I only after those replacement paths exist; historical ART-05/06 and XINT-05 designs remain non-executable. ## Preserved history diff --git a/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md b/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md new file mode 100644 index 000000000..d1316bced --- /dev/null +++ b/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md @@ -0,0 +1,195 @@ +# WS-ART-001-07A1 — Exact reviewer packet membership contract + +- Initiative: `WS-ART-001` +- Durable disposition: `Complete` +- Intended merge outcome: Publish ART's bounded, metadata-only packet membership + contract and correct the source-storage prerequisites for shared acceptance. + +## Intent + +The user approved correcting the prerequisite sequence before shared +FinalAcceptance. Preserve one shared acceptance operation for human accept and +false-policy automated acceptance; do not introduce a synthetic Review, +compatibility path or incomplete Review table solely as an FK target. + +On main `7f8acfaf`, ART has immutable Submission bindings and guide-source +bindings. TASK has immutable route-neutral checker source facts. REV has queues +and leases, but no normalized packet manifest or Review. ART has no public +packet-membership contract. `review.decision` is planned; routing action/service +registration, false-policy activation and both acceptance branches are absent. + +## Bounded change + +### Allowed files + +- `backend/app/modules/artifacts/api/review_packet.py`: strict detached values + and a type-only async membership port. +- `backend/app/modules/artifacts/api/__init__.py`: public exports only. +- `backend/tests/artifacts/test_review_packet_contract.py`: focused contract proof. +- `backend/scripts/test_lane_catalogue.py` and `backend/tests/test_ci_lane_catalogue.py`: + explicit registration in existing shared partitions, unchanged execution rules. +- `backend/scripts/behavior_ownership.py`, `backend/tests/test_behavior_ownership.py` + and `.ci/behavior-ownership/partition.v1.json`: exact additive ART API registration + and its independent neighbor-rejection proof only. +- This record and `.commitrail/INDEX.md`. +- `.commitrail/initiatives/WS-ART-001/OVERVIEW.md` +- `.commitrail/initiatives/WS-REV-001/OVERVIEW.md` +- `.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md` +- `.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md` +- `.commitrail/initiatives/WS-POL-003/OVERVIEW.md` +- `.commitrail/initiatives/WS-CON-001/OVERVIEW.md` +- `.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md` +- `.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md` +- `.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md` +- `.commitrail/initiatives/WS-AUTH-001/planning/PLAN.md` +- `.commitrail/initiatives/WS-AUTH-001/planning/CHUNK_MAP.md` +- `.commitrail/initiatives/WS-POL-003/planning/PLAN.md` +- `.commitrail/initiatives/WS-POL-003/planning/CHUNK_MAP.md` +- `.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04E-canonical-allow-review.md`. +- `README.md`, `docs/roadmap_status.md`, `docs/spec_review_lifecycle.md`, + `docs/spec_artifact_storage_service.md`, `docs/architecture_data_model.md`, + `docs/engineering/authorization_activation_custody.md`. +- Local ignored roadmap exports only if present; preserve the single sheet. + +### Not allowed + +No database table/migration, provider or scratch access, materialization adapter, +read implementation, endpoint, service registration, AUTH activation, Review, +FinalAcceptance, CON effect, worker, acceptance-only Review variant, fake receipt, +new lane/timeout/coverage gate, test deletion or retained-data deletion. + +## Design + +Publish one ART-owned `ReviewPacketMembershipPort.resolve_membership` Protocol. +It describes a future caller-session metadata read; there is no implementation, +registration, default or fallback. It grants no authority and performs no I/O. +Future implementations must resolve the exact request from canonical owner facts +inside the caller's transaction and conceal absent, foreign or incomplete sets +with `ReviewPacketMembershipUnavailable`. They must never accept caller-provided +binding lists or silently use current project policies. Byte access still needs +separate exact lease/packet AUTH and bounded ART materialization. + +Strict frozen request values identify project, task, Submission/version, +admitting checker run and aggregate `CheckerRun.result_id` UUID (never an +individual `CheckerResult.id` or copied result digest), locked guide +ID/version/source snapshot, and exact activated project setup run/generation. UUIDs +remain UUIDs; positive versions reject booleans/coercion. Guide version is bounded +nonblank text, not an implementation version. + +The result carries the exact request and: + +- Exactly one required Submission ZIP member: `binding_id` targets + `artifact_bindings`, logical role `submission_bundle_original`, media type `application/zip`. +- One through 100 required guide-original members, matching the existing guide + document bound: `guide_binding_id` targets `guide_source_artifact_bindings`, + `source_item_id`, nonnegative `item_order`, supported canonical guide media type; + logical role `guide_source_original`. Both member kinds are always required; + there is no optional flag to configure. + Source IDs, guide binding IDs and item order are unique; tuple order is canonical. + +Exact type/field inventories: + +| Type | Fields | +|---|---| +| `ReviewPacketMembershipRequest` | project_id, task_id, submission_id, submission_version, checker_run_id, result_id, guide_id, guide_version, source_snapshot_id, project_setup_run_id, setup_generation | +| `ReviewSubmissionMember` | binding_id, logical_role, media_type | +| `ReviewGuideMember` | guide_binding_id, source_item_id, item_order, logical_role, media_type | +| `ReviewPacketMembership` | request, submission, guide_documents | + +`ReviewPacketMembership.require_request(expected)` rejects any scope difference +with the concealed unavailable error, including setup generation/run, same-project +Submission/checker substitutions and guide selectors. Future consumers call this +before using members. The method proves echoed-request equality, not stored +ownership or authorization; those require the later resolver and real database +proof. Resolver membership comes from the activated setup run/generation, never +a later retry against the same snapshot. Member logical-role/media constants are +explicit required fields, not inferred from caller labels. + +Distinct member types preserve the two real FK targets for REV-03B; no generic +opaque binding-ID set or JSON manifest replaces normalized persistence. Reuse +PROJECTS' public `GuideDocumentMediaType` scalar, not its private repositories or +runtime document manifest (which contains digests/replica facts). + +Current post-submit implementations have zero output slots. Checker result +identity remains in the scope, but this contract adds no speculative output-file +member, reviewer-uploaded evidence or revision-response artifact. A future +registered output contract must extend the same membership contract with exact +owner custody before REV may include that output. Guide completeness and actual +stored ownership remain the future resolver's responsibility; shape validation +alone does not prove either. + +All values forbid extra fields. No bytes, content hash, size, content/replica ID, +provider URL/key, scratch path, receipt, lease capability, raw policy, AUTH handle +or arbitrary metadata is returned. Availability is not frozen into the semantic +membership; later authorized reads recheck it. No model claims authority merely +because its shape is valid. + +## Corrected dependency sequence + +This contract -> REV-03B normalized packet persistence -> REV-04A complete Review +source persistence -> REV-04B shared FinalAcceptance source storage -> CON-03C/07 +and the existing shared fence -> one shared acceptance operation -> hidden +routing / exact AUTH activation / live composition -> remediation and public +intake. Do not force live human queues, claims or decisions into the first +false-policy runtime milestone. + +Storage-contract proof and live-authority proof are separate. Before shared +acceptance persistence is implemented, its bounded record must reconcile exact +source receipts and unavailable AUTH contracts without inventing a valid allow. +Contract registration alone is not activation. Real authorized acceptance and +atomic effects must be proven before either runtime branch is enabled. Do not +make AUTH activation depend on an already live acceptance operation; hidden +composition proof precedes activation. No temporary always-deny acceptance table +or target-only Review is added here. + +## Acceptance criteria + +- Public import exposes the sole strict metadata contract, not a runnable adapter. +- Valid initial and later Submission identities round-trip with exact fields. +- Missing/extra/private fields, invalid IDs/versions/media types, duplicate guide + identities/order, unordered/empty/oversized document sets and unknown logical-role + values fail. Required ZIP/guide members cannot become optional. +- Regression uses exact field inventories and nested rejected-field probes; + no public route or composition registration appears. +- Existing module-boundary guard remains unchanged and passes. +- Existing lane catalogue proves exact full inventory; full hosted tests remain + required with zero skips/deselections. No database/provider behavior is claimed + by pure contract tests; existing integration lanes still run. +- Roadmap and linked current entries show the corrected prerequisites, distinguish + types from implemented reads and keep both final policy branches visible. + +## Risk and review routing + +Risk: L1 architecture and privacy contract. Required focused reviewers: +architecture/reuse, security, QA/test-delta, docs/product-operations and CI +integrity for inventory. Human focus: exact metadata ownership and no premature +acceptance or byte authority. No new user decision is needed within this scope. + +## Evidence + +Verification: focused new tests and catalogue tests; Ruff; module boundary, +Commitrail, Markdown links and stale wording; full hosted Backend and API checks. +No historical pre-cutover record is rewritten as a current plan. + +## Reconciliation + +No predecessor implementation exists to retain or alias. Replace affected +current next-step wording in the same PR. Remove obsolete "ART v2" wording from +the touched canonical packet boundary; protocol/business versions remain intact. +Next usable boundary after this contract: REV-03B normalized packet persistence. + +## Implemented outcome + +The sole ART public metadata contract and exact inventory registrations are +implemented. No resolver, schema, provider access or authority is introduced. +Plan review corrected setup-generation identity and reused the aggregate +`CheckerRun.result_id` vocabulary. Current navigation now places REV-03B packet +storage and complete REV-04A Review storage before shared FinalAcceptance. +Pure contract tests cover strict shape, privacy inventories, scope substitution, +required members, uniqueness and canonical order. They do not establish stored +ownership, completeness or authorized byte access. + +Implementation review tightened native Python UUID validation (JSON decoding +remains supported) and reconciled later human-runtime steps with storage already +required by automated acceptance. The substitution regression rejects valid UUID +strings at request and both member boundaries; no compatibility coercion remains. diff --git a/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md b/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md index b4948a18a..e4e98d6c7 100644 --- a/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md @@ -10,6 +10,10 @@ Historical pre-cutover work records: [`STATUS.md`](pre-cutover/STATUS.md), [`planning/chunk contracts`](pre-cutover/chunks/). - Disposition: Planned +- Delivered prerequisite: [ART-07A1](../WS-ART-001/WS-ART-001-07A1.md) supplies + metadata-only packet types; REV-03B packet storage and REV-04A Review storage + precede shared FinalAcceptance. No packet resolver or human runtime is live. + - Intent: provide deny-default, project-scoped authority with canonical human and service identities and attributable audit evidence. - Current boundary: hidden projections and atomic setup finalization have exact @@ -45,7 +49,7 @@ Historical pre-cutover work records: [`STATUS.md`](pre-cutover/STATUS.md), and minimal writers and ARCH-03A internal guide context. POL-07B internal phase composition is delivered. The dispatcher registers only exact assignment invalidation. Future checker routing still requires its separate exact authority and handler. -- Next usable boundary: shared REV-04B/CON-03C/07 and REV-12A/CON fence +- Next usable boundary: REV-03B packet and REV-04A Review storage, then shared REV-04B/CON-03C/07 and REV-12A/CON fence foundations precede shared acceptance composition and hidden ARCH-04E1B; ARCH-04E2 then owns exact routing activation before 04E3 live composition. - Governing source: `docs/spec_authorization_service.md`, authorization code, diff --git a/.commitrail/initiatives/WS-AUTH-001/planning/CHUNK_MAP.md b/.commitrail/initiatives/WS-AUTH-001/planning/CHUNK_MAP.md index 774f457ec..18882bd86 100644 --- a/.commitrail/initiatives/WS-AUTH-001/planning/CHUNK_MAP.md +++ b/.commitrail/initiatives/WS-AUTH-001/planning/CHUNK_MAP.md @@ -1,5 +1,10 @@ # WS-AUTH-001 — Current pre-review activation map +The delivered [ART-07A1 metadata contract](../../WS-ART-001/WS-ART-001-07A1.md) +now precedes REV-03B packet persistence and complete REV-04A Review storage, +then shared REV-04B/CON acceptance foundations. These are storage prerequisites; +no live human-review queue or endpoint is required for automated acceptance. + Use the [current plan](PLAN.md) and [cross-owner order](../../WS-ARCH-001/planning/PLAN.md#current-dependency-contract). The [verbatim former map](../pre-cutover/CHUNK_MAP.md) preserves all completed diff --git a/.commitrail/initiatives/WS-AUTH-001/planning/PLAN.md b/.commitrail/initiatives/WS-AUTH-001/planning/PLAN.md index 7e79be84c..350c57883 100644 --- a/.commitrail/initiatives/WS-AUTH-001/planning/PLAN.md +++ b/.commitrail/initiatives/WS-AUTH-001/planning/PLAN.md @@ -1,5 +1,10 @@ # WS-AUTH-001 — Current pre-review activation plan +The delivered [ART-07A1 metadata contract](../../WS-ART-001/WS-ART-001-07A1.md) +now precedes REV-03B packet persistence and complete REV-04A Review storage, +then shared REV-04B/CON acceptance foundations. These are storage prerequisites; +no live human-review queue or endpoint is required for automated acceptance. + The [cross-owner dependency contract](../../WS-ARCH-001/planning/PLAN.md#current-dependency-contract) owns current delivery order through `allow_review`. The [preserved plan](../pre-cutover/PLAN.md) retains completed history; its broad diff --git a/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md b/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md index 97c39ca90..93413aa8a 100644 --- a/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md +++ b/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md @@ -5,6 +5,10 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), [`planning/chunk contracts`](pre-cutover/chunks/). - Disposition: Planned +- Delivered prerequisite: [ART-07A1](../WS-ART-001/WS-ART-001-07A1.md) supplies + metadata-only packet types; REV-03B packet storage and REV-04A Review storage + precede shared FinalAcceptance. No packet resolver or human runtime is live. + - Completed boundary: recovery foundation and [TASK/checker authorization cleanup](WS-AUTH-003-TASKCHECKER.md). - Intent: route public authorization capability through `authorization.api` and remove cross-module repository/model coupling. @@ -14,8 +18,9 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), [ARCH-04B2 output custody](../WS-ARCH-001/WS-ARCH-001-04B2.md), ARCH-03D hidden intake and [AUTH-18 public manager activation](../WS-AUTH-001/WS-AUTH-001-18.md). They install no routing action, handler or runtime composition. -- Next usable boundary: continue canonical boundary recovery through the shared - REV/CON/fence foundations and later ARCH-04E1B/04E2/04E3 routing sequence. +- Next usable boundary: continue canonical boundary recovery through REV-03B + packet and complete REV-04A Review storage, then shared REV/CON/fence + foundations and later ARCH-04E1B/04E2/04E3 routing. Submission/checker history uses canonical authority; the alternate gate lifecycle is removed. Continue shrinking the canonical import ledger as implementation reaches each remaining consumer. diff --git a/.commitrail/initiatives/WS-CON-001/OVERVIEW.md b/.commitrail/initiatives/WS-CON-001/OVERVIEW.md index 23023f406..656a200f7 100644 --- a/.commitrail/initiatives/WS-CON-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-CON-001/OVERVIEW.md @@ -4,6 +4,10 @@ Current pre-review work follows the [cross-owner dependency contract](../WS-ARCH and the [capability ledger](../../../docs/roadmap_status.md). - Disposition: Planned +- Delivered prerequisite: [ART-07A1](../WS-ART-001/WS-ART-001-07A1.md) supplies + metadata-only packet types; REV-03B packet storage and REV-04A Review storage + precede shared FinalAcceptance. No packet resolver or human runtime is live. + - Completed boundary: public Finance ContributionPolicy administration, exact Finance Authority, CP06 selected-policy validation and CP07 internal guide activation/binding. @@ -32,7 +36,8 @@ and the [capability ledger](../../../docs/roadmap_status.md). and minimal writers, ARCH-03A internal guide context, [CP07 activation/binding](../WS-ARCH-001/WS-ARCH-001-CP07.md) and [AUTH-12H live authority](../WS-AUTH-001/WS-AUTH-001-12H.md), before task readiness. -- Next usable boundary: REV-04B source/FinalAcceptance persistence, then +- Next usable boundary: REV-03B packet and REV-04A Review storage, then + REV-04B FinalAcceptance persistence and CON-03C/07 and the existing shared REV-12A/CON fence foundation before one shared acceptance operation serves both the human and automatic triggers. - Governing sources: `docs/spec_contribution_compensation.md`, diff --git a/.commitrail/initiatives/WS-POL-003/OVERVIEW.md b/.commitrail/initiatives/WS-POL-003/OVERVIEW.md index 67e2ed554..8b457c68a 100644 --- a/.commitrail/initiatives/WS-POL-003/OVERVIEW.md +++ b/.commitrail/initiatives/WS-POL-003/OVERVIEW.md @@ -16,6 +16,10 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), [`planning/chunk contracts`](pre-cutover/chunks/). - Disposition: Planned +- Delivered prerequisite: [ART-07A1](../WS-ART-001/WS-ART-001-07A1.md) supplies + metadata-only packet types; REV-03B packet storage and REV-04A Review storage + precede shared FinalAcceptance. No packet resolver or human runtime is live. + - Completed boundary: automatic unified execution, deterministic projections, immutable setup finalization, current-authority replay and one public guide creation/document-upload flow; hidden complete-proposal review, pre-submission @@ -57,7 +61,7 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), Earlier development schemas require no backward-compatibility paths. The existing ReviewPolicy boolean is delivered; false has scalar DTO proof only and automated acceptance remains unavailable. -- Next usable boundary: shared REV-04B/CON-03C/07 and REV-12A/CON fence +- Next usable boundary: REV-03B packet and REV-04A Review storage, then shared REV-04B/CON-03C/07 and REV-12A/CON fence foundations, then shared acceptance composition and ARCH-04E1B/04E2/04E3. ARCH-04F remediation still precedes enabling false. - Governing sources: project-guide specifications, authorization and diff --git a/.commitrail/initiatives/WS-POL-003/planning/CHUNK_MAP.md b/.commitrail/initiatives/WS-POL-003/planning/CHUNK_MAP.md index 0e6d16efc..15bb7cb6a 100644 --- a/.commitrail/initiatives/WS-POL-003/planning/CHUNK_MAP.md +++ b/.commitrail/initiatives/WS-POL-003/planning/CHUNK_MAP.md @@ -1,5 +1,10 @@ # Chunk Map: WS-POL-003 - Unified Project Guide Compilation +The delivered [ART-07A1 metadata contract](../../WS-ART-001/WS-ART-001-07A1.md) +now precedes REV-03B packet persistence and complete REV-04A Review storage, +then shared REV-04B/CON acceptance foundations. These are storage prerequisites; +no live human-review queue or endpoint is required for automated acceptance. + All chunks are L1 and one PR each. Product behavior is built hidden before AUTH activation; only a later live-cutover chunk exposes it. Open pull requests show transient work, and no chunk starts automatically. diff --git a/.commitrail/initiatives/WS-POL-003/planning/PLAN.md b/.commitrail/initiatives/WS-POL-003/planning/PLAN.md index de75e7268..ff6a70309 100644 --- a/.commitrail/initiatives/WS-POL-003/planning/PLAN.md +++ b/.commitrail/initiatives/WS-POL-003/planning/PLAN.md @@ -1,5 +1,10 @@ # Plan: WS-POL-003 - Unified Project Guide Compilation +The delivered [ART-07A1 metadata contract](../../WS-ART-001/WS-ART-001-07A1.md) +now precedes REV-03B packet persistence and complete REV-04A Review storage, +then shared REV-04B/CON acceptance foundations. These are storage prerequisites; +no live human-review queue or endpoint is required for automated acceptance. + ## Objective The delivered setup replaces the former three complete project-guide inference passes with one diff --git a/.commitrail/initiatives/WS-REV-001/OVERVIEW.md b/.commitrail/initiatives/WS-REV-001/OVERVIEW.md index 3333a8ffe..41bcde450 100644 --- a/.commitrail/initiatives/WS-REV-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-REV-001/OVERVIEW.md @@ -5,6 +5,10 @@ This is the pre-review admission fact, not REV activation or implementation of review/revision behavior. The downstream owner contracts remain separate. - Disposition: Planned +- Delivered prerequisite: [ART-07A1](../WS-ART-001/WS-ART-001-07A1.md) supplies + metadata-only packet types; REV-03B packet storage and REV-04A Review storage + precede shared FinalAcceptance. No packet resolver or human runtime is live. + - Completed boundary: queue admission and ReviewLease persistence through 03A2. - Intent: ensure the authorized reviewer evaluates the exact verified artifact under the locked policy version and produces attributable outcomes. @@ -12,7 +16,8 @@ of review/revision behavior. The downstream owner contracts remain separate. source storage, detached source facts and the type-only accepted-effects Protocol. It provides no writer, reader, handler, routing authority, current pointer or acceptance implementation. -- Next usable boundary: REV-04B shared source/FinalAcceptance persistence, +- Next usable boundary: REV-03B normalized packet persistence, then complete + REV-04A Review storage and REV-04B shared FinalAcceptance persistence, CON-03C/07 and the existing REV-12A/CON fence foundation under the canonical order; human hidden behavior may continue independently behind exact AUTH, ART and CON prerequisites. @@ -57,13 +62,14 @@ live human queues, ReviewLeases or decision endpoints. Human lifecycle work remains required for v0.1, but need not delay the first automated end-to-end proof. No adjudication setting or behavior is included. -1. `03B`: normalized reviewer packet manifest after ART publishes the exact - packet-membership contract. +1. `03B`: normalized reviewer packet persistence consumes the delivered + [ART-07A1 exact membership contract](../WS-ART-001/WS-ART-001-07A1.md). + Next complete REV-04A Review-source storage; neither step activates human review. 2. Continue hidden claim/revision behavior against canonical `allow_review`, copying the Submission policy version without a current-policy lookup. 3. TASK's early 04E1A source schema/detached facts and source-neutral accepted- - effects types are delivered. Implement the REV-04B shared - source/FinalAcceptance persistence foundation next, + effects types are delivered. After REV-03B and complete REV-04A source + storage, implement the REV-04B shared FinalAcceptance persistence foundation, then CON-03C/CON-07 persistence and submitter participation. This foundation can precede human runtime: ARCH-04E uses it for false/pass acceptance without live queues, leases or decisions. Pull the existing REV-12A/CON shared diff --git a/README.md b/README.md index 1d322845a..426843e7b 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,12 @@ unified setup agent. Guide metadata in PostgreSQL also holds at least one requir task example; the agent assesses the examples with the uploaded guide documents. Findings and policy proposals retain document-access evidence. +[ART-07A1](.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md) provides strict +metadata-only reviewer packet types, not a resolver or byte-access capability. +Next are REV-03B normalized packet storage and complete REV-04A Review storage, +then shared FinalAcceptance. These internal prerequisites do not require live +human review before the first automated acceptance path. + Active work is connecting those foundations into the remaining production lifecycle: the remaining artifact custody chain, review and revision, contribution records, and conditional compensation awards and fulfillment. diff --git a/backend/app/modules/artifacts/api/__init__.py b/backend/app/modules/artifacts/api/__init__.py index 47813c349..183c8a63d 100644 --- a/backend/app/modules/artifacts/api/__init__.py +++ b/backend/app/modules/artifacts/api/__init__.py @@ -17,7 +17,22 @@ SubmissionAdmissionConsumptionStatus, ) +from app.modules.artifacts.api.review_packet import ( + ReviewGuideMember, + ReviewPacketMembership, + ReviewPacketMembershipPort, + ReviewPacketMembershipRequest, + ReviewPacketMembershipUnavailable, + ReviewSubmissionMember, +) + __all__ = ( + "ReviewGuideMember", + "ReviewPacketMembership", + "ReviewPacketMembershipPort", + "ReviewPacketMembershipRequest", + "ReviewPacketMembershipUnavailable", + "ReviewSubmissionMember", "SubmissionBundlePreparationCommand", "SubmissionBundlePreparationRejected", "SubmissionBundlePreparationInfrastructureUnavailable", diff --git a/backend/app/modules/artifacts/api/review_packet.py b/backend/app/modules/artifacts/api/review_packet.py new file mode 100644 index 000000000..f3dca2d89 --- /dev/null +++ b/backend/app/modules/artifacts/api/review_packet.py @@ -0,0 +1,105 @@ +"""Exact reviewer packet metadata; these values grant no artifact access.""" + +from __future__ import annotations + +from typing import Literal, Protocol +from uuid import UUID + +from pydantic import BaseModel, ConfigDict, Field, StrictInt, field_validator, model_validator + +from app.modules.projects.api.guide_documents import GuideDocumentMediaType + + +class ReviewPacketMembershipUnavailable(RuntimeError): + """Conceal absent, foreign or incomplete membership without private details.""" + + def __init__(self) -> None: + super().__init__("review_packet_membership_unavailable") + + +class ReviewPacketMembershipRequest(BaseModel): + """Locked scope; result_id names CheckerRun.result_id, not CheckerResult.id.""" + + model_config = ConfigDict(extra="forbid", frozen=True, strict=True) + + project_id: UUID + task_id: UUID + submission_id: UUID + submission_version: StrictInt = Field(ge=1) + checker_run_id: UUID + result_id: UUID + guide_id: UUID + guide_version: str = Field(min_length=1, max_length=50) + source_snapshot_id: UUID + project_setup_run_id: UUID + setup_generation: StrictInt = Field(ge=1) + + @field_validator("guide_version") + @classmethod + def nonblank_guide_version(cls, value: str) -> str: + if not value.strip(): + raise ValueError("guide version must not be blank") + return value + + +class ReviewSubmissionMember(BaseModel): + """Required original ZIP; binding_id identifies ART's artifact_bindings row.""" + + model_config = ConfigDict(extra="forbid", frozen=True, strict=True) + + binding_id: UUID + logical_role: Literal["submission_bundle_original"] + media_type: Literal["application/zip"] + + +class ReviewGuideMember(BaseModel): + """Required original document from ART's guide_source_artifact_bindings.""" + + model_config = ConfigDict(extra="forbid", frozen=True, strict=True) + + guide_binding_id: UUID + source_item_id: UUID + item_order: StrictInt = Field(ge=0) + logical_role: Literal["guide_source_original"] + media_type: GuideDocumentMediaType + + +class ReviewPacketMembership(BaseModel): + """Complete metadata shape; stored ownership/completeness need owner resolution.""" + + model_config = ConfigDict(extra="forbid", frozen=True, strict=True) + + request: ReviewPacketMembershipRequest + submission: ReviewSubmissionMember + guide_documents: tuple[ReviewGuideMember, ...] = Field(min_length=1, max_length=100) + + @model_validator(mode="after") + def canonical_documents(self) -> ReviewPacketMembership: + for attribute in ("guide_binding_id", "source_item_id", "item_order"): + values = [getattr(document, attribute) for document in self.guide_documents] + if len(values) != len(set(values)): + raise ValueError("review packet guide membership is duplicated") + orders = tuple(document.item_order for document in self.guide_documents) + if orders != tuple(sorted(orders)): + raise ValueError("review packet guide documents are not in source order") + return self + + def require_request(self, expected: ReviewPacketMembershipRequest) -> None: + """Check echoed scope before use; this does not prove stored ownership.""" + if self.request != expected: + raise ReviewPacketMembershipUnavailable() + + +class ReviewPacketMembershipPort(Protocol): + """Future caller-transaction read; no implementation or authority is provided. + + Resolve the entire declared set from canonical owner facts for this exact + activated setup run/generation. Never select a latest policy or accept a + caller's binding list. Conceal missing, foreign or incomplete sets with + ReviewPacketMembershipUnavailable. Consumers require_request before use; + byte reads separately require exact lease/packet authorization. + """ + + async def resolve_membership( + self, request: ReviewPacketMembershipRequest, + ) -> ReviewPacketMembership: ... diff --git a/backend/scripts/behavior_ownership.py b/backend/scripts/behavior_ownership.py index 9ae0ecd14..aa09fb43b 100644 --- a/backend/scripts/behavior_ownership.py +++ b/backend/scripts/behavior_ownership.py @@ -132,6 +132,7 @@ MODULE_PUBLIC_API_FOUNDATION_TARGETS = frozenset( { "backend/app/api/routes/artifact_submissions.py", + "backend/app/modules/artifacts/api/review_packet.py", "backend/app/modules/artifacts/api/submission_admission.py", "backend/app/modules/artifacts/api/submission_preparation.py", "backend/app/modules/artifacts/submission_bindings.py", diff --git a/backend/scripts/test_lane_catalogue.py b/backend/scripts/test_lane_catalogue.py index 994ccbf98..f37c2b090 100644 --- a/backend/scripts/test_lane_catalogue.py +++ b/backend/scripts/test_lane_catalogue.py @@ -23,6 +23,7 @@ class TestLane: SHARED_FOUNDATION_MODULES = ( + "tests/artifacts/test_review_packet_contract.py", "tests/authorization/post_submit/test_atomicity.py", "tests/authorization/post_submit/test_concurrency.py", "tests/authorization/post_submit/test_live_authority.py", diff --git a/backend/tests/artifacts/test_review_packet_contract.py b/backend/tests/artifacts/test_review_packet_contract.py new file mode 100644 index 000000000..605e64231 --- /dev/null +++ b/backend/tests/artifacts/test_review_packet_contract.py @@ -0,0 +1,198 @@ +"""Metadata transport proofs, without claiming stored ownership or authority.""" + +from copy import deepcopy +from uuid import UUID + +from pydantic import ValidationError +import pytest + +from app.modules.artifacts.api import ( + ReviewGuideMember, + ReviewPacketMembership, + ReviewPacketMembershipPort, + ReviewPacketMembershipRequest, + ReviewPacketMembershipUnavailable, + ReviewSubmissionMember, +) + + +def packet() -> dict: + return { + "request": { + "project_id": UUID(int=1), "task_id": UUID(int=2), + "submission_id": UUID(int=3), "submission_version": 1, + "checker_run_id": UUID(int=4), "result_id": UUID(int=5), + "guide_id": UUID(int=6), "guide_version": "initial-guide", + "source_snapshot_id": UUID(int=7), "project_setup_run_id": UUID(int=8), + "setup_generation": 1, + }, + "submission": { + "binding_id": UUID(int=9), "logical_role": "submission_bundle_original", + "media_type": "application/zip", + }, + "guide_documents": (guide(0), guide(2)), + } + + +def guide(order: int) -> dict: + return { + "guide_binding_id": UUID(int=100 + order), + "source_item_id": UUID(int=300 + order), "item_order": order, + "logical_role": "guide_source_original", "media_type": "application/pdf", + } + + +@pytest.mark.parametrize("version", [1, 4]) +def test_exact_packet_round_trip_and_frozen_nested_values(version: int) -> None: + raw = packet() + raw["request"]["submission_version"] = version + value = ReviewPacketMembership.model_validate(raw) + value.require_request(ReviewPacketMembershipRequest.model_validate(raw["request"])) + assert ReviewPacketMembership.model_validate_json(value.model_dump_json()) == value + assert value.model_dump() == {**raw, "guide_documents": tuple(raw["guide_documents"])} + assert isinstance(value.request.project_id, UUID) + for obj, field, replacement in ( + (value, "submission", value.submission), + (value.request, "submission_version", 2), + (value.submission, "binding_id", UUID(int=20)), + (value.guide_documents[0], "item_order", 7), + ): + with pytest.raises(ValidationError, match="frozen"): + setattr(obj, field, replacement) + + +def test_closed_public_field_inventories() -> None: + assert set(ReviewPacketMembershipRequest.model_fields) == { + "project_id", "task_id", "submission_id", "submission_version", "checker_run_id", + "result_id", "guide_id", "guide_version", "source_snapshot_id", + "project_setup_run_id", "setup_generation", + } + assert set(ReviewSubmissionMember.model_fields) == {"binding_id", "logical_role", "media_type"} + assert set(ReviewGuideMember.model_fields) == { + "guide_binding_id", "source_item_id", "item_order", "logical_role", "media_type", + } + assert set(ReviewPacketMembership.model_fields) == {"request", "submission", "guide_documents"} + with pytest.raises(TypeError, match="Protocols cannot be instantiated"): + ReviewPacketMembershipPort() + + +@pytest.mark.parametrize("scope", ["packet", "request", "submission", "guide"]) +def test_every_field_required_and_private_additions_rejected(scope: str) -> None: + raw = packet() + model, data = { + "packet": (ReviewPacketMembership, raw), + "request": (ReviewPacketMembershipRequest, raw["request"]), + "submission": (ReviewSubmissionMember, raw["submission"]), + "guide": (ReviewGuideMember, raw["guide_documents"][0]), + }[scope] + model.model_validate(data) + for name in data: + reduced = {key: value for key, value in data.items() if key != name} + with pytest.raises(ValidationError, match="Field required"): + model.model_validate(reduced) + for name in ( + "required", "sha256", "byte_count", "content_id", "replica_id", "provider_url", + "object_key", "scratch_path", "receipt", "lease_capability", "policy", "metadata", + "checker_result_id", "authorization", + ): + with pytest.raises(ValidationError, match="Extra inputs"): + model.model_validate({**data, name: False}) + + +@pytest.mark.parametrize("field", list(packet()["request"])) +def test_scope_substitution_is_concealed(field: str) -> None: + raw = packet() + value = ReviewPacketMembership.model_validate(raw) + changed = deepcopy(raw["request"]) + old = changed[field] + changed[field] = UUID(int=999) if isinstance(old, UUID) else old + 1 if isinstance(old, int) else "other-guide" + expected = ReviewPacketMembershipRequest.model_validate(changed) + with pytest.raises(ReviewPacketMembershipUnavailable) as caught: + value.require_request(expected) + assert str(caught.value) == "review_packet_membership_unavailable" + + +def test_invalid_ids_and_strict_versions() -> None: + raw = packet() + for name, value in raw["request"].items(): + if isinstance(value, UUID): + with pytest.raises(ValidationError): + ReviewPacketMembershipRequest.model_validate({**raw["request"], name: "invalid"}) + for model, data, fields in ( + (ReviewSubmissionMember, raw["submission"], ["binding_id"]), + (ReviewGuideMember, raw["guide_documents"][0], ["guide_binding_id", "source_item_id"]), + ): + for name in fields: + with pytest.raises(ValidationError): + model.model_validate({**data, name: "invalid"}) + for name in ("submission_version", "setup_generation"): + for invalid in (0, -1, True, "1", 1.0): + with pytest.raises(ValidationError): + ReviewPacketMembershipRequest.model_validate({**raw["request"], name: invalid}) + for invalid in ("", " ", "x" * 51): + with pytest.raises(ValidationError): + ReviewPacketMembershipRequest.model_validate({**raw["request"], "guide_version": invalid}) + for invalid in (-1, True, "0", 0.0): + with pytest.raises(ValidationError): + ReviewGuideMember.model_validate({**guide(0), "item_order": invalid}) + + +def test_closed_roles_and_supported_media() -> None: + raw = packet() + for model, data in ((ReviewSubmissionMember, raw["submission"]), (ReviewGuideMember, guide(0))): + for field, invalid in (("logical_role", "other"), ("media_type", "text/plain")): + with pytest.raises(ValidationError): + model.model_validate({**data, field: invalid}) + for media in ( + "application/pdf", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ): + assert ReviewGuideMember.model_validate({**guide(0), "media_type": media}).media_type == media + + +@pytest.mark.parametrize("attribute", ["guide_binding_id", "source_item_id", "item_order"]) +def test_independent_duplicate_membership_rejected(attribute: str) -> None: + raw = packet() + raw["guide_documents"][1][attribute] = raw["guide_documents"][0][attribute] + with pytest.raises(ValidationError, match="membership is duplicated"): + ReviewPacketMembership.model_validate(raw) + + +def test_canonical_order_and_document_count_bounds() -> None: + raw = packet() + ReviewPacketMembership.model_validate(raw) + with pytest.raises(ValidationError) as caught: + ReviewPacketMembership.model_validate({**raw, "guide_documents": list(raw["guide_documents"])}) + assert len(caught.value.errors()) == 1 + assert caught.value.errors()[0]["type"] == "tuple_type" + assert caught.value.errors()[0]["loc"] == ("guide_documents",) + with pytest.raises(ValidationError, match="source order"): + ReviewPacketMembership.model_validate({**raw, "guide_documents": tuple(reversed(raw["guide_documents"]))}) + for count in (1, 100): + assert len(ReviewPacketMembership.model_validate({**raw, "guide_documents": tuple(guide(i) for i in range(count))}).guide_documents) == count + for count in (0, 101): + with pytest.raises(ValidationError): + ReviewPacketMembership.model_validate({**raw, "guide_documents": tuple(guide(i) for i in range(count))}) + + +def test_python_uuid_strings_rejected_at_each_nested_boundary() -> None: + """JSON is decoded at its boundary; Python callers must supply native UUIDs.""" + raw = packet() + ReviewPacketMembership.model_validate(raw) + for scope, fields in ( + ("request", ("project_id", "task_id", "submission_id", "checker_run_id", + "result_id", "guide_id", "source_snapshot_id", "project_setup_run_id")), + ("submission", ("binding_id",)), + ("guide", ("guide_binding_id", "source_item_id")), + ): + for field in fields: + changed = deepcopy(raw) + nested = changed["guide_documents"][0] if scope == "guide" else changed[scope] + nested[field] = str(nested[field]) + with pytest.raises(ValidationError) as caught: + ReviewPacketMembership.model_validate(changed) + assert len(caught.value.errors()) == 1 + assert caught.value.errors()[0]["type"] == "is_instance_of" + expected_location = ("guide_documents", 0, field) if scope == "guide" else (scope, field) + assert caught.value.errors()[0]["loc"] == expected_location diff --git a/backend/tests/test_behavior_ownership.py b/backend/tests/test_behavior_ownership.py index 51c149ef2..34385eb34 100644 --- a/backend/tests/test_behavior_ownership.py +++ b/backend/tests/test_behavior_ownership.py @@ -2210,3 +2210,15 @@ def test_routing_source_registration_rejects_adjacent_runtime_targets(): ownership._validate_additive_partition_transition( _partition(sorted({retained, *expected, neighbor})), trusted ) + + +def test_review_packet_contract_addition_preserves_existing_ownership() -> None: + retained = "backend/app/core/config.py" + addition = "backend/app/modules/artifacts/api/review_packet.py" + trusted = _partition([retained]) + current = _partition(sorted([retained, addition])) + ownership._validate_additive_partition_transition(current, trusted) + assert ownership.group_for_target(addition) == "artifacts" + for targets in ([addition], [retained, addition, "backend/app/modules/artifacts/api/packet_reader.py"]): + with pytest.raises(ownership.BehaviorOwnershipError, match="untrusted_partition_change"): + ownership._validate_additive_partition_transition(_partition(sorted(targets)), trusted) diff --git a/backend/tests/test_ci_lane_catalogue.py b/backend/tests/test_ci_lane_catalogue.py index 1c9a03b43..9d3dd7780 100644 --- a/backend/tests/test_ci_lane_catalogue.py +++ b/backend/tests/test_ci_lane_catalogue.py @@ -261,6 +261,7 @@ def test_measured_hotspots_have_explicit_semantic_owners() -> None: shared_a = modules_by_lane[catalogue.PARTITIONED_SHARED_LANES[0]] shared_b = modules_by_lane[catalogue.PARTITIONED_SHARED_LANES[1]] assert shared_a == shared_b == set(catalogue.SHARED_FOUNDATION_MODULES) + assert "tests/artifacts/test_review_packet_contract.py" in shared_a assert { "tests/authorization/post_submit/test_atomicity.py", "tests/authorization/post_submit/test_concurrency.py", diff --git a/docs/architecture_data_model.md b/docs/architecture_data_model.md index 098487bb5..a72052e62 100644 --- a/docs/architecture_data_model.md +++ b/docs/architecture_data_model.md @@ -1835,6 +1835,12 @@ REV's database guard rejects a draft, crossed-project, or lineage-mismatched identity. Reviewer and preferred-reviewer FKs accept only canonical human ActorProfiles. +`ReviewPacketManifest` remains planned REV persistence. The delivered +[ART-07A1 contract](../.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md) +provides metadata-only types with distinct Submission and guide binding IDs, +not a packet table, resolver or byte capability. REV-03B will normalize those +members before complete REV-04A Review storage and shared FinalAcceptance. + `ReviewPacketManifest` is an immutable REV semantic projection over the exact lease, Submission, admitting CheckerRun/results, stamped context, response evidence, and ART binding IDs. It contains no bytes, digest, provider locator, diff --git a/docs/engineering/authorization_activation_custody.md b/docs/engineering/authorization_activation_custody.md index b5715ce8b..95b9a4b15 100644 --- a/docs/engineering/authorization_activation_custody.md +++ b/docs/engineering/authorization_activation_custody.md @@ -66,6 +66,11 @@ The CHECKERS zero-slot reservation reader is implemented. Output authority remai fixed-service AUTH/PREP and an exact current execution lease. Execute/finalize use the fixed `workstream.checker.post_submit` identity and phase-specific receipts. Do not implement an additional XINT-06B lane. +[ART-07A1](../../.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md) delivers +metadata-only packet types without authority or a resolver. REV-03B packet +storage and complete REV-04A Review storage precede shared FinalAcceptance; +hidden composition proof precedes exact activation. + Runtime owner `WS-XINT-002-07` retains catalogue custody. The only approved v0.1 availability transition is 07A packet materialization. Evidence binding remains planned and unavailable pending a separate REV-owned intent. diff --git a/docs/roadmap_status.md b/docs/roadmap_status.md index 6485f95bd..d56cf7278 100644 --- a/docs/roadmap_status.md +++ b/docs/roadmap_status.md @@ -115,7 +115,9 @@ pointer, routing authority or acceptance behavior. Required success then branches on the locked ReviewPolicy: true routes to human `allow_review`; false invokes shared authorized acceptance without a human Review. Both routing integrations remain planned; false has scalar DTO proof only and guide activation -still rejects it. Human review/revision, contribution and conditional +still rejects it. ART-07A1 supplies metadata-only reviewer packet types, with no resolver or byte +authority. REV-03B packet persistence and complete REV-04A Review storage come +next, before shared acceptance storage. Human review/revision, contribution and conditional compensation effects, operations and release proof complete v0.1. The [independent MCP package](../mcp_server/README.md) implements one profile @@ -166,8 +168,8 @@ cannot be reused as post-submission review-gate evidence. See the | Contributor artifact preparation | **Hidden and proven** | One outer ZIP; bounded scratch inspection; canonical manifest; platform and project prechecks; unchanged-work rejection; durable put intent; verification; capacity-charged ready admission; hidden final handoff validates the exact activated historical guide through owner ports | Complete the later public admission-only cutover | | Pre-submission intake checking | **Hidden with approved-guide lineage** | Separate versioned pre-submission catalogue, locked effective-plan compilation, platform/project checks during continuous preparation, blocking feedback before Submission creation, and one internal phase command covering execution/replay with the JSON precheck removed; ARCH-03D connects approved-guide lineage through the final durable handoff | Complete the canonical public cutover after evaluation/remediation prerequisites; passing intake must never substitute for post-submit evaluation | | Immutable Submission creation | **Hidden foundation; public packet creation retired** | Contributor preparation authority; durable pre-submit reservation and exact completed-evidence recovery without rerunning checks; atomic admission consumption; TASK-owned admission-backed creation with exact assignment ContributionPolicyVersion and locked policy lineage; fixed-service artifact binding; replay/concurrency/rollback proof | Finish downstream evaluation and the canonical public integration. The retained submission-list GET is not a usable creation POST | -| Post-submission evaluation and `allow_review` | **Hidden source foundation; routing planned** | One canonical CHECKER post-submit catalogue/compiler used by existing consumers, internal phase service with exact fixed-service post-submit authority, hidden value contracts and structural-handler conformance; ARCH-04B/04B2 input and output custody; ARCH-04C durable execution and current-result custody; ARCH-04D1 canonical ART material custody; ARCH-04D2 exact phase authority and receipts; ARCH-04E1A immutable route-neutral source table, detached facts and type-only accepted-effects Protocol | Build shared REV-04B/CON-03C/07 and REV-12A/CON fence foundations, then 04E1B/04E2/04E3 dispatch and routing plus 04F remediation. Before publication, harden the same source table with mandatory exact route/owner receipts and refuse retained pre-authority rows. No writer, reader, handler, current pointer, route or acceptance effect is live | -| Review queue and lease | **Hidden persistence foundation** | Queue/admission idempotency and ReviewLease/preference persistence; complete unavailable REV action/principal catalogue and typed AUTH contracts | Packet-membership contract and manifest; Review schema; canonical admission from `allow_review`; claim/lease/packet authority; lease copies the Submission-stamped policy version with no CON lookup | +| Post-submission evaluation and `allow_review` | **Hidden source foundation; routing planned** | One canonical CHECKER post-submit catalogue/compiler used by existing consumers, internal phase service with exact fixed-service post-submit authority, hidden value contracts and structural-handler conformance; ARCH-04B/04B2 input and output custody; ARCH-04C durable execution and current-result custody; ARCH-04D1 canonical ART material custody; ARCH-04D2 exact phase authority and receipts; ARCH-04E1A immutable route-neutral source table, detached facts and type-only accepted-effects Protocol | Build REV-03B packet and REV-04A Review storage, then shared REV-04B/CON-03C/07 and REV-12A/CON fence foundations, then 04E1B/04E2/04E3 dispatch and routing plus 04F remediation. Before publication, harden the same source table with mandatory exact route/owner receipts and refuse retained pre-authority rows. No writer, reader, handler, current pointer, route or acceptance effect is live | +| Review queue and lease | **Hidden persistence foundation** | Queue/admission idempotency and ReviewLease/preference persistence; complete unavailable REV action/principal catalogue and typed AUTH contracts; ART-07A1 metadata-only packet contract | REV-03B normalized packet persistence and resolver proof; REV-04A Review schema; canonical admission from `allow_review`; claim/lease/packet authority; lease copies the Submission-stamped policy version with no CON lookup | | Review decision and revision | **Planned** | Review/revision policy identities and mutation authority; approved same-task revision-rebase semantics | Immutable findings and decisions; `accept`, `needs_revision`, and `reject`; complete-context revision preparation; finding responses; replacement contributor rules; replay and recovery | | Contribution and compensation truth | **Schema foundations plus public policy administration** | ContributionPolicyVersion persistence; lifecycle-audit participant; adapter bindings; public Finance policy administration | Persist ContributionRecord/CompensationAward and one shared FinalAcceptance/submitter operation for human accept or authorized false/pass routing. Only actual Reviews create reviewer records. Evaluate frozen actor rules into zero, one or two awards | | Fulfillment, reconciliation, and audit | **Planned** | Shared audit foundations, provider-neutral adapter convention, AUTH-OUTBOX-02 live dispatcher authority, retained phase audit decisions, Celery delivery/recovery scans and CON-02B custody | Feature-specific handlers and authority, conditional award fulfillment, callbacks, idempotent recovery, reconciliation, bounded operational reads, and release controls | @@ -464,7 +466,7 @@ The next dependency-safe product sequence is: ARCH-04D2 supplies exact input/execute/finalize service authority and durable receipt custody. ARCH-04E1A supplies one immutable route-neutral source table, detached facts and source-neutral accepted-effects types. It has no runtime - entry. Shared REV-04B/CON-03C/07 and the existing REV-12A/CON fence foundation + entry. REV-03B packet and REV-04A Review storage, then shared REV-04B/CON-03C/07 and the existing REV-12A/CON fence foundation come next; ARCH-04E1B/04E2/04E3 then dispatch evaluation and publish an exact human `allow_review` manifest on true when no blocking failure exists. CHECKERS owns durable execution/currentness; the shared facade does not @@ -475,7 +477,8 @@ The next dependency-safe product sequence is: approved catalogue-bound generation. Infrastructure retries and project setup faults are not contributor failures; `allow_review` is not acceptance. **For the first false-policy acceptance path:** consume the delivered TASK - 04E1A source facts in REV-04B's source FK; complete CON-03C/07 and the existing + 04E1A source facts in REV-04B's source FK after REV-03B packet and complete + REV-04A Review storage; complete CON-03C/07 and the existing shared fence/controller slice, then wire one shared acceptance operation through 04E1B/04E2/04E3. Prove real scoped activation/drain and 04F remediation before enabling false. This milestone creates the submitter contribution and @@ -491,8 +494,9 @@ The next dependency-safe product sequence is: correction feedback for blocking intake failures and publishes ready admission only after the required preparation/custody checks; the existing TASK creation operation consumes that admission with the assignment's locked lineage. -4. **Start the live REV path.** Complete packet, Review, and FinalAcceptance - persistence; admit only canonical `allow_review`; claim a bounded lease and +4. **Start the live REV path.** Reuse the packet, Review and FinalAcceptance + storage completed before the automated path. Admit only canonical + `allow_review`; claim a bounded lease and exact packet using the Submission-stamped ContributionPolicyVersion. 5. **Make human review decisions economically complete.** Before the first live Review commit, add the reviewer CON operation and reuse the shared acceptance @@ -578,10 +582,12 @@ Delivered foundations (not a claim of full public integration) ARCH-04D1 canonical ART material custody at terminal CHECKERS commit ARCH-04D2 exact input/execute/finalize authority + durable receipts ARCH-04E1A immutable route-neutral TASK source facts + type-only effects port + ART-07A1 metadata-only packet membership types (no resolver/byte authority) | v Remaining integration - shared REV-04B/CON-03C/07 + REV-12A/CON fence foundation + REV-03B normalized packet -> REV-04A complete Review storage + -> shared REV-04B/CON-03C/07 + REV-12A/CON fence foundation -> shared acceptance composition -> 04E1B/04E2/04E3 dispatch/routing -> 04F remediation -> public intake and immutable admitted Submission cutover @@ -702,7 +708,9 @@ remaining trace sequence is: and [ARCH-04D2 exact service authority](../.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04D2.md) lead to delivered [ARCH-04E1A source facts](../.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1A.md). - Shared REV-04B/CON-03C/07 and the REV-12A/CON fence foundation precede + Delivered [ART-07A1 packet types](../.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md) + precede REV-03B packet and REV-04A Review storage, then shared + REV-04B/CON-03C/07 and the REV-12A/CON fence foundation before `04E1B -> 04E2 -> 04E3` dispatch and routing; 04F supplies remediation. The mandatory [04D1 canonical material custody](../.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04D1.md) closes the three-field ART database guarantee before authority activation. diff --git a/docs/spec_artifact_storage_service.md b/docs/spec_artifact_storage_service.md index 788d32598..b4dd0639d 100644 --- a/docs/spec_artifact_storage_service.md +++ b/docs/spec_artifact_storage_service.md @@ -1622,6 +1622,10 @@ ARCH-04E separately owns TASK routing. Historical ART-06A/06B labels do not open duplicate implementation lanes. This ordering prevents a live contributor route whose mandatory checker read is unavailable. +[ART-07A1](../.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md) supplies +metadata-only packet membership types and a type-only port. It implements no +resolver, guide-binding writer or byte access. REV-03B normalized packet storage +and complete REV-04A Review storage precede shared FinalAcceptance. ART later supplies an exact, authorized reviewer-packet byte capability, while REV owns queueing, leases, decisions, and the reviewer note/findings. The approved v0.1 review flow does not upload a reviewer revision artifact. CON owns diff --git a/docs/spec_review_lifecycle.md b/docs/spec_review_lifecycle.md index 968b573cf..467c9dba9 100644 --- a/docs/spec_review_lifecycle.md +++ b/docs/spec_review_lifecycle.md @@ -22,8 +22,8 @@ and decision evidence. ReviewPolicy and RevisionPolicy use immutable, append-only identities installed by XINT-003-02A; their only writer is the guide-bound PREP mutation surface activated by XINT-003-02B. This configuration surface does not activate review queues, leases, findings, decisions, or -revision execution. XINT-002-07A activates reviewer packet materialization -only. ART review-evidence binding remains planned/unavailable and 07B is +revision execution. XINT-002-07A is planned to activate reviewer packet +materialization only; it is not live. ART review-evidence binding remains planned/unavailable and 07B is reserved pending separate REV-owned intent. ## Precedence And Archival Inputs @@ -320,7 +320,7 @@ LocalStorage is development-only. MinIO proves the S3-compatible protocol in local/CI. AWS S3 is the v0.1 hosted provider behind the provider-neutral `S3CompatibleArtifactStore`. Cloudflare R2 and Flow Node remain deferred. -REV consumes only narrow ART v2 typed product capabilities. It never imports +REV consumes only narrow ART-owned typed product capabilities. It never imports the raw byte-only `ArtifactStore`, a concrete provider, ART repositories, `ArtifactScratchManager`, `PreparedArtifact`, `CommittedArtifactSource`, object keys, provider URIs, scratch paths, receipts, or credentials. @@ -345,6 +345,21 @@ still holds the exact project reviewer grant, or an explicitly authorized Project Manager/Operator. Prior participation grants metadata history only; artifact bytes still require the current active lease for the exact packet. + +The delivered [ART-07A1 membership contract](../.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md) +provides strict detached types and a type-only async port, not a resolver. Its +scope includes exact Submission/version, aggregate CheckerRun result identity, +locked guide/snapshot and activated setup run/generation. It names one required +original ZIP binding and 1–100 ordered original guide bindings using their +separate ART owners. Both member kinds are always required. The guide binding +table exists, but its packet writer/resolver is not implemented. Shape and echoed +request validation prove neither stored ownership nor complete membership; +future canonical-owner reads must establish both within the caller transaction. +REV-03B must retain normalized members; no opaque JSON binding set. Byte access +still requires separate exact lease/packet authorization. The current catalogue +has no output files; adding those later requires an explicit owner-custody +contract, not arbitrary additional packet members. + ## Review Notes, Findings, And Revision Responses A reviewer records exactly one decision (`accept`, `needs_revision`, or @@ -556,9 +571,14 @@ Extract foundations from existing owner work, not a new initiative: REV FK. One manifest stores the locked `human_review_required` branch; it is not restricted to human admission. False proof is scalar transport only while activation remains unavailable. This schema precedes the REV source FK. -2. REV-04B shared source/FinalAcceptance persistence follows that schema, then - CON-03C contribution/award persistence and CON-07 submitter participation. - A Review FK target may require a table, not live claim or review endpoints. +2. [ART-07A1](../.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md) supplies + the metadata-only packet contract. Next implement REV-03B normalized packet + persistence, then complete REV-04A Review-source storage before REV-04B + shared FinalAcceptance storage. Do not create an incomplete Review solely as + an FK target. CON-03C contribution/award persistence and CON-07 submitter + participation follow. These storage prerequisites require no live human + claim or decision endpoint. Hidden composition proof precedes exact AUTH + activation; unavailable authority must not be replaced with fabricated allow evidence. 3. Pull the existing [REV-12A shared fence foundation](#rev-12a-shared-fence-foundation) (controller/fence persistence, mutation-fence port and CON obligation-ordinal hooks) forward before shared acceptance.