From 25d033e6e6bc462e8e53ff38db46ec2dd811d546 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Thu, 1 Oct 2026 22:07:08 +0100 Subject: [PATCH 1/6] plan: correct shared acceptance storage prerequisites --- .../initiatives/WS-ART-001/WS-ART-001-07A1.md | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 .commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md 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..10ce48816 --- /dev/null +++ b/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md @@ -0,0 +1,174 @@ +# WS-ART-001-07A1 — Exact reviewer packet membership contract + +- Initiative: `WS-ART-001` +- Durable disposition: `Planned` +- Intended merge outcome: Publish ART's bounded, metadata-only packet membership + contract and correct the source-storage prerequisites for shared acceptance. + +## Intent and current behavior + +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/result UUID (not a 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, checker_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 and evidence + +- 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 relation + 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: 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. + +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. From a05c946689cb272756b4ec45d9f1867d702752a6 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Thu, 1 Oct 2026 22:07:59 +0100 Subject: [PATCH 2/6] plan: name aggregate checker result identity explicitly --- .commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md b/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md index 10ce48816..c9a0f1f78 100644 --- a/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md +++ b/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md @@ -70,7 +70,8 @@ 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/result UUID (not a copied result digest), locked guide +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. @@ -90,7 +91,7 @@ Exact type/field inventories: | Type | Fields | |---|---| -| `ReviewPacketMembershipRequest` | project_id, task_id, submission_id, submission_version, checker_run_id, checker_result_id, guide_id, guide_version, source_snapshot_id, project_setup_run_id, setup_generation | +| `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 | @@ -146,7 +147,7 @@ or target-only Review is added here. - 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 relation + 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. From 6f26d30cb95f8a62c69abbf83b57ddba6f86fc74 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Thu, 1 Oct 2026 22:14:50 +0100 Subject: [PATCH 3/6] feat(art): define exact reviewer packet membership contract --- .ci/behavior-ownership/partition.v1.json | 6 +- .commitrail/INDEX.md | 8 +- .../initiatives/WS-ARCH-001/OVERVIEW.md | 7 +- .../WS-ARCH-001/planning/CHUNK_MAP.md | 2 +- .../initiatives/WS-ARCH-001/planning/PLAN.md | 4 +- .../WS-ARCH-001-04E-canonical-allow-review.md | 5 +- .../initiatives/WS-ART-001/OVERVIEW.md | 8 +- .../initiatives/WS-ART-001/WS-ART-001-07A1.md | 21 ++- .../initiatives/WS-AUTH-001/OVERVIEW.md | 6 +- .../WS-AUTH-001/planning/CHUNK_MAP.md | 5 + .../initiatives/WS-AUTH-001/planning/PLAN.md | 5 + .../initiatives/WS-AUTH-003/OVERVIEW.md | 4 + .../initiatives/WS-CON-001/OVERVIEW.md | 7 +- .../initiatives/WS-POL-003/OVERVIEW.md | 6 +- .../WS-POL-003/planning/CHUNK_MAP.md | 5 + .../initiatives/WS-POL-003/planning/PLAN.md | 5 + .../initiatives/WS-REV-001/OVERVIEW.md | 16 +- README.md | 6 + backend/app/modules/artifacts/api/__init__.py | 15 ++ .../modules/artifacts/api/review_packet.py | 105 +++++++++++ backend/scripts/behavior_ownership.py | 1 + backend/scripts/test_lane_catalogue.py | 1 + .../artifacts/test_review_packet_contract.py | 170 ++++++++++++++++++ backend/tests/test_behavior_ownership.py | 12 ++ backend/tests/test_ci_lane_catalogue.py | 1 + docs/architecture_data_model.md | 6 + .../authorization_activation_custody.md | 5 + docs/roadmap_status.md | 21 ++- docs/spec_artifact_storage_service.md | 4 + docs/spec_review_lifecycle.md | 32 +++- 30 files changed, 462 insertions(+), 37 deletions(-) create mode 100644 backend/app/modules/artifacts/api/review_packet.py create mode 100644 backend/tests/artifacts/test_review_packet_contract.py 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..8a84719b9 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-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; 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-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 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-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..ac23d5e4b 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, diff --git a/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md b/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md index c9a0f1f78..b54bf7d00 100644 --- a/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md +++ b/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md @@ -1,11 +1,11 @@ # WS-ART-001-07A1 — Exact reviewer packet membership contract - Initiative: `WS-ART-001` -- Durable disposition: `Planned` +- 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 and current behavior +## Intent The user approved correcting the prerequisite sequence before shared FinalAcceptance. Preserve one shared acceptance operation for human accept and @@ -142,7 +142,7 @@ 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 and evidence +## 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. @@ -158,11 +158,15 @@ or target-only Review is added here. - 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. @@ -173,3 +177,14 @@ 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. 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..67ba273bb 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. 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..97c9ae1cb --- /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) + + 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) + + 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) + + 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) + + 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..b0b4a8be8 --- /dev/null +++ b/backend/tests/artifacts/test_review_packet_contract.py @@ -0,0 +1,170 @@ +"""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() + with pytest.raises(ValidationError, match="source order"): + ReviewPacketMembership.model_validate({**raw, "guide_documents": list(reversed(raw["guide_documents"]))}) + for count in (1, 100): + assert len(ReviewPacketMembership.model_validate({**raw, "guide_documents": [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": [guide(i) for i in range(count)]}) 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..0580aec78 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 @@ -578,10 +581,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 +707,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. From 15fcabf8a5b304996308e1e8fcf742b3235e9cb6 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Thu, 1 Oct 2026 22:23:45 +0100 Subject: [PATCH 4/6] fix(art): enforce native UUID inputs and align prerequisite navigation --- .commitrail/INDEX.md | 6 ++-- .../initiatives/WS-ART-001/OVERVIEW.md | 7 +++-- .../initiatives/WS-ART-001/WS-ART-001-07A1.md | 5 ++++ .../modules/artifacts/api/review_packet.py | 8 ++--- .../artifacts/test_review_packet_contract.py | 30 ++++++++++++++++--- docs/roadmap_status.md | 5 ++-- 6 files changed, 46 insertions(+), 15 deletions(-) diff --git a/.commitrail/INDEX.md b/.commitrail/INDEX.md index 8a84719b9..e2aebd63a 100644 --- a/.commitrail/INDEX.md +++ b/.commitrail/INDEX.md @@ -10,10 +10,10 @@ for current product capability. | [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 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; shared acceptance foundations and hidden 04E1B proof precede exact 04E2 activation and 04E3 live composition | +| [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 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-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 | diff --git a/.commitrail/initiatives/WS-ART-001/OVERVIEW.md b/.commitrail/initiatives/WS-ART-001/OVERVIEW.md index ac23d5e4b..29b8a9408 100644 --- a/.commitrail/initiatives/WS-ART-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-ART-001/OVERVIEW.md @@ -47,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 index b54bf7d00..d1316bced 100644 --- a/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md +++ b/.commitrail/initiatives/WS-ART-001/WS-ART-001-07A1.md @@ -188,3 +188,8 @@ 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/backend/app/modules/artifacts/api/review_packet.py b/backend/app/modules/artifacts/api/review_packet.py index 97c9ae1cb..f3dca2d89 100644 --- a/backend/app/modules/artifacts/api/review_packet.py +++ b/backend/app/modules/artifacts/api/review_packet.py @@ -20,7 +20,7 @@ def __init__(self) -> None: class ReviewPacketMembershipRequest(BaseModel): """Locked scope; result_id names CheckerRun.result_id, not CheckerResult.id.""" - model_config = ConfigDict(extra="forbid", frozen=True) + model_config = ConfigDict(extra="forbid", frozen=True, strict=True) project_id: UUID task_id: UUID @@ -45,7 +45,7 @@ def nonblank_guide_version(cls, value: str) -> str: class ReviewSubmissionMember(BaseModel): """Required original ZIP; binding_id identifies ART's artifact_bindings row.""" - model_config = ConfigDict(extra="forbid", frozen=True) + model_config = ConfigDict(extra="forbid", frozen=True, strict=True) binding_id: UUID logical_role: Literal["submission_bundle_original"] @@ -55,7 +55,7 @@ class ReviewSubmissionMember(BaseModel): class ReviewGuideMember(BaseModel): """Required original document from ART's guide_source_artifact_bindings.""" - model_config = ConfigDict(extra="forbid", frozen=True) + model_config = ConfigDict(extra="forbid", frozen=True, strict=True) guide_binding_id: UUID source_item_id: UUID @@ -67,7 +67,7 @@ class ReviewGuideMember(BaseModel): class ReviewPacketMembership(BaseModel): """Complete metadata shape; stored ownership/completeness need owner resolution.""" - model_config = ConfigDict(extra="forbid", frozen=True) + model_config = ConfigDict(extra="forbid", frozen=True, strict=True) request: ReviewPacketMembershipRequest submission: ReviewSubmissionMember diff --git a/backend/tests/artifacts/test_review_packet_contract.py b/backend/tests/artifacts/test_review_packet_contract.py index b0b4a8be8..ae1a78852 100644 --- a/backend/tests/artifacts/test_review_packet_contract.py +++ b/backend/tests/artifacts/test_review_packet_contract.py @@ -30,7 +30,7 @@ def packet() -> dict: "binding_id": UUID(int=9), "logical_role": "submission_bundle_original", "media_type": "application/zip", }, - "guide_documents": [guide(0), guide(2)], + "guide_documents": (guide(0), guide(2)), } @@ -162,9 +162,31 @@ def test_independent_duplicate_membership_rejected(attribute: str) -> None: def test_canonical_order_and_document_count_bounds() -> None: raw = packet() with pytest.raises(ValidationError, match="source order"): - ReviewPacketMembership.model_validate({**raw, "guide_documents": list(reversed(raw["guide_documents"]))}) + ReviewPacketMembership.model_validate({**raw, "guide_documents": tuple(reversed(raw["guide_documents"]))}) for count in (1, 100): - assert len(ReviewPacketMembership.model_validate({**raw, "guide_documents": [guide(i) for i in range(count)]}).guide_documents) == count + 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": [guide(i) for i in range(count)]}) + 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/docs/roadmap_status.md b/docs/roadmap_status.md index 0580aec78..d56cf7278 100644 --- a/docs/roadmap_status.md +++ b/docs/roadmap_status.md @@ -494,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 From e3b00d050d2e6b76d102623af4fba59869acaf51 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Thu, 1 Oct 2026 22:26:20 +0100 Subject: [PATCH 5/6] test(art): prove strict packet container boundary --- backend/tests/artifacts/test_review_packet_contract.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/tests/artifacts/test_review_packet_contract.py b/backend/tests/artifacts/test_review_packet_contract.py index ae1a78852..605e64231 100644 --- a/backend/tests/artifacts/test_review_packet_contract.py +++ b/backend/tests/artifacts/test_review_packet_contract.py @@ -161,6 +161,12 @@ def test_independent_duplicate_membership_rejected(attribute: str) -> None: 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): From d82eb9f8327a7155716c0b7816e8a68dc16dc26b Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Thu, 1 Oct 2026 22:35:57 +0100 Subject: [PATCH 6/6] docs: clarify AUTH boundary storage prerequisites --- .commitrail/initiatives/WS-AUTH-003/OVERVIEW.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md b/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md index 67ba273bb..93413aa8a 100644 --- a/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md +++ b/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md @@ -18,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.