From 9b6ee2ab2928493453e794f1213b1c0123acc733 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 11:41:16 +0100 Subject: [PATCH 1/9] Bind admitted Submission text to its checked packet --- .commitrail/INDEX.md | 2 +- .../initiatives/WS-ARCH-001/OVERVIEW.md | 2 + .../WS-ARCH-001/WS-ARCH-001-04E1BB4.md | 94 ++++++++++++ .../WS-ARCH-001/planning/CHUNK_MAP.md | 2 + .../initiatives/WS-ARCH-001/planning/PLAN.md | 2 + .../WS-ARCH-001-04E-canonical-allow-review.md | 10 ++ README.md | 4 +- backend/alembic/env.py | 2 +- .../0022_submission_packet_custody.py | 58 +++++++ backend/app/adapters/tasks/__init__.py | 1 + .../artifacts/api/submission_admission.py | 3 + .../modules/artifacts/pre_submit_attempts.py | 2 +- .../modules/artifacts/submission_bindings.py | 2 + .../app/modules/checkers/api/pre_submit.py | 10 ++ .../modules/tasks/api/submission_command.py | 1 + .../modules/tasks/submission_composition.py | 4 + backend/tests/conftest.py | 2 +- backend/tests/submission_fixtures.py | 2 + .../tests/tasks/test_submission_lineage.py | 145 ++++++++++++++++-- backend/tests/test_alembic.py | 2 +- backend/tests/test_artifact_bindings.py | 28 ++++ backend/tests/test_artifact_bindings_db.py | 9 +- backend/tests/test_submission_composition.py | 2 + docs/roadmap_status.md | 13 +- docs/spec_artifact_storage_service.md | 6 +- docs/spec_chunk_4_task_queue_assignment.md | 8 + 26 files changed, 390 insertions(+), 26 deletions(-) create mode 100644 .commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md create mode 100644 backend/alembic/versions/0022_submission_packet_custody.py diff --git a/.commitrail/INDEX.md b/.commitrail/INDEX.md index 0a5281e51..29880e124 100644 --- a/.commitrail/INDEX.md +++ b/.commitrail/INDEX.md @@ -9,7 +9,7 @@ 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 | Nine tools through WS-MCP-002-03: self-service and administrative reads; 18 tools remain and WS-MCP-002-04 administrative grant mutations are next | | [WS-CLI-001](initiatives/WS-CLI-001/OVERVIEW.md) | Planned | Public Go CLI self-service, project inspection, manager browsing, contributor discovery and claim/start delivered through WS-CLI-001-06; further public journeys and binary distribution remain | -| [WS-ARCH-001](initiatives/WS-ARCH-001/OVERVIEW.md) | Planned | Source storage, inert AUTH contracts, TASK request reservation, hidden exact AUTH preparation and the REV-04C hidden FinalAcceptance/TASK/CON participant are delivered; TASK-before-CHECKERS reservation/current-read custody and ordered admission INSERTs are delivered by 04E1B-B1; 04E1B-B2 adds exact source preparation without publication; 04E1B-B3 retains inspected ZIP metadata for consumption; initial Submission/dispatch composition is next, followed by remaining hidden routing handlers. True admission remains independent of shared acceptance; false activation still requires exact AUTH receipt custody, database complete-set enforcement, currentness race proof and atomic routing activation. | +| [WS-ARCH-001](initiatives/WS-ARCH-001/OVERVIEW.md) | Planned | Source storage, inert AUTH contracts, TASK request reservation, hidden exact AUTH preparation and the REV-04C hidden FinalAcceptance/TASK/CON participant are delivered; TASK-before-CHECKERS reservation/current-read custody and ordered admission INSERTs are delivered by 04E1B-B1; 04E1B-B2 adds exact source preparation without publication; 04E1B-B3 retains inspected ZIP metadata and B4 binds Submission text to checked packet custody; initial Submission/dispatch composition is next, followed by remaining hidden routing handlers. True admission remains independent of shared acceptance; false activation still requires exact AUTH receipt custody, database complete-set enforcement, currentness race proof and atomic routing activation. | | [WS-ART-001](initiatives/WS-ART-001/OVERVIEW.md) | Planned | Exact checker input/output custody and packet foundations are delivered; routing integration, remediation and public intake remain. | | [WS-AUTH-001](initiatives/WS-AUTH-001/OVERVIEW.md) | Planned | AUTH-19A commitments, TASK request reservation, ARCH-04E2-A hidden strict PREP matching and the REV-04C hidden FinalAcceptance/TASK/CON participant are delivered; the action remains unavailable, with mandatory exact AUTH receipt input, database closure, audit/outbox and scoped activation still required for the automated path. | | [WS-CON-001](initiatives/WS-CON-001/OVERVIEW.md) | Planned | Contribution/award storage, CON-07 participation and REV-04C hidden FinalAcceptance/TASK/CON composition are delivered; production consumption still requires genuine authority, database complete-set enforcement, currentness race proof, shared audit/outbox, fulfillment-root ordinals and lifecycle activation. | diff --git a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md index 49e79c6b0..dfd35aa25 100644 --- a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md @@ -1,5 +1,7 @@ # WS-ARCH-001 — Modular monolith boundaries +[ARCH-04E1B-B4](WS-ARCH-001-04E1BB4.md) binds Submission summary and attestation to the packet retained by intake, including database custody. Initial dispatch remains next and must reconcile capacity, exact receipts and fresh-authorized replay before connecting workers. + [ARCH-04E1B-B3](WS-ARCH-001-04E1BB3.md) retains the inspected ZIP manifest in immutable ART evidence and returns verified file metadata on admission consumption. Initial Submission/dispatch composition is next; it must reconcile existing ART/CHECKERS size limits and retain exact creation/binding receipts. No dispatch or routing authority is activated. [ARCH-04E1B-B2](WS-ARCH-001-04E1BB2.md) supplies exact source preparation through diff --git a/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md b/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md new file mode 100644 index 000000000..751aa5e87 --- /dev/null +++ b/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md @@ -0,0 +1,94 @@ +# ARCH-04E1B-B4 — Bind Submission text to its checked packet + +- Initiative: `WS-ARCH-001` +- Durable disposition: `Complete` +- Intended merge outcome: admission consumption and persisted Submission text must match the exact packet retained by pre-submission checking. + +## Intent and discovery + +Initial dispatch must use exactly the input that passed preparation. Plan review +found that TASK forwards no packet commitment to ART consumption: prepared summary +and attestation A can be replaced with B when creating a Submission. The existing +pre-submit evidence already stores their canonical packet hash. Enforce that +existing commitment before building dispatch on this boundary. + +## Bounded design + +- Forward the canonical hash of the actual creation request's summary and + contributor attestation through existing TASK and ART consumption requests. + Share the existing packet hash construction; no second packet format. +- ART compares it with locked immutable pre-submit evidence before consumed + replay or new binding/consumption. Mismatch gives the existing concealed + unavailable error and no mutation or final binding authorization. +- A deferred PostgreSQL guard reads the final Submission row and compares its + summary/worker_attestation with its admission's retained evidence packet hash. + Support existing insert-unbound then bind in the same transaction. Once bound, + retain the existing guard against clearing or replacing the admission/binding/content triple. Reuse the + existing canonical SQL JSON function and qualify every protected reference with + a pinned safe search_path. Existing upstream hash/link immutability remains. +- Preserve retained data unchanged at upgrade. Unbound stored rows gain no + admission or dispatch eligibility. Newly bound/changed rows must satisfy the + guard; no optional current path, fabricated hash, compatibility API or backfill. + +## Allowed files + +TASK submission command contract/composition and adapters/tasks; ART consumption +contract/service, packet hashing caller and directly affected exports; CHECKERS public packet value helper; one migration after 0021, test_alembic and schema +fingerprint; focused binding/composition and real PostgreSQL submission tests plus +their affected canonical fixtures; exact lane/ownership registration; this record, +parent 04E contract and affected ARCH/AUTH/POL current navigation, README, +TASK/ART specifications and roadmap. + +## Prohibited changes + +No dispatch reservation/event/handler, capacity-limit changes, new receipt store, +AUTH replay activation, routing/acceptance/review effects, public route, claim +expiry, provider read, retained data rewrite/delete, compatibility path, weakened +CI or skipped tests. Preserve unrelated CLI work. + +## Acceptance and proof + +1. Exact prepared packet creates a Submission through real hidden TASK/ART/AUTH. + Changing only summary or only attestation rejects and rolls back Submission, + admission consumption, binding and staged AUTH evidence. No provider reread. +2. Exact ART consumption replay remains valid; a changed packet digest on a + consumed admission rejects before binding authorization or mutation. +3. PostgreSQL permits valid insert-unbound/update-bind in one transaction; rejects + changed packet fields, wrong packet on first binding and clearing/substituting + bound lineage. Verify persisted state after rollback. Existing upstream + evidence-hash/admission-link immutability tests remain valid. +4. Upgrade preserves existing rows unchanged. Canonical hash parity includes + quotes, backslashes and supported packet text. Tests target each independent + field; remove the service/SQL predicate and prove the intended assertions fail. +5. Run focused pure/PostgreSQL tests, Ruff, boundaries, lane/ownership inventory, + stale wording/link/Commitrail checks and full hosted completeness. Coverage is + diagnostic. Tests protect outcomes; no mirrored implementation-only cases. + +## Risk and reviewers + +L1. Architecture/security/reuse and QA/test-delta plan review before code. +Implementation reviews additionally include CI-integrity and docs/product ops. +Human focus: exact pre-check-to-Submission input custody, rejection before effects, +immutable bound lineage, caller rollback, retained-data preservation. + +## Next dependency + +Initial Submission/dispatch remains next after capacity and replay reconciliation. +Discovery established three explicit obligations for that transaction: retain +exact creation/binding AUTH receipts; validate the same bounded checker request +before ready admission and at dispatch; resolve same-admission replay under fresh +AUTH after TASK reaches evaluation_pending without replacing original identities. +The current creation-context validator intentionally permits only in_progress or +needs_revision, so broadening it is not a replay design. Both true review admission +and false shared acceptance remain in the parent plan. Worker activation, +remediation and public intake follow; contributor claim expiry remains deferred. + +## Plan review outcome + +Architecture/security and QA found the original atomic dispatch proposal too early: +packet substitution is currently possible, creation replay rejects post-creation +TASK state, and ready ZIP capacities exceed CHECKERS inputs. This chunk repairs +only the first concrete boundary. Both plan reviews found it feasible. Reuse +`protect_submission_contribution_stamp` for once-bound identity and existing ART +immutable evidence/admission guards; do not duplicate them. The real test keeps +preparation artifacts/evidence intact while proving creation-side rollback. diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md b/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md index d32e9632b..38645dbe3 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md @@ -1,5 +1,7 @@ # WS-ARCH-001 — Current remaining change map +[ARCH-04E1B-B4](../WS-ARCH-001-04E1BB4.md) binds Submission summary and attestation to the packet retained by intake, including database custody. Initial dispatch remains next and must reconcile capacity, exact receipts and fresh-authorized replay before connecting workers. + [ARCH-04E1B-B3](../WS-ARCH-001-04E1BB3.md) retains the inspected ZIP manifest in immutable ART evidence and returns verified file metadata on admission consumption. Initial Submission/dispatch composition is next; it must reconcile existing ART/CHECKERS size limits and retain exact creation/binding receipts. No dispatch or routing authority is activated. [ARCH-04E1B-B2](../WS-ARCH-001-04E1BB2.md) supplies exact source preparation through TASK, CHECKERS and historical PROJECTS policy facts. It stages only the existing diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md index ea13830f9..d89c80e3b 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md @@ -1,5 +1,7 @@ # WS-ARCH-001 — Current delivery plan through allow_review +[ARCH-04E1B-B4](../WS-ARCH-001-04E1BB4.md) binds Submission summary and attestation to the packet retained by intake, including database custody. Initial dispatch remains next and must reconcile capacity, exact receipts and fresh-authorized replay before connecting workers. + [ARCH-04E1B-B3](../WS-ARCH-001-04E1BB3.md) retains the inspected ZIP manifest in immutable ART evidence and returns verified file metadata on admission consumption. Initial Submission/dispatch composition is next; it must reconcile existing ART/CHECKERS size limits and retain exact creation/binding receipts. No dispatch or routing authority is activated. [ARCH-04E1B-B2](../WS-ARCH-001-04E1BB2.md) supplies exact source preparation through TASK, CHECKERS and historical PROJECTS policy facts. It stages only the existing 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 5002a65b7..37c5fdb47 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 @@ -314,3 +314,13 @@ composition phases above; only false handlers add shared acceptance. ## Merge state - Outcome on merge: `planned` + +### Checked packet prerequisite + +[ARCH-04E1B-B4](../../WS-ARCH-001-04E1BB4.md) binds Submission text to the +canonical packet retained by preparation, through ART consumption and a deferred +storage guard. Initial dispatch must next reconcile capacity before ready +admission, retain exact creation/binding receipts and define fresh-authorized +same-admission replay after creation. Do not broaden the initial/revision context +validator to treat evaluation_pending as a new submission window. No dispatch +handler, routing authority or public intake is delivered by this correction. diff --git a/README.md b/README.md index ee9436c7f..13a91e511 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,9 @@ ARCH-04E1B-B1 requires TASK locking before checker reservation, current-result reads and review admission INSERTs, preserving exact read-only reservation replay after acceptance. ARCH-04E1B-B3 retains the inspected ZIP file metadata with immutable ART evidence and returns it on consumption without another storage read. Initial -Submission/dispatch composition remains pending. ARCH-04E1B-B2 prepares exact source proposals from current +Submission/dispatch composition remains pending. ARCH-04E1B-B4 binds the +Submission summary and attestation to the packet that passed intake, with +service and database enforcement. ARCH-04E1B-B2 prepares exact source proposals from current CHECKERS custody and historical PROJECTS policy, without inserting a manifest or granting authority. Hidden handlers still need complete authorized currentness proof. These prerequisites do not require live diff --git a/backend/alembic/env.py b/backend/alembic/env.py index 564cf7244..b0ce2140f 100644 --- a/backend/alembic/env.py +++ b/backend/alembic/env.py @@ -21,7 +21,7 @@ target_metadata = Base.metadata _BASELINE_REVISION = "0001_uuid7_v01" -_CURRENT_HEAD_REVISION = "0021_submission_manifest" +_CURRENT_HEAD_REVISION = "0022_submission_packet_custody" _RECREATE_GUIDANCE = ( "Workstream v0.1 requires a fresh database; recreate this database before " "running the 0001_uuid7_v01 migration" diff --git a/backend/alembic/versions/0022_submission_packet_custody.py b/backend/alembic/versions/0022_submission_packet_custody.py new file mode 100644 index 000000000..5b1b5b1c9 --- /dev/null +++ b/backend/alembic/versions/0022_submission_packet_custody.py @@ -0,0 +1,58 @@ +"""Bind each admitted Submission to the contributor packet that passed intake.""" + +from alembic import op + +revision = "0022_submission_packet_custody" +down_revision = "0021_submission_manifest" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # Read the final row: TASK inserts first, then binds ART in the same transaction. + # Existing owner triggers already freeze bound identities and upstream evidence. + op.execute(""" +CREATE FUNCTION public.validate_submission_packet_custody() RETURNS trigger +LANGUAGE plpgsql SET search_path = pg_catalog, public, pg_temp AS $$ +DECLARE + stored public.submissions%ROWTYPE; + expected_packet text; + actual_packet text; +BEGIN + IF TG_OP = 'UPDATE' AND + ROW(NEW.summary, NEW.worker_attestation, NEW.submission_bundle_admission_id, + NEW.artifact_binding_id, NEW.artifact_content_id) IS NOT DISTINCT FROM + ROW(OLD.summary, OLD.worker_attestation, OLD.submission_bundle_admission_id, + OLD.artifact_binding_id, OLD.artifact_content_id) THEN + RETURN NULL; + END IF; + SELECT * INTO stored FROM public.submissions WHERE id = NEW.id; + IF NOT FOUND OR stored.submission_bundle_admission_id IS NULL THEN + RETURN NULL; + END IF; + SELECT evidence.packet_sha256 INTO expected_packet + FROM public.submission_bundle_admissions AS admission + JOIN public.pre_submit_evidence_sets AS evidence + ON evidence.id = admission.pre_submit_evidence_set_id + WHERE admission.id = stored.submission_bundle_admission_id; + actual_packet := 'sha256:' || pg_catalog.encode(pg_catalog.sha256(pg_catalog.convert_to( + public.project_guide_projection_canonical_json(pg_catalog.jsonb_build_object( + 'summary', stored.summary, 'contributor_attestation', stored.worker_attestation + )), 'UTF8')), 'hex'); + IF expected_packet IS NULL OR actual_packet IS DISTINCT FROM expected_packet THEN + RAISE EXCEPTION 'submission packet differs from checked evidence' USING ERRCODE='23514'; + END IF; + RETURN NULL; +END; +$$; +""") + op.execute(""" +CREATE CONSTRAINT TRIGGER submission_packet_custody +AFTER INSERT OR UPDATE ON public.submissions +DEFERRABLE INITIALLY DEFERRED FOR EACH ROW +EXECUTE FUNCTION public.validate_submission_packet_custody(); +""") + + +def downgrade() -> None: + raise RuntimeError("Workstream v0.1 migrations cannot be downgraded; recreate the database") diff --git a/backend/app/adapters/tasks/__init__.py b/backend/app/adapters/tasks/__init__.py index 34f0b2706..da789ae3b 100644 --- a/backend/app/adapters/tasks/__init__.py +++ b/backend/app/adapters/tasks/__init__.py @@ -136,6 +136,7 @@ async def consume( submission_id=request.submission_id, submission_version=request.submission_version, task_context=request.task_context, + packet_sha256=request.packet_sha256, ) ) if result.binding_id is None or result.status != "consumed": diff --git a/backend/app/modules/artifacts/api/submission_admission.py b/backend/app/modules/artifacts/api/submission_admission.py index c66bc66aa..60dbf64be 100644 --- a/backend/app/modules/artifacts/api/submission_admission.py +++ b/backend/app/modules/artifacts/api/submission_admission.py @@ -36,10 +36,13 @@ class SubmissionAdmissionConsumptionRequest: submission_id: UUID submission_version: int task_context: TaskSubmissionContextFacts + packet_sha256: str def __post_init__(self) -> None: if type(self.submission_version) is not int or self.submission_version < 1: raise ValueError("submission version is invalid") + if type(self.packet_sha256) is not str or not re.fullmatch(r"sha256:[0-9a-f]{64}", self.packet_sha256): + raise ValueError("submission packet digest is invalid") @dataclass(frozen=True, slots=True) diff --git a/backend/app/modules/artifacts/pre_submit_attempts.py b/backend/app/modules/artifacts/pre_submit_attempts.py index 291098408..ccb673c75 100644 --- a/backend/app/modules/artifacts/pre_submit_attempts.py +++ b/backend/app/modules/artifacts/pre_submit_attempts.py @@ -59,7 +59,7 @@ def logical_request( return { **values, "effective_plan_sha256": plan.plan_sha256, - "packet_sha256": canonical_json_hash(asdict(packet)), + "packet_sha256": packet.sha256, } diff --git a/backend/app/modules/artifacts/submission_bindings.py b/backend/app/modules/artifacts/submission_bindings.py index aebdc15e4..4d92c5016 100644 --- a/backend/app/modules/artifacts/submission_bindings.py +++ b/backend/app/modules/artifacts/submission_bindings.py @@ -160,6 +160,8 @@ async def consume( ) except (TypeError, ValueError) as exc: raise SubmissionAdmissionConsumptionError("submission_bundle_admission_unavailable") from exc + if evidence.packet_sha256 != request.packet_sha256: + raise SubmissionAdmissionConsumptionError("submission_bundle_admission_unavailable") if admission.status == "consumed": return await self._consumed_replay(admission, evidence, request) if not self._task_lineage_matches(admission, evidence, request): diff --git a/backend/app/modules/checkers/api/pre_submit.py b/backend/app/modules/checkers/api/pre_submit.py index 0ecf05c66..07a9aa39a 100644 --- a/backend/app/modules/checkers/api/pre_submit.py +++ b/backend/app/modules/checkers/api/pre_submit.py @@ -202,6 +202,16 @@ def __post_init__(self) -> None: if type(value) is not str or len(value.encode("utf-8")) > 64 * 1024: raise ValueError("submission packet text is invalid") + @property + def sha256(self) -> str: + """Commit to the same exact text at preparation and Submission creation.""" + from app.core.hashing import canonical_json_hash + + return canonical_json_hash({ + "summary": self.summary, + "contributor_attestation": self.contributor_attestation, + }) + @dataclass(frozen=True, slots=True) class PreSubmissionExecutionEntryFacts: diff --git a/backend/app/modules/tasks/api/submission_command.py b/backend/app/modules/tasks/api/submission_command.py index e11511213..f69a2ccd7 100644 --- a/backend/app/modules/tasks/api/submission_command.py +++ b/backend/app/modules/tasks/api/submission_command.py @@ -92,6 +92,7 @@ class SubmissionArtifactAdmissionRequest: submission_id: UUID submission_version: int task_context: TaskSubmissionContextFacts + packet_sha256: str @dataclass(frozen=True, slots=True) diff --git a/backend/app/modules/tasks/submission_composition.py b/backend/app/modules/tasks/submission_composition.py index 090864843..1234065de 100644 --- a/backend/app/modules/tasks/submission_composition.py +++ b/backend/app/modules/tasks/submission_composition.py @@ -20,6 +20,7 @@ SubmissionCreationResult, TaskSubmissionContextRequest, ) +from app.modules.checkers.api import SubmissionPacketView from app.modules.tasks.models import EvidenceItem, Submission from app.modules.tasks.repository import TaskRepository from app.modules.tasks.service import TaskService @@ -153,6 +154,9 @@ async def create(self, request: SubmissionCreationRequest) -> SubmissionCreation submission_id=submission_id, submission_version=version, task_context=context, + packet_sha256=SubmissionPacketView( + request.summary, request.contributor_attestation, + ).sha256, ) ) if ( diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index 01be1e3cb..811d6bc44 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -23,7 +23,7 @@ DDL_LOCK_DIRECTORY = Path("/tmp") # Match the PostgreSQL 16 engine used by Backend CI. Catalog identity rendering # differs across major versions; regenerate only after comparing actual objects. -EXPECTED_PUBLIC_SCHEMA_SHA256 = "6136687c178fbec0b8f6161f8954ba9f57e3e1392cdebd80c7d527bb329bd85b" +EXPECTED_PUBLIC_SCHEMA_SHA256 = "4ee1263792feddd89c1af69b97052d67e8b08a5b4bf3a0e9c8ed5711ef0b70f4" PROTECTED_TEST_TABLES = ( "joint_lifecycle_release_control", "actor_profile_migration_state", diff --git a/backend/tests/submission_fixtures.py b/backend/tests/submission_fixtures.py index 780448fe1..1ca623b08 100644 --- a/backend/tests/submission_fixtures.py +++ b/backend/tests/submission_fixtures.py @@ -9,6 +9,7 @@ from tests.retained_material_fixtures import retained_admission, RetainedBindingAuthority from app.modules.artifacts.submission_bindings import SubmissionAdmissionConsumptionService from app.modules.artifacts.api import SubmissionAdmissionConsumptionRequest +from app.modules.checkers.api import SubmissionPacketView from app.modules.tasks.api import TaskSubmissionContextRequest from app.modules.tasks.repository import TaskRepository from app.core.config import get_settings @@ -83,6 +84,7 @@ async def seed_retained_submission( session, RetainedBindingAuthority(), ).consume(SubmissionAdmissionConsumptionRequest( UUID(admission_id), UUID(submission_id), submission.version, context, + SubmissionPacketView(packet.summary, packet.worker_attestation).sha256, )) assert consumed.status == "consumed" submission.submission_bundle_admission_id = admission_id diff --git a/backend/tests/tasks/test_submission_lineage.py b/backend/tests/tasks/test_submission_lineage.py index 1a4242fa8..ee7c3121b 100644 --- a/backend/tests/tasks/test_submission_lineage.py +++ b/backend/tests/tasks/test_submission_lineage.py @@ -2,10 +2,13 @@ import asyncio from dataclasses import replace +from contextlib import asynccontextmanager +from types import SimpleNamespace from app.core.identifiers import new_record_id import pytest -from sqlalchemy import select, func +from sqlalchemy import select, func, event, text +from sqlalchemy.exc import DBAPIError, IntegrityError from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from app.api.deps.authorization import compose_hidden_submission_creation_command @@ -19,7 +22,7 @@ ) from app.modules.authorization.api import ActorIdentityFacts, ActorKind from app.modules.tasks.api import SubmissionCreationRequest, TaskSubmissionContextUnavailable -from app.modules.tasks.models import Submission, TaskAssignment, WorkstreamTask +from app.modules.tasks.models import AuditEvent, Submission, TaskAssignment, WorkstreamTask from tests.pre_submit_test_helpers import approved_pre_submit_fixture from tests.submission_preparation_auth_helpers import install_submitter_grant from tests.tasks.lineage_fixtures import seed_started_task_for_artifact_test @@ -36,10 +39,8 @@ from tests.tasks.submission_lineage_support import _seed_services, _verified_admission -async def test_real_zip_admission_and_hidden_creation_copy_exact_assignment( - isolated_database_env, - tmp_path, -): +@asynccontextmanager +async def _prepared_packet(isolated_database_env, tmp_path): engine = create_async_engine(isolated_database_env) factory = async_sessionmaker(engine, expire_on_commit=False) settings = _settings(tmp_path, maximum_bytes=1024 * 1024) @@ -71,7 +72,7 @@ async def test_real_zip_admission_and_hidden_creation_copy_exact_assignment( assignment_id=assignment_id, predecessor_submission_id=None, idempotency_key=new_record_id(), - summary="Completed the required project work and included evidence.", + summary='Completed the "required" project work in folder \\results with evidence.', contributor_attestation="I confirm no confidential client data, credentials, or copied source material is included in this submission; rights_confirmed. " + " ".join(policy["attestation_terms"]), media_type="application/zip", @@ -89,6 +90,22 @@ async def test_real_zip_admission_and_hidden_creation_copy_exact_assignment( summary=request.summary, contributor_attestation=request.contributor_attestation, ) + yield SimpleNamespace( + factory=factory, context=context, task_id=task_id, assignment_id=assignment_id, + admission_id=admission_id, creation=creation, + ) + finally: + bootstrap.close() + await engine.dispose() + + +async def test_real_zip_admission_and_hidden_creation_copy_exact_assignment( + isolated_database_env, tmp_path, +): + async with _prepared_packet(isolated_database_env, tmp_path) as h: + factory, context = h.factory, h.context + task_id, assignment_id = h.task_id, h.assignment_id + admission_id, creation = h.admission_id, h.creation # ART rejection occurs after TASK insertion; the command must roll the # entire root transaction back without stranding a staged Submission. async with factory() as session: @@ -104,6 +121,47 @@ async def test_real_zip_admission_and_hidden_creation_copy_exact_assignment( admission = await session.get(SubmissionBundleAdmission, str(admission_id)) assert admission.status == "ready" + async def assert_unconsumed(): + async with factory() as check: + assert await check.scalar(select(func.count()).select_from(Submission)) == 0 + assert await check.scalar(select(func.count()).select_from(ArtifactBinding).where( + ArtifactBinding.resource_type == "submission", + )) == 0 + assert await check.scalar(select(func.count()).select_from(AuditEvent).where( + AuditEvent.action_id.in_(["submission.create", "artifact.submission.binding.create"]), + )) == 0 + assert (await check.get(SubmissionBundleAdmission, str(admission_id))).status == "ready" + assert (await check.get(WorkstreamTask, str(task_id))).status == "in_progress" + + # Each field is independently bound to the packet that actually passed. + for field in ("summary", "contributor_attestation"): + async with factory() as session: + with pytest.raises(SubmissionAdmissionConsumptionError, match="submission_bundle_admission_unavailable"): + await compose_hidden_submission_creation_command( + session, context, request_id=new_record_id(), correlation_id=new_record_id(), + ).create(replace(creation, **{field: getattr(creation, field) + " Changed."})) + await assert_unconsumed() + + # Stage valid creation, then change only stored text using SQL before the + # root commit. This reaches the deferred packet guard, not the ART check. + for column in ("summary", "worker_attestation"): + async with factory() as session: + def substitute_packet(sync_session): + sync_session.connection().execute(text( + f"UPDATE public.submissions SET {column} = {column} || ' Changed.' " + "WHERE submission_bundle_admission_id = :admission" + ), {"admission": admission_id}) + + event.listen(session.sync_session, "before_commit", substitute_packet) + try: + with pytest.raises(IntegrityError, match="submission packet differs from checked evidence"): + await compose_hidden_submission_creation_command( + session, context, request_id=new_record_id(), correlation_id=new_record_id(), + ).create(creation) + finally: + event.remove(session.sync_session, "before_commit", substitute_packet) + await assert_unconsumed() + async def create(): async with factory() as session: return await compose_hidden_submission_creation_command( @@ -144,6 +202,73 @@ async def create(): assert admission.consumed_by_submission_id == submission.id assert submission.locked_payment_policy_version is None assert await session.scalar(select(func.count()).select_from(Submission)) == 1 - finally: - bootstrap.close() - await engine.dispose() + # Existing owner immutability is part of the new cross-row guarantee. + for update in ( + "submission_bundle_admission_id=NULL, artifact_binding_id=NULL, artifact_content_id=NULL", + "submission_bundle_admission_id=:foreign", + "artifact_binding_id=:foreign", + "artifact_content_id=:foreign", + ): + with pytest.raises(DBAPIError, match="submission contribution identity is immutable"): + async with factory.begin() as session: + await session.execute(text(f"UPDATE public.submissions SET {update} WHERE id=:id"), + {"id": created.submission_id, "foreign": new_record_id()}) + for statement, message in ( + ("UPDATE public.pre_submit_evidence_sets SET packet_sha256='sha256:' || repeat('0',64) " + "WHERE id=(SELECT pre_submit_evidence_set_id FROM public.submission_bundle_admissions WHERE id=:id)", + "pre_submit_evidence_sets rows are immutable"), + ("UPDATE public.submission_bundle_admissions SET pre_submit_evidence_set_id=:foreign WHERE id=:id", + "submission bundle admission lineage is immutable"), + ): + with pytest.raises(DBAPIError, match=message): + async with factory.begin() as session: + await session.execute(text(statement), {"id": admission_id, "foreign": new_record_id()}) + async with factory() as session: + retained = await session.get(Submission, str(created.submission_id)) + assert retained.summary == creation.summary + assert retained.worker_attestation == creation.contributor_attestation + assert retained.submission_bundle_admission_id == str(admission_id) + assert retained.artifact_binding_id == str(created.artifact_binding_id) + assert retained.artifact_content_id == str(created.artifact_content_id) + + +@pytest.mark.postgres_schema_contract +async def test_packet_custody_upgrade_preserves_retained_submission( + isolated_database_env, tmp_path, migration_lock, +): + import asyncpg + from alembic import command + from app.db import session as db_session + from tests.migration_fixtures import _config + + with migration_lock(): + await db_session.dispose_engine() + connection = await asyncpg.connect(isolated_database_env.replace("+asyncpg", "")) + try: + await connection.execute("drop schema public cascade; create schema public") + finally: + await connection.close() + await asyncio.to_thread(command.upgrade, _config(), "0021_submission_manifest") + async with _prepared_packet(isolated_database_env, tmp_path) as h: + async with h.factory() as session: + created = await compose_hidden_submission_creation_command( + session, h.context, request_id=new_record_id(), correlation_id=new_record_id(), + ).create(h.creation) + # The predecessor allowed this mismatch. Upgrade must neither invent + # evidence nor rewrite/delete retained text, even when inconsistent. + async with h.factory.begin() as session: + await session.execute(text( + "UPDATE public.submissions SET summary = summary || ' Historical.' WHERE id=:id" + ), {"id": created.submission_id}) + before = await session.scalar(text( + "SELECT to_jsonb(s) FROM public.submissions s WHERE id=:id" + ), {"id": created.submission_id}) + await asyncio.to_thread(command.upgrade, _config(), "head") + async with h.factory() as session: + after = await session.scalar(text( + "SELECT to_jsonb(s) FROM public.submissions s WHERE id=:id" + ), {"id": created.submission_id}) + assert after == before + assert await session.scalar(text( + "SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgname='submission_packet_custody'" + )) == 1 diff --git a/backend/tests/test_alembic.py b/backend/tests/test_alembic.py index 0a2dcca2e..70621c0b3 100644 --- a/backend/tests/test_alembic.py +++ b/backend/tests/test_alembic.py @@ -79,7 +79,7 @@ def test_v01_graph_has_one_root_and_head() -> None: script = ScriptDirectory.from_config(config) revisions = list(script.walk_revisions()) - assert [revision.revision for revision in revisions] == [HEAD_REVISION, "0020_review_admission_lock_order", "0019_submitter_awards", "0018_task_routing_request", "0017_acceptance_source_contracts", "0016_review_lifecycle_fence", "0015_contribution_awards", "0014_final_acceptance", "0013_review_source", "0012_review_packet", "0011_task_routing_source", "0010_post_submit_authority", "0009_checker_material_lineage", "0008_checker_execution", "0007_checker_output_custody", "0006_history_read_authority", "0005_task_evidence_authority", "0004_task_context_authority", "0003_task_read_authority", "0002_task_queue_authority", BASELINE_REVISION] + assert [revision.revision for revision in revisions] == [HEAD_REVISION, "0021_submission_manifest", "0020_review_admission_lock_order", "0019_submitter_awards", "0018_task_routing_request", "0017_acceptance_source_contracts", "0016_review_lifecycle_fence", "0015_contribution_awards", "0014_final_acceptance", "0013_review_source", "0012_review_packet", "0011_task_routing_source", "0010_post_submit_authority", "0009_checker_material_lineage", "0008_checker_execution", "0007_checker_output_custody", "0006_history_read_authority", "0005_task_evidence_authority", "0004_task_context_authority", "0003_task_read_authority", "0002_task_queue_authority", BASELINE_REVISION] assert revisions[-1].down_revision is None assert script.get_heads() == [HEAD_REVISION] diff --git a/backend/tests/test_artifact_bindings.py b/backend/tests/test_artifact_bindings.py index 7e5c04163..e7020dc5f 100644 --- a/backend/tests/test_artifact_bindings.py +++ b/backend/tests/test_artifact_bindings.py @@ -3,6 +3,8 @@ from __future__ import annotations from datetime import UTC, datetime +from dataclasses import replace +from app.modules.checkers.api import SubmissionPacketView from types import SimpleNamespace from unittest.mock import AsyncMock, Mock from uuid import UUID @@ -40,6 +42,7 @@ def _request(*, submission_id=None) -> SubmissionAdmissionConsumptionRequest: pre_submit_policy_bundle_hash=_sha("3"), ) return SubmissionAdmissionConsumptionRequest( + packet_sha256=SubmissionPacketView("Prepared summary", "Prepared attestation").sha256, admission_id=new_record_id(), submission_id=submission_id or new_record_id(), submission_version=1, @@ -85,6 +88,7 @@ def _lineage(request: SubmissionAdmissionConsumptionRequest): stale_reason=None, ) evidence = SimpleNamespace( + packet_sha256=request.packet_sha256, id=evidence_id, actor_profile_id=admission.actor_profile_id, identity_link_id=admission.identity_link_id, @@ -316,6 +320,7 @@ async def test_consumed_admission_rejects_different_submission() -> None: async def test_consumed_admission_rejects_wrong_submission_version() -> None: original = _request() replay = SubmissionAdmissionConsumptionRequest( + packet_sha256=original.packet_sha256, admission_id=original.admission_id, submission_id=original.submission_id, submission_version=2, @@ -386,3 +391,26 @@ async def test_consumption_rejects_invalid_manifest_before_binding(corruption): session.add.assert_not_called() session.flush.assert_not_awaited() authority.consume.assert_not_awaited() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("status", ["ready", "consumed"]) +@pytest.mark.parametrize("field", ["summary", "contributor_attestation"]) +async def test_changed_packet_denies_before_binding_or_consumed_replay(status, field): + original = _request() + admission, evidence, content = _lineage(original) + admission.status = status + if status == "consumed": + admission.consumed_by_submission_id = str(original.submission_id) + admission.consumed_by_submission_version = original.submission_version + packet = SubmissionPacketView("Prepared summary", "Prepared attestation") + changed = replace(packet, **{field: "Different valid contributor text"}) + request = replace(original, packet_sha256=changed.sha256) + session = _session(admission, evidence, content) + authority = _Allow() + with pytest.raises(SubmissionAdmissionConsumptionError, match="submission_bundle_admission_unavailable"): + await SubmissionAdmissionConsumptionService(session, authority).consume(request) + authority.consume.assert_not_awaited() + session.add.assert_not_called() + session.flush.assert_not_awaited() + assert admission.status == status diff --git a/backend/tests/test_artifact_bindings_db.py b/backend/tests/test_artifact_bindings_db.py index 450392bea..29dadda2f 100644 --- a/backend/tests/test_artifact_bindings_db.py +++ b/backend/tests/test_artifact_bindings_db.py @@ -212,8 +212,8 @@ async def validate_context(self, candidate): request = SubmissionCreationRequest( admission_id=art_request.admission_id, task_id=context.task_id, assignment_id=context.assignment_id, contributor_id=context.contributor_id, - predecessor_submission_id=None, summary="summary", - contributor_attestation="attestation", + predecessor_submission_id=None, summary="Prepared summary", + contributor_attestation="Prepared attestation", ) async with factory() as session: await session.execute(text(f'set search_path to "{schema}"')) @@ -242,6 +242,7 @@ async def test_postgresql_consumption_is_concurrent_and_rollback_safe( ) -> None: request = _request() request = type(request)( + packet_sha256=request.packet_sha256, admission_id=request.admission_id, submission_id=request.submission_id, submission_version=2, @@ -430,8 +431,8 @@ async def fixed_context(*_args, **_kwargs): return service request = SubmissionCreationRequest( admission_id=art_request.admission_id, task_id=context.task_id, assignment_id=context.assignment_id, contributor_id=context.contributor_id, - predecessor_submission_id=None, summary="summary", - contributor_attestation="attestation", + predecessor_submission_id=None, summary="Prepared summary", + contributor_attestation="Prepared attestation", ) return art_request, human, request, request_id, correlation_id diff --git a/backend/tests/test_submission_composition.py b/backend/tests/test_submission_composition.py index aaf9aa07f..3ae968fd3 100644 --- a/backend/tests/test_submission_composition.py +++ b/backend/tests/test_submission_composition.py @@ -168,6 +168,8 @@ def close(self, handle): assert handle == "prepared" class Admissions: async def consume(self, value): + from app.modules.checkers.api import SubmissionPacketView + assert value.packet_sha256 == SubmissionPacketView(request.summary, request.contributor_attestation).sha256 events.append(("art", value.submission_version)) return SubmissionArtifactAdmissionResult(binding_id=new_record_id(), content_id=new_record_id()) diff --git a/docs/roadmap_status.md b/docs/roadmap_status.md index 7043ac519..afc3df552 100644 --- a/docs/roadmap_status.md +++ b/docs/roadmap_status.md @@ -160,7 +160,10 @@ adds exact hidden source preparation through existing owner ports, without source publication or authority. [ARCH-04E1B-B3](../.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB3.md) retains verified ZIP member metadata for consumption without another storage read. -Initial Submission/dispatch composition is next, followed by the remaining routing +[ARCH-04E1B-B4](../.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md) +binds Submission text to its checked intake packet at consumption and in storage. +Initial Submission/dispatch composition is next, with capacity, receipt custody +and fresh-authorized replay still to reconcile, followed by the remaining routing handlers and complete authorized transaction proof. ## Pre-Submission And Post-Submission Checking @@ -207,8 +210,8 @@ cannot be reused as post-submission review-gate evidence. See the | Task readiness and claim | **Foundation with grant-backed manager and contributor commands** | Task records, assignments and locked work context; guide-bound ContributionPolicyVersion locked before `READY` and copied to TaskAssignment; detached project/guide display; public project-scoped ready, management and operational queues with distinct current grant authority and signed bounded live pagination; public contributor/management detail with exact project and assignment authority; separate current live work-context projections with exact receipt-selected review/revision/ContributionPolicy identities and no obsolete economic fields; explicit management/operational/audit locked-context projections using one historical resolver, with separate public manager, system-Operator and Audit Authority access; immutable contributor/management requirements using one historical translator, with public exact Contributor and Manager authority; bounded public Audit Authority lifecycle evidence with atomic project/task scoping and exact transition references; public manager create/screen/release use exact covered Project Manager authority, atomic audit and replay; claim/start/contributor context use exact-project Submitter grants; separate manager context and system-Operator start; durable claim/start retry receipts with fresh authority and exact assignment checks; hidden exact-assignment invalidation with committed cause verification, delivery fencing, exact fixed-service authority and decision-bound immutable release evidence; atomic authority-loss publication and registered prefork delivery | Public intake cutover after evaluation/remediation prerequisites | | 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 exact preparation; 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 and detached facts; AUTH-19A inert source/receipt commitments and planned router identity; ARCH-04E1B-A immutable request/source-identity reservation and exact replay; ARCH-04E2-A strict preparation; REV-04C hidden FinalAcceptance/TASK/CON participant; ARCH-04E1B-B1 required TASK reservation/current-read guard, ordered admission INSERTs and mechanical race controls; ARCH-04E1B-B2 exact source preparation without publication; 04E1B-B3 retains inspected ZIP metadata for consumption | Initial Submission/dispatch composition is next, then remaining handlers 04E1B-B. True routing remains independent of shared acceptance. False activation at 04E2-B requires the same strict participant input to carry the mandatory exact AUTH decision-event receipt, database-enforced FinalAcceptance/TASK/CON completeness, shared audit/outbox and scoped lifecycle/fulfillment custody. 04E1B-B1 supplies reservation/current-read and admission INSERT lock ordering; the remaining handlers must prove complete authorized routing/currentness race orders. No handler, current pointer, route, currentness guarantee or acceptance effect is live; 04F remediation still precedes false guide activation | +| 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, locked policy lineage and service/database checked-packet custody; 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 exact preparation; 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 and detached facts; AUTH-19A inert source/receipt commitments and planned router identity; ARCH-04E1B-A immutable request/source-identity reservation and exact replay; ARCH-04E2-A strict preparation; REV-04C hidden FinalAcceptance/TASK/CON participant; ARCH-04E1B-B1 required TASK reservation/current-read guard, ordered admission INSERTs and mechanical race controls; ARCH-04E1B-B2 exact source preparation without publication; 04E1B-B3 retains inspected ZIP metadata and B4 binds checked packet text for consumption | Initial Submission/dispatch composition is next, then remaining handlers 04E1B-B. True routing remains independent of shared acceptance. False activation at 04E2-B requires the same strict participant input to carry the mandatory exact AUTH decision-event receipt, database-enforced FinalAcceptance/TASK/CON completeness, shared audit/outbox and scoped lifecycle/fulfillment custody. 04E1B-B1 supplies reservation/current-read and admission INSERT lock ordering; the remaining handlers must prove complete authorized routing/currentness race orders. No handler, current pointer, route, currentness guarantee or acceptance effect is live; 04F remediation still precedes false guide activation | | 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 and REV-03B immutable normalized packet persistence with live ingest custody; REV-04A Review/finding/resolution and completed request storage | Future resolver proof; canonical admission from `allow_review`; claim/lease/packet authority; lease copies the Submission-stamped policy version with no CON lookup | | Review decision and revision | **Hidden acceptance core; runtime planned** | Review/revision policy identities and mutation authority; REV-04A immutable Review storage; REV-04B source storage; REV-04C hidden source-neutral FinalAcceptance/TASK/CON participant; approved same-task revision-rebase semantics | Add the mandatory exact AUTH receipt to the same participant input and complete database/audit/outbox closure before either trigger consumes it; then authorize atomic human decisions, revision preparation, replay and recovery | | Contribution and compensation truth | **Hidden shared participant plus public policy administration** | ContributionPolicyVersion persistence; lifecycle-audit participant; adapter bindings; public Finance policy administration; REV-04B shared acceptance source storage; CON-03C immutable ContributionRecord/CompensationAward storage; CON-07 source-neutral submitter participant and complete award sets; REV-04C composes it with FinalAcceptance/TASK effects in the caller transaction | Add authority/evidence and complete-set database closure before production consumption. Only actual Reviews create reviewer records. Add audit/outbox and fulfillment-root/ordinal custody before activation; no public recognition or fulfillment route is live | @@ -558,7 +561,7 @@ The next dependency-safe product sequence is: exactly replay the contribution and complete zero/one/two frozen award set; paid replay checks its correlation and unpaid replay retains none. REV-04C now composes that result with FinalAcceptance and TASK effects. Hidden handlers - 04E1B-B remain after delivered 04E1B-B2 exact source preparation and 04E1B-B3 verified ZIP metadata. Initial dispatch must bind creation/binding receipts and reconcile ART/CHECKERS input limits. Delivered 04E1B-B1 makes TASK-before-CHECKERS reservation, + 04E1B-B remain after delivered 04E1B-B2 exact source preparation and 04E1B-B3 verified ZIP metadata plus B4 checked-packet custody. Initial dispatch must bind creation/binding receipts, reconcile ART/CHECKERS input limits and implement fresh-authorized replay after creation. Delivered 04E1B-B1 makes TASK-before-CHECKERS reservation, current-read and admission INSERT ordering mandatory, including intermediate admission waits and both mechanical race controls; the full authorized acceptance/successor race proof remains required. At activation 04E2-B make the @@ -686,7 +689,7 @@ Delivered foundations (not a claim of full public integration) CON-07 hidden source-neutral submitter participant + complete frozen award set REV-04C hidden FinalAcceptance + TASK effects + CON composition (no authority/route) ARCH-04E1B-B1 ordered reservation/current reads + admission INSERTs (no activation) - ARCH-04E1B-B2 exact source proposal + B3 verified ZIP metadata (no dispatch/publication authority) + ARCH-04E1B-B2 exact source proposal + B3 ZIP metadata + B4 checked packet custody (no dispatch/publication authority) Remaining integration both branches: handlers 04E1B-B -> activation 04E2-B -> live 04E3 dispatch/routing diff --git a/docs/spec_artifact_storage_service.md b/docs/spec_artifact_storage_service.md index b188742c1..54f86ea9f 100644 --- a/docs/spec_artifact_storage_service.md +++ b/docs/spec_artifact_storage_service.md @@ -1348,7 +1348,11 @@ Unicode 15 mapping that matches the backend, rather than locale-dependent lowerc The admission references its identity and hash. Consumption validates that body and returns detached file metadata with archive commitments only for a consumed result or exact replay; stale results contain no material. Consumption performs -no provider read. Older retained evidence without metadata stays unchanged and +no provider read. Consumption also requires the canonical hash of the exact +Submission summary and contributor attestation to match retained pre-submit +evidence, before either new binding or consumed replay. A deferred database +guard compares the final bound Submission text with that evidence; the existing +lineage guard prevents clearing or replacing a bound admission. Older retained evidence without metadata stays unchanged and cannot supply current consumption. Existing post-submit material selection keeps its exact immutable ART lineage and inspected-byte checks; it does not use this new consumption projection. This storage guarantee does not activate diff --git a/docs/spec_chunk_4_task_queue_assignment.md b/docs/spec_chunk_4_task_queue_assignment.md index 2be7786f3..7dd95d2bc 100644 --- a/docs/spec_chunk_4_task_queue_assignment.md +++ b/docs/spec_chunk_4_task_queue_assignment.md @@ -567,3 +567,11 @@ creation time. No source INSERT or authority follows from constructing a proposa The current hidden intake does not yet set `evaluation_pending`; the later atomic dispatch composition owns that transition. Mechanical preparation tests explicitly arrange that state and the claim timestamp, without claiming live dispatch/claim. + +### Checked packet custody at hidden creation + +ARCH-04E1B-B4 forwards the canonical summary/attestation commitment from the +actual Submission request to ART. Consumption rejects a different packet before +binding or consumed replay. PostgreSQL also checks the final bound Submission +against retained pre-submit evidence at commit, permitting the existing atomic +insert-then-bind sequence. This does not activate dispatch or expose public intake. From 44bfcf7ebc16f664f3a5a253f1c1f58080a41666 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 11:59:11 +0100 Subject: [PATCH 2/9] Prioritize the first contributor journey and repair verification --- .../WS-ARCH-001/WS-ARCH-001-04E1BB4.md | 19 ++++-- AGENTS.md | 24 +++++++- backend/alembic/env.py | 2 +- .../tests/tasks/test_submission_lineage.py | 61 ++++++++++--------- 4 files changed, 70 insertions(+), 36 deletions(-) diff --git a/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md b/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md index 751aa5e87..96525851e 100644 --- a/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md +++ b/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md @@ -4,7 +4,7 @@ - Durable disposition: `Complete` - Intended merge outcome: admission consumption and persisted Submission text must match the exact packet retained by pre-submission checking. -## Intent and discovery +## Intent Initial dispatch must use exactly the input that passed preparation. Plan review found that TASK forwards no packet commitment to ART consumption: prepared summary @@ -12,7 +12,7 @@ and attestation A can be replaced with B when creating a Submission. The existin pre-submit evidence already stores their canonical packet hash. Enforce that existing commitment before building dispatch on this boundary. -## Bounded design +## Bounded change - Forward the canonical hash of the actual creation request's summary and contributor attestation through existing TASK and ART consumption requests. @@ -37,7 +37,9 @@ contract/service, packet hashing caller and directly affected exports; CHECKERS fingerprint; focused binding/composition and real PostgreSQL submission tests plus their affected canonical fixtures; exact lane/ownership registration; this record, parent 04E contract and affected ARCH/AUTH/POL current navigation, README, -TASK/ART specifications and roadmap. +TASK/ART specifications and roadmap. The user's explicit delivery-priority +instruction also updates the existing AGENTS.md v0.1 rule in this same PR: focus +on the first complete public backend contributor path and defer unrelated work. ## Prohibited changes @@ -46,7 +48,7 @@ AUTH replay activation, routing/acceptance/review effects, public route, claim expiry, provider read, retained data rewrite/delete, compatibility path, weakened CI or skipped tests. Preserve unrelated CLI work. -## Acceptance and proof +## Acceptance criteria 1. Exact prepared packet creates a Submission through real hidden TASK/ART/AUTH. Changing only summary or only attestation rejects and rolls back Submission, @@ -64,7 +66,7 @@ CI or skipped tests. Preserve unrelated CLI work. stale wording/link/Commitrail checks and full hosted completeness. Coverage is diagnostic. Tests protect outcomes; no mirrored implementation-only cases. -## Risk and reviewers +## Risk and review routing L1. Architecture/security/reuse and QA/test-delta plan review before code. Implementation reviews additionally include CI-integrity and docs/product ops. @@ -92,3 +94,10 @@ only the first concrete boundary. Both plan reviews found it feasible. Reuse `protect_submission_contribution_stamp` for once-bound identity and existing ART immutable evidence/admission guards; do not duplicate them. The real test keeps preparation artifacts/evidence intact while proving creation-side rollback. + +## Evidence + +Use the focused binding/composition suite and isolated PostgreSQL lineage and +upgrade tests, plus the shared checks listed above. Verify the service and +database predicates independently with guard-removal probes. Exact heads and +transient run results belong in the PR, not this record. diff --git a/AGENTS.md b/AGENTS.md index d301736d0..c61ac0cb7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -94,7 +94,25 @@ definition or ownership boundary of Workstream. -> submission -> post-submission work evaluation -> review -> revision -> contribution records -> conditional compensation awards/fulfillment -> contribution evidence for a future reputation - projection. Runtime reputation projection remains deferred. + projection. The immediate delivery priority is the first complete backend + journey: approved project guide and locked policies -> task creation -> claim + and start -> upload ZIP -> actionable pre-check feedback or verified immutable + Submission -> automatic post-checking -> governed outcome. For a project with + `human_review_required=false`, passing required checks must reach the shared + authorized FinalAcceptance and submitter ContributionRecord, with applicable + conditional awards committed atomically; never fabricate a Review or reviewer + contribution. Failed checks and infrastructure failures need distinct, + recoverable outcomes. Preserve the default-true human-review branch and its + existing guards; prioritize live human review/revision after this first path. + Before selecting each chunk, review the current plan against merged owners and + identify the concrete gap it closes in this journey and its end-to-end proof. + Take prerequisite work only when that path cannot safely proceed without it; + do not expand foundations for hypothetical later use. Completion means a + realistic drill through public backend APIs and durable workers, including + failure/retry and exact contribution-record evidence, not hidden storage or + individually passing module tests alone. External integrations, frontend + expansion, contributor claim expiry/skip, runtime reputation and unrelated + cleanup remain deferred unless the user explicitly changes this priority. - Review decision stored values are only accept, needs_revision, or reject. - Frontend is locked as React + Vite + TypeScript. - Backend API is locked as Python with FastAPI. @@ -120,7 +138,9 @@ definition or ownership boundary of Workstream. - Bounded private ephemeral processing scratch is not artifact storage. It may use local files only through the canonical `ArtifactScratchManager` with aggregate quotas, crash cleanup, and no durable product reference. -- Do not expand into blockchain settlement, marketplace, external source adapters, automated routing, or agent workspace until the internal loop is proven. +- Do not expand into blockchain settlement, marketplace, external source adapters, + external task-routing systems or agent workspace until the internal loop is + proven. Internal policy-governed post-check routing is part of that loop. - External integrations must follow ADR 0014: extend the shared `ExternalServiceAdapter` convention through a typed capability port and use a typed `ExternalServiceAdapterFactory[TAdapter]` with explicit diff --git a/backend/alembic/env.py b/backend/alembic/env.py index b0ce2140f..b4bcbccd3 100644 --- a/backend/alembic/env.py +++ b/backend/alembic/env.py @@ -52,7 +52,7 @@ def do_run_migrations(connection: Connection) -> None: .scalars() .all() ) - if revisions not in ((), (_BASELINE_REVISION,), ("0002_task_queue_authority",), ("0003_task_read_authority",), ("0004_task_context_authority",), ("0005_task_evidence_authority",), ("0006_history_read_authority",), ("0007_checker_output_custody",), ("0008_checker_execution",), ("0009_checker_material_lineage",), ("0010_post_submit_authority",), ("0011_task_routing_source",), ("0012_review_packet",), ("0013_review_source",), ("0014_final_acceptance",), ("0015_contribution_awards",), ("0016_review_lifecycle_fence",), ("0017_acceptance_source_contracts",), ("0018_task_routing_request",), ("0019_submitter_awards",), ("0020_review_admission_lock_order",), (_CURRENT_HEAD_REVISION,)): + if revisions not in ((), (_BASELINE_REVISION,), ("0002_task_queue_authority",), ("0003_task_read_authority",), ("0004_task_context_authority",), ("0005_task_evidence_authority",), ("0006_history_read_authority",), ("0007_checker_output_custody",), ("0008_checker_execution",), ("0009_checker_material_lineage",), ("0010_post_submit_authority",), ("0011_task_routing_source",), ("0012_review_packet",), ("0013_review_source",), ("0014_final_acceptance",), ("0015_contribution_awards",), ("0016_review_lifecycle_fence",), ("0017_acceptance_source_contracts",), ("0018_task_routing_request",), ("0019_submitter_awards",), ("0020_review_admission_lock_order",), ("0021_submission_manifest",), (_CURRENT_HEAD_REVISION,)): raise RuntimeError(_RECREATE_GUIDANCE) # The read-only preflight autobegins a SQLAlchemy transaction. End that # transaction before Alembic establishes the migration transaction; diff --git a/backend/tests/tasks/test_submission_lineage.py b/backend/tests/tasks/test_submission_lineage.py index ee7c3121b..593102837 100644 --- a/backend/tests/tasks/test_submission_lineage.py +++ b/backend/tests/tasks/test_submission_lineage.py @@ -202,34 +202,39 @@ async def create(): assert admission.consumed_by_submission_id == submission.id assert submission.locked_payment_policy_version is None assert await session.scalar(select(func.count()).select_from(Submission)) == 1 - # Existing owner immutability is part of the new cross-row guarantee. - for update in ( - "submission_bundle_admission_id=NULL, artifact_binding_id=NULL, artifact_content_id=NULL", - "submission_bundle_admission_id=:foreign", - "artifact_binding_id=:foreign", - "artifact_content_id=:foreign", - ): - with pytest.raises(DBAPIError, match="submission contribution identity is immutable"): - async with factory.begin() as session: - await session.execute(text(f"UPDATE public.submissions SET {update} WHERE id=:id"), - {"id": created.submission_id, "foreign": new_record_id()}) - for statement, message in ( - ("UPDATE public.pre_submit_evidence_sets SET packet_sha256='sha256:' || repeat('0',64) " - "WHERE id=(SELECT pre_submit_evidence_set_id FROM public.submission_bundle_admissions WHERE id=:id)", - "pre_submit_evidence_sets rows are immutable"), - ("UPDATE public.submission_bundle_admissions SET pre_submit_evidence_set_id=:foreign WHERE id=:id", - "submission bundle admission lineage is immutable"), - ): - with pytest.raises(DBAPIError, match=message): - async with factory.begin() as session: - await session.execute(text(statement), {"id": admission_id, "foreign": new_record_id()}) - async with factory() as session: - retained = await session.get(Submission, str(created.submission_id)) - assert retained.summary == creation.summary - assert retained.worker_attestation == creation.contributor_attestation - assert retained.submission_bundle_admission_id == str(admission_id) - assert retained.artifact_binding_id == str(created.artifact_binding_id) - assert retained.artifact_content_id == str(created.artifact_content_id) + await _assert_bound_packet_immutable(h, created) + + +async def _assert_bound_packet_immutable(h, created): + factory, admission_id, creation = h.factory, h.admission_id, h.creation + # Existing owner immutability is part of the new cross-row guarantee. + for update in ( + "submission_bundle_admission_id=NULL, artifact_binding_id=NULL, artifact_content_id=NULL", + "submission_bundle_admission_id=:foreign", + "artifact_binding_id=:foreign", + "artifact_content_id=:foreign", + ): + with pytest.raises(DBAPIError, match="submission contribution identity is immutable"): + async with factory.begin() as session: + await session.execute(text(f"UPDATE public.submissions SET {update} WHERE id=:id"), + {"id": created.submission_id, "foreign": new_record_id()}) + for statement, message in ( + ("UPDATE public.pre_submit_evidence_sets SET packet_sha256='sha256:' || repeat('0',64) " + "WHERE id=(SELECT pre_submit_evidence_set_id FROM public.submission_bundle_admissions WHERE id=:id)", + "pre_submit_evidence_sets rows are immutable"), + ("UPDATE public.submission_bundle_admissions SET pre_submit_evidence_set_id=:foreign WHERE id=:id", + "submission bundle admission lineage is immutable"), + ): + with pytest.raises(DBAPIError, match=message): + async with factory.begin() as session: + await session.execute(text(statement), {"id": admission_id, "foreign": new_record_id()}) + async with factory() as session: + retained = await session.get(Submission, str(created.submission_id)) + assert retained.summary == creation.summary + assert retained.worker_attestation == creation.contributor_attestation + assert retained.submission_bundle_admission_id == str(admission_id) + assert retained.artifact_binding_id == str(created.artifact_binding_id) + assert retained.artifact_content_id == str(created.artifact_content_id) @pytest.mark.postgres_schema_contract From 78a6ceb86d911344907ea369ab1ff1dfaf58c249 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 12:11:29 +0100 Subject: [PATCH 3/9] Align delivery plans around the first complete contributor journey --- .commitrail/INDEX.md | 2 +- .../initiatives/WS-ARCH-001/OVERVIEW.md | 2 + .../WS-ARCH-001/WS-ARCH-001-04E1BB4.md | 5 +- .../WS-ARCH-001/planning/CHUNK_MAP.md | 6 ++- .../initiatives/WS-ARCH-001/planning/PLAN.md | 50 ++++++++++++++++++- .../WS-ARCH-001-04F-checker-remediation.md | 6 ++- .../initiatives/WS-AUTH-001/OVERVIEW.md | 2 + .../initiatives/WS-CON-001/OVERVIEW.md | 2 + .../initiatives/WS-POL-003/OVERVIEW.md | 2 + .../initiatives/WS-REV-001/OVERVIEW.md | 2 + docs/roadmap_status.md | 19 +++++-- 11 files changed, 85 insertions(+), 13 deletions(-) diff --git a/.commitrail/INDEX.md b/.commitrail/INDEX.md index 29880e124..df6def5f5 100644 --- a/.commitrail/INDEX.md +++ b/.commitrail/INDEX.md @@ -9,7 +9,7 @@ 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 | Nine tools through WS-MCP-002-03: self-service and administrative reads; 18 tools remain and WS-MCP-002-04 administrative grant mutations are next | | [WS-CLI-001](initiatives/WS-CLI-001/OVERVIEW.md) | Planned | Public Go CLI self-service, project inspection, manager browsing, contributor discovery and claim/start delivered through WS-CLI-001-06; further public journeys and binary distribution remain | -| [WS-ARCH-001](initiatives/WS-ARCH-001/OVERVIEW.md) | Planned | Source storage, inert AUTH contracts, TASK request reservation, hidden exact AUTH preparation and the REV-04C hidden FinalAcceptance/TASK/CON participant are delivered; TASK-before-CHECKERS reservation/current-read custody and ordered admission INSERTs are delivered by 04E1B-B1; 04E1B-B2 adds exact source preparation without publication; 04E1B-B3 retains inspected ZIP metadata and B4 binds Submission text to checked packet custody; initial Submission/dispatch composition is next, followed by remaining hidden routing handlers. True admission remains independent of shared acceptance; false activation still requires exact AUTH receipt custody, database complete-set enforcement, currentness race proof and atomic routing activation. | +| [WS-ARCH-001](initiatives/WS-ARCH-001/OVERVIEW.md) | Planned | Source storage, inert AUTH contracts, TASK request reservation, hidden exact AUTH preparation and the REV-04C hidden FinalAcceptance/TASK/CON participant are delivered; TASK-before-CHECKERS reservation/current-read custody and ordered admission INSERTs are delivered by 04E1B-B1; 04E1B-B2 adds exact source preparation without publication; 04E1B-B3 retains inspected ZIP metadata and B4 binds Submission text to checked packet custody; initial Submission/dispatch composition is next under the [first-layer sequence](initiatives/WS-ARCH-001/planning/PLAN.md#first-complete-contributor-milestone), ending in a public contributor drill before live human review/revision. True admission remains independent of shared acceptance; false activation still requires exact AUTH receipt custody, database complete-set enforcement, currentness race proof and atomic routing activation. | | [WS-ART-001](initiatives/WS-ART-001/OVERVIEW.md) | Planned | Exact checker input/output custody and packet foundations are delivered; routing integration, remediation and public intake remain. | | [WS-AUTH-001](initiatives/WS-AUTH-001/OVERVIEW.md) | Planned | AUTH-19A commitments, TASK request reservation, ARCH-04E2-A hidden strict PREP matching and the REV-04C hidden FinalAcceptance/TASK/CON participant are delivered; the action remains unavailable, with mandatory exact AUTH receipt input, database closure, audit/outbox and scoped activation still required for the automated path. | | [WS-CON-001](initiatives/WS-CON-001/OVERVIEW.md) | Planned | Contribution/award storage, CON-07 participation and REV-04C hidden FinalAcceptance/TASK/CON composition are delivered; production consumption still requires genuine authority, database complete-set enforcement, currentness race proof, shared audit/outbox, fulfillment-root ordinals and lifecycle activation. | diff --git a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md index dfd35aa25..1b3e7f2b6 100644 --- a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md @@ -1,5 +1,7 @@ # WS-ARCH-001 — Modular monolith boundaries +Delivery priority: [first complete contributor milestone](planning/PLAN.md#first-complete-contributor-milestone). Use its nine-step order and end-to-end exit proof when selecting the next bounded change; live human review/revision and external integration are later work. + [ARCH-04E1B-B4](WS-ARCH-001-04E1BB4.md) binds Submission summary and attestation to the packet retained by intake, including database custody. Initial dispatch remains next and must reconcile capacity, exact receipts and fresh-authorized replay before connecting workers. [ARCH-04E1B-B3](WS-ARCH-001-04E1BB3.md) retains the inspected ZIP manifest in immutable ART evidence and returns verified file metadata on admission consumption. Initial Submission/dispatch composition is next; it must reconcile existing ART/CHECKERS size limits and retain exact creation/binding receipts. No dispatch or routing authority is activated. diff --git a/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md b/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md index 96525851e..b49fea35b 100644 --- a/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md +++ b/.commitrail/initiatives/WS-ARCH-001/WS-ARCH-001-04E1BB4.md @@ -36,9 +36,10 @@ TASK submission command contract/composition and adapters/tasks; ART consumption contract/service, packet hashing caller and directly affected exports; CHECKERS public packet value helper; one migration after 0021, test_alembic and schema fingerprint; focused binding/composition and real PostgreSQL submission tests plus their affected canonical fixtures; exact lane/ownership registration; this record, -parent 04E contract and affected ARCH/AUTH/POL current navigation, README, +parent 04E contract and affected ARCH/AUTH/POL/CON/REV current navigation, README, TASK/ART specifications and roadmap. The user's explicit delivery-priority -instruction also updates the existing AGENTS.md v0.1 rule in this same PR: focus +instruction also reconciles the existing first-layer sequence, roadmap/navigation, +04F dependencies and the existing AGENTS.md v0.1 rule in this same PR: focus on the first complete public backend contributor path and defer unrelated work. ## Prohibited changes diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md b/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md index 38645dbe3..155f3fab0 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md @@ -1,5 +1,7 @@ # WS-ARCH-001 — Current remaining change map +Delivery priority: [first complete contributor milestone](PLAN.md#first-complete-contributor-milestone). Use its nine-step order and end-to-end exit proof when selecting the next bounded change; live human review/revision and external integration are later work. + [ARCH-04E1B-B4](../WS-ARCH-001-04E1BB4.md) binds Submission summary and attestation to the packet retained by intake, including database custody. Initial dispatch remains next and must reconcile capacity, exact receipts and fresh-authorized replay before connecting workers. [ARCH-04E1B-B3](../WS-ARCH-001-04E1BB3.md) retains the inspected ZIP manifest in immutable ART evidence and returns verified file metadata on admission consumption. Initial Submission/dispatch composition is next; it must reconcile existing ART/CHECKERS size limits and retain exact creation/binding receipts. No dispatch or routing authority is activated. @@ -49,7 +51,7 @@ currentness proof stay within 04E1B-B, before activation and live composition. | [WS-ARCH-001-03B7](../WS-ARCH-001-03B7.md) | Immutable contributor and management requirements through one historical translator and scoped lock | L1 | Complete; exact Contributor and Manager requirements authority/public access delivered by 03C5 | | [WS-ARCH-001-03B8](../WS-ARCH-001-03B8.md) | Bounded immutable task audit evidence with atomic project scope and exact transition references | L1 | Complete; Audit Authority/public activation delivered by 03C7; assignment hidden invalidation delivered by 03B9; 03C1 exact feature authority complete; producer/registration complete in 03C2 | | [WS-ARCH-001-03B9](../WS-ARCH-001-03B9.md) | Hidden exact-assignment authority invalidation with committed cause, chronology and same-transaction delivery fence | L1 | Complete; 03C1 authority and 03C2 atomic publication/registration delivered | -| `WS-ARCH-001-02I` | Admission-only public API/dispatch cutover and removal of legacy route reachability; physical economic cleanup remains CP09 after zero consumers | L1 | Deferred after 02H plus split 03/04/05 remediation, revision, checker-output and REV admission prerequisites | +| `WS-ARCH-001-02I` | Admission-only public API/dispatch cutover and removal of legacy route reachability; physical economic cleanup remains CP09 after zero consumers | L1 | Planned after first-layer runtime and checker remediation; initial and checker-remediation intake only. Human-review revisions follow their own live boundary | | [WS-ARCH-001-CP05](../WS-ARCH-001-CP05.md) | AUTH exact ContributionPolicy activation | L1 | Complete; exact policy authority delivered in PR #387 | | [WS-ARCH-001-CP06](../WS-ARCH-001-CP06.md) | CON guide-activation/revision policy-validation port | L1 | Complete; explicit version/purpose validation and shared current resource fences | | [WS-ARCH-001-CP07](../WS-ARCH-001-CP07.md) | PROJECTS hidden activation/binding and replacement readiness guard | L1 | Complete; AUTH-12H authority and AUTH-18 public manager activation/context delivered | @@ -74,7 +76,7 @@ currentness proof stay within 04E1B-B, before activation and live composition. | [WS-ARCH-001-04E1A](../WS-ARCH-001-04E1A.md) | Route-neutral immutable source schema and shared accepted-effects types | L1 | Complete; REV-04C uses a bounded exact-source verifier, with no general routing publication writer/reader, routing authority or current pointer; its hidden effects participant does not make false routing available | | [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 | Both branches: delivered 04E1A/04D2/OUTBOX-02, request reservation 04E1B-A and AUTH preparation 04E2-A; exact source preparation [04E1B-B2](../WS-ARCH-001-04E1BB2.md) -> verified ZIP metadata [04E1B-B3](../WS-ARCH-001-04E1BB3.md) -> initial Submission/dispatch composition and remaining handlers/currentness proof 04E1B-B -> authority/evidence closure and activation 04E2-B -> live 04E3. False uses delivered REV-04C participation and additionally needs mandatory exact receipt/database/audit closure, fulfillment-root ordinal custody and scoped lifecycle activation; true does not depend on CON. False guide 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` | +| [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 from required hidden 04E result/handler contracts; before false-policy activation and public 02I, without requiring live human review | CP09, 04E and 04F are coordination parents, not permission for multi-owner PRs. Only CP09 and 04F are outside the `allow_review` critical path; 04E's children diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md index d89c80e3b..eaf14ba08 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md @@ -1,5 +1,51 @@ # WS-ARCH-001 — Current delivery plan through allow_review +## First complete contributor milestone + +This is the governing delivery order for the first usable backend journey, not +nine promised PRs. Review each bounded change against merged owners and name the +step it closes, its concrete prerequisite and its observable proof. Existing +hidden foundations are reused; a new foundation is justified only by a demonstrated +blocker to this journey. Completion of an implementation PR is not completion of +the milestone. Open PRs describe transient work; records describe intended merged +outcomes. + +| Order | Work and existing owner boundary | Required outcome | +| --- | --- | --- | +| 1 | [Checked packet custody, ARCH-04E1B-B4](../WS-ARCH-001-04E1BB4.md) | Actual Submission summary/attestation match retained intake evidence; service and database rejection preserve rollback and retained data. | +| 2 | Input capacity within remaining ARCH-04E1B-B | Preparation and dispatch use the same bounded request rules. Oversized inputs fail before ready admission, without truncation or a stranded successful preparation. | +| 3 | Initial Submission/dispatch within ARCH-04E1B-B | Submission, ART binding, exact creation/binding receipts, initial evaluation reservation and shared outbox event commit together. Fresh-authorized replay returns original identities after a lost response. | +| 4 | Hidden request/completion handlers within ARCH-04E1B-B | Reuse shared outbox and CHECKERS execution. Verify exact bytes, locked policies and current generation; duplicate/stale delivery has no additional effect. | +| 5 | Authorized governed outcomes, ARCH-04E2-B and existing shared participants | Genuine authority commits with its full consequence. False/pass atomically creates FinalAcceptance, accepted TASK state, submitter ContributionRecord and applicable awards; true preserves its independent human-review handoff. Include exact receipt, database closure, audit/outbox, lock-race and required fulfillment-root custody. | +| 6 | [Checker remediation and recovery, ARCH-04F](chunks/WS-ARCH-001-04F-checker-remediation.md) | Contributor-correctable failure has bounded findings and same-policy replacement ZIP intake. Infrastructure recovery and project/setup faults remain separate, with correct authorized retry and immutable prior evidence. | +| 7 | Live composition, ARCH-04E3, and false-policy readiness | Register proven handlers; enable the false-policy path only after success, remediation and the existing scoped lifecycle activation/drain controls are proven. Preserve default-true policy and deny unsupported paths. | +| 8 | Public intake, ARCH-02I | Expose initial upload/preparation, verification progress, feedback, admission-backed creation and checker-remediation resubmission through exact authorized APIs and outcome reads. Remove superseded touched paths; no provider coordinates or compatibility route. | +| 9 | First-layer integration drill | One real project completes guide approval, task creation/claim/start, upload, failed intake/correction, verified Submission, automatic checking, post-check remediation and false-policy acceptance with exact ContributionRecord evidence. Exercise real PostgreSQL, S3-compatible storage and broker/workers, lost responses, duplicate delivery, restart, revocation/isolation and recovery. | + +The first public intake scope is **initial submissions and checker remediation**. +The historical pre-cutover ARCH-02I contract's requirement to implement human +review revisions before any public intake is not adopted for this milestone. +Human-review revision remains unavailable until its own live authority and +lineage are implemented through the same canonical intake operation; it gains no +permissive placeholder or alternate endpoint. The current bounded ARCH-02I record +must use this scope when implementation starts. + +ARCH-04F can be implemented and proven against hidden current-result and routing +participants before production false-policy activation. Its dependency is the +required 04E handler/result contracts, not a fully live false branch. This avoids +a cycle: prove success and failure paths first, then activate the connected runtime. +True human-review handoff remains independent of CON/shared acceptance and is not +a requirement to activate human review queues for this first milestone. + +Live human review/decisions and reviewer contributions, controlled human revision, +contributor claim expiry/skip, external integrations, frontend expansion, runtime +reputation and unrelated cleanup follow later unless the user changes priority. +Applicable award facts stay atomic in step 5; broader external payment fulfillment +is not required to prove an unpaid project's first usable path. Supported registered +checks must genuinely meet the selected project's requirements: structural checks +must not be advertised as substantive judges, and an unsupported required evaluator +blocks that project rather than being silently omitted. + [ARCH-04E1B-B4](../WS-ARCH-001-04E1BB4.md) binds Submission summary and attestation to the packet retained by intake, including database custody. Initial dispatch remains next and must reconcile capacity, exact receipts and fresh-authorized replay before connecting workers. [ARCH-04E1B-B3](../WS-ARCH-001-04E1BB3.md) retains the inspected ZIP manifest in immutable ART evidence and returns verified file metadata on admission consumption. Initial Submission/dispatch composition is next; it must reconcile existing ART/CHECKERS size limits and retain exact creation/binding receipts. No dispatch or routing authority is activated. @@ -101,7 +147,7 @@ checker-remediation boundary before public Submission cutover. | ARCH-04E2-B | ARCH-04E1B-B; scoped XINT-003-08B controller activation for false | Require the exact AUTH receipt on the same strict input; add database complete-set and audit/outbox closure; genuine allow commits with all governed effects | | 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 | | ARCH-04E | ARCH-04E3 | Completed coordination boundary consumed by downstream REV | -| ARCH-04F (later public-cutover prerequisite) | ARCH-04E | CHECKER failure facts and TASK/ART remediation resubmission, not REV | +| ARCH-04F (before false activation and public intake) | Required hidden 04E result/handler contracts; no live false-branch prerequisite | CHECKER failure facts and TASK/ART remediation resubmission, not REV | False guide activation additionally requires shared acceptance, exact AUTH, a valid generation through scoped XINT-003-08B controller activation and @@ -113,7 +159,7 @@ The first complete contributor milestone includes public claim/upload/pre-check feedback, immutable Submission, automatic checking, failure remediation and, for locked false, shared FinalAcceptance plus the submitter ContributionRecord and applicable awards. Complete it before live human review/revision; independent -review foundations may proceed in another worktree without blocking that path. +review work requires an explicitly assigned parallel scope and must not delay that path. CP05 and ARCH-04A have independent prerequisites. POL-04B consumes the corrected ARCH-04A catalogue/schema before producing approval-eligible generations. Owners may diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04F-checker-remediation.md b/.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04F-checker-remediation.md index c8ef434f3..4fcacdaf8 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04F-checker-remediation.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/chunks/WS-ARCH-001-04F-checker-remediation.md @@ -1,6 +1,6 @@ # Chunk Contract: WS-ARCH-001-04F Checker Remediation Handoff -Disposition: Planned. Non-executable coordination parent after 04E, to be +Disposition: Planned. Non-executable coordination parent using the required hidden 04E result/handler contracts, to be split into owner-sized hidden behavior, authority and live integration changes before implementation; not one combined multi-owner PR. Risk: L1. Outcome: final current contributor-correctable checker outcomes create one bounded, @@ -18,7 +18,9 @@ run and blocking findings; replay and concurrency create one projection; superseded or stale runs cannot remain current; contributor visibility is bounded to their own Submission. This chunk is required before public 02I but does not block REV beginning from the separate canonical `allow_review` -manifest. +manifest. Its hidden implementation and authority proof precede production +false-policy activation; it does not depend on an already-live false branch. +Follow the [first-layer sequence](../PLAN.md#first-complete-contributor-milestone). This is the sole replacement for historical XINT-05C checker-remediation submission work. TASKS owns predecessor/current-assignment validation and the diff --git a/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md b/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md index 32f12279c..c140579e7 100644 --- a/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md @@ -1,5 +1,7 @@ # WS-AUTH-001 — Workstream authorization service +Delivery priority follows the [first complete contributor milestone](../WS-ARCH-001/planning/PLAN.md#first-complete-contributor-milestone): contribute only prerequisites of that public backend path; live human review/revision and external integrations remain later work. + [AUTH-19A](../WS-AUTH-001/WS-AUTH-001-19A.md) delivers inert exact source/receipt contracts and the planned router identity. ARCH-04E1B-A delivers caller-owned routing-request and future source-identity reservation. ARCH-04E2-A now delivers strict hidden diff --git a/.commitrail/initiatives/WS-CON-001/OVERVIEW.md b/.commitrail/initiatives/WS-CON-001/OVERVIEW.md index aa784d897..e08be26a3 100644 --- a/.commitrail/initiatives/WS-CON-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-CON-001/OVERVIEW.md @@ -1,5 +1,7 @@ # WS-CON-001 — Contribution and conditional compensation +Delivery priority follows the [first complete contributor milestone](../WS-ARCH-001/planning/PLAN.md#first-complete-contributor-milestone): contribute only prerequisites of that public backend path; live human review/revision and external integrations remain later work. + [AUTH-19A](../WS-AUTH-001/WS-AUTH-001-19A.md) delivers inert exact source/receipt contracts and the planned router identity. TASK request and future source-ID reservation (ARCH-04E1B-A) and strict hidden AUTH preparation (ARCH-04E2-A) are delivered. diff --git a/.commitrail/initiatives/WS-POL-003/OVERVIEW.md b/.commitrail/initiatives/WS-POL-003/OVERVIEW.md index 1cc6e4fe2..28c67d54b 100644 --- a/.commitrail/initiatives/WS-POL-003/OVERVIEW.md +++ b/.commitrail/initiatives/WS-POL-003/OVERVIEW.md @@ -1,5 +1,7 @@ # WS-POL-003 — Unified project-guide compilation +Delivery priority follows the [first complete contributor milestone](../WS-ARCH-001/planning/PLAN.md#first-complete-contributor-milestone): contribute only prerequisites of that public backend path; live human review/revision and external integrations remain later work. + [AUTH-19A](../WS-AUTH-001/WS-AUTH-001-19A.md) delivers inert exact source/receipt contracts and the planned router identity. ARCH-04E1B-A delivers caller-owned routing-request and future source-identity reservation. ARCH-04E2-A now delivers strict hidden diff --git a/.commitrail/initiatives/WS-REV-001/OVERVIEW.md b/.commitrail/initiatives/WS-REV-001/OVERVIEW.md index bb06cd0f7..56774b0fa 100644 --- a/.commitrail/initiatives/WS-REV-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-REV-001/OVERVIEW.md @@ -1,5 +1,7 @@ # WS-REV-001 — Review and revision lifecycle +Delivery priority follows the [first complete contributor milestone](../WS-ARCH-001/planning/PLAN.md#first-complete-contributor-milestone): contribute only prerequisites of that public backend path; live human review/revision and external integrations remain later work. + [AUTH-19A](../WS-AUTH-001/WS-AUTH-001-19A.md) delivers inert exact source/receipt contracts and the planned router identity. TASK request and future source-ID reservation (ARCH-04E1B-A) and strict hidden AUTH preparation (ARCH-04E2-A) are delivered. diff --git a/docs/roadmap_status.md b/docs/roadmap_status.md index afc3df552..d0b54cf6e 100644 --- a/docs/roadmap_status.md +++ b/docs/roadmap_status.md @@ -511,7 +511,16 @@ Exact post-submit service authority and ARCH-04E1A source-only facts/types are implemented; automatic dispatch, routing and acceptance remain unavailable. Live setup does not wait for downstream task/checker execution. -The next dependency-safe product sequence is: +The [first complete contributor milestone](../.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md#first-complete-contributor-milestone) +is the immediate delivery sequence and exit test: checked input, capacity alignment, +atomic Submission/dispatch, hidden handlers, authorized outcomes, remediation, +live activation, public intake and a real end-to-end drill. Human review/revision +runtime follows that milestone. Initial public intake covers initial submissions +and checker remediation; the historical requirement to complete human-review +revisions before any public intake is not adopted. Prove remediation against hidden +handlers before activating false; do not make it depend on an already-live false path. + +The broader v0.1 sequence below retains later scope: 1. **Integrate the delivered guide/task foundations.** CP08 lineage and ARCH-03B1–03B9 owner operations are delivered at the exposure boundaries @@ -692,14 +701,16 @@ Delivered foundations (not a claim of full public integration) ARCH-04E1B-B2 exact source proposal + B3 ZIP metadata + B4 checked packet custody (no dispatch/publication authority) Remaining integration - both branches: handlers 04E1B-B -> activation 04E2-B -> live 04E3 dispatch/routing + both branches: hidden handlers 04E1B-B -> authority/consequence proof 04E2-B + production false path additionally requires remediation before live activation true: own routing prerequisites; no CON/shared acceptance prerequisite selected false path first: delivered shared participant -> handler -> mandatory same-input AUTH receipt + DB complete-set closure -> TASK-before-CHECKERS race proof + shared audit/outbox -> fulfillment-root ordinal custody and authorized lifecycle activation - -> 04F remediation - -> public intake and immutable admitted Submission cutover + -> 04F hidden remediation + authorized recovery proof + -> 04E3 live composition and false-policy readiness + -> public initial/checker-remediation intake and immutable admitted Submission cutover -> automatically consume the durable current result + required checks pass | +-- locked true -> allow_review -> human Review From 58a3404922a596bf1cee4ee33bd34b5cc04bbf72 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 12:14:04 +0100 Subject: [PATCH 4/9] Reconcile next-boundary navigation and activation proof stages --- .commitrail/initiatives/WS-ARCH-001/OVERVIEW.md | 13 ++++++++----- .../initiatives/WS-ARCH-001/planning/CHUNK_MAP.md | 6 +++--- .../initiatives/WS-ARCH-001/planning/PLAN.md | 10 ++++++---- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md index 1b3e7f2b6..08e2d92eb 100644 --- a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md @@ -70,11 +70,14 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), [REV-04A](../WS-REV-001/WS-REV-001-04A.md) adds complete immutable Review, findings, resolutions and completed request storage; no decision runtime. [REV-04B](../WS-REV-001/WS-REV-001-04B.md) adds shared FinalAcceptance source storage, without AUTH receipt custody or a production writer. -- Next usable boundary: ARCH-04E1B-B hidden handlers using the delivered - REV-04C participant, then mandatory exact AUTH receipt input, database closure, - audit/outbox, TASK-before-CHECKERS currentness race proof and activation at - ARCH-04E2-B before 04E3 and ARCH-04F. Output-file - authority remains unavailable for the zero-output catalogue. +- Next usable boundary: capacity alignment and atomic initial Submission/dispatch, + then the remaining hidden 04E1B-B handlers. ARCH-04E2-B proves genuine authority + with exact receipt/database/effect closure under a valid scoped controller + generation for false. Prove ARCH-04F remediation before production false-policy + enablement and ARCH-04E3 live composition. True handoff remains independent of + CON/shared acceptance. Public intake and the first-layer drill follow the + [governing sequence](planning/PLAN.md#first-complete-contributor-milestone). + Output-file authority remains unavailable for the zero-output catalogue. [AUTH-18](../WS-AUTH-001/WS-AUTH-001-18.md) delivers public manager activation context and exact guide activation using the existing CP07 operation. [CP05A](WS-ARCH-001-CP05A.md) supplies public Finance policy administration and recoverable draft selectors. diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md b/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md index 155f3fab0..ef65dd688 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/CHUNK_MAP.md @@ -20,8 +20,8 @@ future source-identity reservation. ARCH-04E2-A delivers strict hidden resource/preparation matching and a nominal fixed-router adapter through canonical PREP while the action remains planned/unavailable. CON-07 hidden submitter participation and complete frozen award-set staging/replay are delivered. REV-04C -adds the hidden FinalAcceptance/TASK/CON participant. Hidden handlers 04E1B-B are -next. Mandatory exact same-input AUTH receipt, database complete-set enforcement, +adds the hidden FinalAcceptance/TASK/CON participant. Remaining 04E1B-B work begins with capacity alignment and atomic initial +Submission/dispatch before the hidden request/completion handlers. Mandatory exact same-input AUTH receipt, database complete-set enforcement, TASK-before-CHECKERS race proof, shared audit/outbox, fulfillment-root ordinal custody and scoped lifecycle activation remain required before production consumption. Neither phase may @@ -74,7 +74,7 @@ currentness proof stay within 04E1B-B, before activation and live composition. | [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; REV-04C uses a bounded exact-source verifier, with no general routing publication writer/reader, routing authority or current pointer; its hidden effects participant does not make false routing available | -| [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 | Both branches: delivered 04E1A/04D2/OUTBOX-02, request reservation 04E1B-A and AUTH preparation 04E2-A; exact source preparation [04E1B-B2](../WS-ARCH-001-04E1BB2.md) -> verified ZIP metadata [04E1B-B3](../WS-ARCH-001-04E1BB3.md) -> initial Submission/dispatch composition and remaining handlers/currentness proof 04E1B-B -> authority/evidence closure and activation 04E2-B -> live 04E3. False uses delivered REV-04C participation and additionally needs mandatory exact receipt/database/audit closure, fulfillment-root ordinal custody and scoped lifecycle activation; true does not depend on CON. False guide 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 | Both branches: delivered 04E1A/04D2/OUTBOX-02, request reservation 04E1B-A and AUTH preparation 04E2-A; exact source preparation [04E1B-B2](../WS-ARCH-001-04E1BB2.md) -> verified ZIP metadata [04E1B-B3](../WS-ARCH-001-04E1BB3.md) -> checked packet custody [04E1B-B4](../WS-ARCH-001-04E1BB4.md) -> capacity alignment -> initial Submission/dispatch composition and remaining handlers/currentness proof 04E1B-B -> authority/evidence closure and activation 04E2-B -> live 04E3. False uses delivered REV-04C participation and additionally needs mandatory exact receipt/database/audit closure, fulfillment-root ordinal custody and scoped lifecycle activation; true does not depend on CON. False guide 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 from required hidden 04E result/handler contracts; before false-policy activation and public 02I, without requiring live human review | diff --git a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md index eaf14ba08..e942b8e98 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md @@ -16,7 +16,7 @@ outcomes. | 2 | Input capacity within remaining ARCH-04E1B-B | Preparation and dispatch use the same bounded request rules. Oversized inputs fail before ready admission, without truncation or a stranded successful preparation. | | 3 | Initial Submission/dispatch within ARCH-04E1B-B | Submission, ART binding, exact creation/binding receipts, initial evaluation reservation and shared outbox event commit together. Fresh-authorized replay returns original identities after a lost response. | | 4 | Hidden request/completion handlers within ARCH-04E1B-B | Reuse shared outbox and CHECKERS execution. Verify exact bytes, locked policies and current generation; duplicate/stale delivery has no additional effect. | -| 5 | Authorized governed outcomes, ARCH-04E2-B and existing shared participants | Genuine authority commits with its full consequence. False/pass atomically creates FinalAcceptance, accepted TASK state, submitter ContributionRecord and applicable awards; true preserves its independent human-review handoff. Include exact receipt, database closure, audit/outbox, lock-race and required fulfillment-root custody. | +| 5 | Authorized governed outcomes, ARCH-04E2-B and existing shared participants | Genuine authority commits with its full consequence. False/pass atomically creates FinalAcceptance, accepted TASK state, submitter ContributionRecord and applicable awards; true preserves its independent human-review handoff. Include exact receipt, database closure, audit/outbox, lock-race and required fulfillment-root custody. Exercise the existing scoped controller action with a valid generation in the isolated hidden-composition proof; this does not enable the path in production. | | 6 | [Checker remediation and recovery, ARCH-04F](chunks/WS-ARCH-001-04F-checker-remediation.md) | Contributor-correctable failure has bounded findings and same-policy replacement ZIP intake. Infrastructure recovery and project/setup faults remain separate, with correct authorized retry and immutable prior evidence. | | 7 | Live composition, ARCH-04E3, and false-policy readiness | Register proven handlers; enable the false-policy path only after success, remediation and the existing scoped lifecycle activation/drain controls are proven. Preserve default-true policy and deny unsupported paths. | | 8 | Public intake, ARCH-02I | Expose initial upload/preparation, verification progress, feedback, admission-backed creation and checker-remediation resubmission through exact authorized APIs and outcome reads. Remove superseded touched paths; no provider coordinates or compatibility route. | @@ -142,9 +142,10 @@ checker-remediation boundary before public Submission cutover. | [ARCH-04E1B-B1](../WS-ARCH-001-04E1BB1.md) | REV-04C and existing CHECKERS coordinator | Complete: required TASK reservation/current-read guard, ordered admission INSERTs, exact terminal replay and mechanical race proof; no handler or activation | | [ARCH-04E1B-B2](../WS-ARCH-001-04E1BB2.md) | 04E1B-B1, existing historical PROJECTS context | Complete: exact detached source preparation and reserved identity; no publication, authority or handler effect | | [ARCH-04E1B-B3](../WS-ARCH-001-04E1BB3.md) | Existing ART inspected manifest and evidence custody | Complete: retained verified ZIP metadata and consumed-only projection; initial Submission/dispatch composition is next | +| [ARCH-04E1B-B4](../WS-ARCH-001-04E1BB4.md) | Existing intake packet commitment and hidden Submission composition | Complete: service/database checked-packet custody; capacity and initial dispatch remain next | | ARCH-04E1B-B | ARCH-04E2-A and CON-02B; false additionally uses delivered REV-04C shared acceptance participation | Hidden TASK handlers plus TASK-before-CHECKERS currentness and both successor-generation race orders; durable receipt proof follows at exact activation | -| Scoped XINT-003-08B controller activation | Existing REV-12A foundation, delivered REV-04C hidden participant and remaining real-writer observation proof | Existing Operator lifecycle-control action for the bounded shared manifest, not human runtime | -| ARCH-04E2-B | ARCH-04E1B-B; scoped XINT-003-08B controller activation for false | Require the exact AUTH receipt on the same strict input; add database complete-set and audit/outbox closure; genuine allow commits with all governed effects | +| Scoped XINT-003-08B controller activation | Existing REV-12A foundation, delivered REV-04C hidden participant and remaining real-writer observation proof | Existing Operator lifecycle-control action for the bounded shared manifest: isolated authorized proof before step 5, production enablement at step 7; not human runtime | +| ARCH-04E2-B | ARCH-04E1B-B; valid scoped XINT-003-08B controller generation in hidden false-branch proof | Require the exact AUTH receipt on the same strict input; add database complete-set and audit/outbox closure; genuine allow commits with all governed effects | | 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 | | ARCH-04E | ARCH-04E3 | Completed coordination boundary consumed by downstream REV | | ARCH-04F (before false activation and public intake) | Required hidden 04E result/handler contracts; no live false-branch prerequisite | CHECKER failure facts and TASK/ART remediation resubmission, not REV | @@ -186,7 +187,8 @@ and [CON-02B](../../WS-CON-001/OVERVIEW.md#con-02b-current-dispatcher-contract). REV-12A1 delivers disabled controller/fence mechanics, CON-07 delivers the hidden source-neutral submitter participant and complete frozen award-set owner, and REV-04C composes hidden FinalAcceptance/TASK/CON effects. The current -false-branch priority is hidden routing handlers. +false-branch priority follows the first-layer sequence: capacity alignment and +initial atomic Submission/dispatch before the remaining hidden routing handlers. Both branches have request reservation 04E1B-A and hidden AUTH preparation 04E2-A delivered before handlers 04E1B-B, activation 04E2-B and live 04E3; true routing can proceed after its own prerequisites without CON or shared acceptance. False adds those participants and scoped lifecycle activation. From 9f3e293eec358ad027aa4856d34bb402cfc8d2d7 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 12:27:53 +0100 Subject: [PATCH 5/9] Make changed-packet regressions discriminate the missing guard --- backend/tests/test_artifact_bindings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/tests/test_artifact_bindings.py b/backend/tests/test_artifact_bindings.py index e7020dc5f..d8b48bfcc 100644 --- a/backend/tests/test_artifact_bindings.py +++ b/backend/tests/test_artifact_bindings.py @@ -406,7 +406,9 @@ async def test_changed_packet_denies_before_binding_or_consumed_replay(status, f packet = SubmissionPacketView("Prepared summary", "Prepared attestation") changed = replace(packet, **{field: "Different valid contributor text"}) request = replace(original, packet_sha256=changed.sha256) - session = _session(admission, evidence, content) + binding = SimpleNamespace(id=str(new_record_id()), content_id=admission.artifact_content_id) + continuation = (binding,) if status == "consumed" else (None, datetime.now(UTC)) + session = _session(admission, evidence, content, *continuation) authority = _Allow() with pytest.raises(SubmissionAdmissionConsumptionError, match="submission_bundle_admission_unavailable"): await SubmissionAdmissionConsumptionService(session, authority).consume(request) From 50511818c2bd20e35ea7f9979c795a92edb2acd3 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 12:34:48 +0100 Subject: [PATCH 6/9] Reuse packet commitment and exercise Unicode SQL parity --- backend/app/modules/artifacts/pre_submit_attempts.py | 2 +- backend/tests/tasks/test_submission_lineage.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/app/modules/artifacts/pre_submit_attempts.py b/backend/app/modules/artifacts/pre_submit_attempts.py index ccb673c75..3a337fee6 100644 --- a/backend/app/modules/artifacts/pre_submit_attempts.py +++ b/backend/app/modules/artifacts/pre_submit_attempts.py @@ -95,7 +95,7 @@ def __reduce__(self): @property def packet_sha256(self) -> str: """Capture the packet actually passed to this claim's checker invocation.""" - return canonical_json_hash(asdict(self._request.packet)) + return self._request.packet.sha256 async def _reserved( self, diff --git a/backend/tests/tasks/test_submission_lineage.py b/backend/tests/tasks/test_submission_lineage.py index 593102837..4bdefb535 100644 --- a/backend/tests/tasks/test_submission_lineage.py +++ b/backend/tests/tasks/test_submission_lineage.py @@ -72,7 +72,7 @@ async def _prepared_packet(isolated_database_env, tmp_path): assignment_id=assignment_id, predecessor_submission_id=None, idempotency_key=new_record_id(), - summary='Completed the "required" project work in folder \\results with evidence.', + summary='Completed the "required" café project work in folder \\results with evidence.', contributor_attestation="I confirm no confidential client data, credentials, or copied source material is included in this submission; rights_confirmed. " + " ".join(policy["attestation_terms"]), media_type="application/zip", From 8beba3bddd8bc1b90134bc1b9ef801aaa5019620 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 12:42:36 +0100 Subject: [PATCH 7/9] Keep custody fixture within current packet header contract --- backend/tests/tasks/test_submission_lineage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/tests/tasks/test_submission_lineage.py b/backend/tests/tasks/test_submission_lineage.py index 4bdefb535..593102837 100644 --- a/backend/tests/tasks/test_submission_lineage.py +++ b/backend/tests/tasks/test_submission_lineage.py @@ -72,7 +72,7 @@ async def _prepared_packet(isolated_database_env, tmp_path): assignment_id=assignment_id, predecessor_submission_id=None, idempotency_key=new_record_id(), - summary='Completed the "required" café project work in folder \\results with evidence.', + summary='Completed the "required" project work in folder \\results with evidence.', contributor_attestation="I confirm no confidential client data, credentials, or copied source material is included in this submission; rights_confirmed. " + " ".join(policy["attestation_terms"]), media_type="application/zip", From dfc8441d54381463153f46ee1881400606338dc0 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 13:00:22 +0100 Subject: [PATCH 8/9] Align remaining overview fields with first contributor delivery order --- .commitrail/initiatives/WS-ARCH-001/OVERVIEW.md | 3 ++- .commitrail/initiatives/WS-AUTH-001/OVERVIEW.md | 3 ++- .commitrail/initiatives/WS-CON-001/OVERVIEW.md | 3 ++- .commitrail/initiatives/WS-POL-003/OVERVIEW.md | 3 ++- .commitrail/initiatives/WS-REV-001/OVERVIEW.md | 3 ++- README.md | 2 +- docs/roadmap_status.md | 2 +- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md index 08e2d92eb..3ebbba106 100644 --- a/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-ARCH-001/OVERVIEW.md @@ -117,7 +117,8 @@ acceptance later uses the same authorized shared acceptance/CON operation. ARCH-04E1B-B1 delivers TASK-before-CHECKERS reservation/current-read custody and ordered review admission INSERTs, including intermediate admission waits, terminal read-only replay and both mechanical race controls. The -remaining 04E1B-B handler work and full authorized currentness proof stay next; +next steps are capacity alignment and atomic initial Submission/dispatch, then +remaining 04E1B-B handlers and full authorized currentness proof; no handler or action is activated by this prerequisite. ## Delivered and remaining diff --git a/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md b/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md index c140579e7..eeea3b31c 100644 --- a/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-AUTH-001/OVERVIEW.md @@ -78,7 +78,8 @@ Historical pre-cutover work records: [`STATUS.md`](pre-cutover/STATUS.md), - Delivered storage: [REV-03B](../WS-REV-001/WS-REV-001-03B.md) freezes exact lease packets with normalized live guide ingests; no resolver or byte authority. [REV-04A](../WS-REV-001/WS-REV-001-04A.md) adds complete immutable Review, findings, resolutions and completed request storage; no decision runtime. -- Next usable boundary: hidden ARCH-04E1B-B routing handlers using the REV-04C +- Next usable boundary: capacity alignment, then atomic initial Submission/dispatch, + before hidden ARCH-04E1B-B routing handlers using the REV-04C participant; ARCH-04E2-B then owns mandatory same-input receipt custody, database closure, audit/outbox and exact routing activation before 04E3 live composition. - Governing source: `docs/spec_authorization_service.md`, authorization code, diff --git a/.commitrail/initiatives/WS-CON-001/OVERVIEW.md b/.commitrail/initiatives/WS-CON-001/OVERVIEW.md index e08be26a3..b07e1cc04 100644 --- a/.commitrail/initiatives/WS-CON-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-CON-001/OVERVIEW.md @@ -67,7 +67,8 @@ and the [capability ledger](../../../docs/roadmap_status.md). [CON-07](WS-CON-001-07.md) adds hidden source-neutral submitter participation and complete frozen award-set staging/replay; no recognition route or fulfillment operation is live. -- Next usable boundary: ARCH-04E1B-B hidden routing handlers using the shared +- Next usable boundary: capacity alignment, then atomic initial Submission/dispatch, + before ARCH-04E1B-B hidden routing handlers using the shared participant. The complete authorized operation still requires a mandatory same-input AUTH receipt, database complete-set enforcement, audit/outbox and currentness proof before either trigger can consume it in production. diff --git a/.commitrail/initiatives/WS-POL-003/OVERVIEW.md b/.commitrail/initiatives/WS-POL-003/OVERVIEW.md index 28c67d54b..dda58d796 100644 --- a/.commitrail/initiatives/WS-POL-003/OVERVIEW.md +++ b/.commitrail/initiatives/WS-POL-003/OVERVIEW.md @@ -87,7 +87,8 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), - Delivered storage: [REV-03B](../WS-REV-001/WS-REV-001-03B.md) freezes exact lease packets with normalized live guide ingests; no resolver or byte authority. [REV-04A](../WS-REV-001/WS-REV-001-04A.md) adds complete immutable Review, findings, resolutions and completed request storage; no decision runtime. -- Next usable boundary: ARCH-04E1B-B hidden handlers using the delivered +- Next usable boundary: capacity alignment, then atomic initial Submission/dispatch, + before ARCH-04E1B-B hidden handlers using the delivered REV-04C participant, then mandatory AUTH receipt/database closure and activation at 04E2-B before 04E3. ARCH-04F remediation still precedes enabling false. diff --git a/.commitrail/initiatives/WS-REV-001/OVERVIEW.md b/.commitrail/initiatives/WS-REV-001/OVERVIEW.md index 56774b0fa..7a3ecf532 100644 --- a/.commitrail/initiatives/WS-REV-001/OVERVIEW.md +++ b/.commitrail/initiatives/WS-REV-001/OVERVIEW.md @@ -44,7 +44,8 @@ of review/revision behavior. The downstream owner contracts remain separate. - Delivered storage: [REV-03B](../WS-REV-001/WS-REV-001-03B.md) freezes exact lease packets with normalized live guide ingests; no resolver or byte authority. [REV-04A](../WS-REV-001/WS-REV-001-04A.md) adds complete immutable Review, findings, resolutions and completed request storage; no decision runtime. -- Next usable boundary: ARCH-04E1B-B hidden routing handlers using the delivered +- Next usable boundary: capacity alignment, then atomic initial Submission/dispatch, + before ARCH-04E1B-B hidden routing handlers using the delivered REV-04C participant. They must prove TASK-before-CHECKERS currentness and both successor-generation race orders; human hidden behavior may continue independently behind exact AUTH, ART and CON prerequisites. diff --git a/README.md b/README.md index 7e47d677c..902a64e61 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ model. Source-agnostic does not mean every source adapter is already implemented. v0.1 remains manual-first with controlled manual, Markdown, and CSV intake. -External origin onboarding, automated routing, and execution workspaces remain +External origin onboarding, external task-routing systems, and execution workspaces remain later adapters. Revision and reassignment belong to the governed lifecycle; adjudication remains a separately approved future capability rather than a claim about current v0.1 behavior. diff --git a/docs/roadmap_status.md b/docs/roadmap_status.md index 1e25c9157..bef25a00e 100644 --- a/docs/roadmap_status.md +++ b/docs/roadmap_status.md @@ -43,7 +43,7 @@ Attributable human Review is required when the locked project mode requires it; automated acceptance records its own authorized decision and evidence instead. Marketplace expansion, blockchain settlement, external source adapters, -automated routing, agent workspaces, and runtime reputation projection remain +external task-routing systems, agent workspaces, and runtime reputation projection remain outside v0.1. ## Status Vocabulary From d8811190e41f6be9122c1303249cac0e0493e480 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Wed, 7 Oct 2026 13:02:36 +0100 Subject: [PATCH 9/9] Reconcile remaining current boundary references --- .commitrail/INDEX.md | 2 +- .commitrail/initiatives/WS-ARCH-001/planning/PLAN.md | 3 ++- .commitrail/initiatives/WS-AUTH-003/OVERVIEW.md | 6 ++++-- README.md | 3 ++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.commitrail/INDEX.md b/.commitrail/INDEX.md index 7d75c61cd..cf8aaee61 100644 --- a/.commitrail/INDEX.md +++ b/.commitrail/INDEX.md @@ -15,7 +15,7 @@ for current product capability. | [WS-CON-001](initiatives/WS-CON-001/OVERVIEW.md) | Planned | Contribution/award storage, CON-07 participation and REV-04C hidden FinalAcceptance/TASK/CON composition are delivered; production consumption still requires genuine authority, database complete-set enforcement, currentness race proof, shared audit/outbox, fulfillment-root ordinals and lifecycle activation. | | [WS-AUTH-003](initiatives/WS-AUTH-003/OVERVIEW.md) | Planned | Canonical source facts and disabled lifecycle fencing are delivered; exact lifecycle activation remains tied to the governed consequence. | | [WS-POL-003](initiatives/WS-POL-003/OVERVIEW.md) | Planned | Locked policy configuration, inert source commitments and the REV-04C hidden false/pass acceptance participant are delivered; false-policy activation remains gated by exact AUTH receipt custody, database closure, currentness proof, remediation and scoped lifecycle authority. | -| [WS-REV-001](initiatives/WS-REV-001/OVERVIEW.md) | Planned | Packet and Review storage plus REV-04C hidden source-neutral FinalAcceptance/TASK/CON composition are delivered; hidden routing handlers are next, while authority/evidence closure and human review/revision remain separately gated. | +| [WS-REV-001](initiatives/WS-REV-001/OVERVIEW.md) | Planned | Packet and Review storage plus REV-04C hidden source-neutral FinalAcceptance/TASK/CON composition are delivered; capacity alignment and atomic initial Submission/dispatch precede hidden routing handlers, while authority/evidence closure and human review/revision remain separately 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/planning/PLAN.md b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md index e942b8e98..76d4ebfaf 100644 --- a/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md +++ b/.commitrail/initiatives/WS-ARCH-001/planning/PLAN.md @@ -77,7 +77,8 @@ then live 04E3; true admission does not depend on CON/shared acceptance. ARCH-04E1B-B1 delivers TASK-before-CHECKERS reservation/current-read guards and ordered review admission INSERTs, including terminal read-only replay and both mechanical race controls. The -remaining 04E1B-B handler work and full authorized currentness proof stay next; +next steps are capacity alignment and atomic initial Submission/dispatch, then +remaining 04E1B-B handlers and full authorized currentness proof; no handler or action is activated by this prerequisite. ## Current dependency contract diff --git a/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md b/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md index dbe80602e..d3311c781 100644 --- a/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md +++ b/.commitrail/initiatives/WS-AUTH-003/OVERVIEW.md @@ -22,8 +22,10 @@ Exact pre-cutover work record: [`STATUS.md`](pre-cutover/STATUS.md), - Delivered storage: [REV-03B](../WS-REV-001/WS-REV-001-03B.md) freezes exact lease packets with normalized live guide ingests; no resolver or byte authority. [REV-04A](../WS-REV-001/WS-REV-001-04A.md) adds complete immutable Review, findings, resolutions and completed request storage; no decision runtime. -- Next usable boundary: for the selected automated-acceptance delivery sequence, continue canonical boundary recovery through CON-07/shared acceptance - foundations and later ARCH-04E1B-B/04E2-B/04E3 routing. +- Next usable boundary: follow the [first contributor milestone](../WS-ARCH-001/planning/PLAN.md#first-complete-contributor-milestone): + capacity alignment and atomic initial Submission/dispatch before hidden handlers + and exact authority/effect closure. CON-07/shared acceptance foundations are + delivered; production consumption and scoped lifecycle activation remain gated. 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/README.md b/README.md index 902a64e61..01443b268 100644 --- a/README.md +++ b/README.md @@ -737,7 +737,8 @@ without creating a REV queue dependency. The false branch binds exact without fabricating a Review. CON-07 now supplies the hidden source-neutral submitter participant and complete frozen award-set staging/replay. REV-04C now composes FinalAcceptance, TASK terminal effects and that CON participant in one -hidden caller-owned transaction for either source. Hidden handlers are next. +hidden caller-owned transaction for either source. Capacity alignment and atomic +initial Submission/dispatch come next, before the hidden handlers. The mandatory exact AUTH receipt must become required on the same strict input, with no optional/default path, before production consumption; database FinalAcceptance/TASK/CON closure, TASK-before-CHECKERS race proof, shared