diff --git a/.agent-loop/REVIEW_LOG.md b/.agent-loop/REVIEW_LOG.md index c785d0f1..e5070555 100644 --- a/.agent-loop/REVIEW_LOG.md +++ b/.agent-loop/REVIEW_LOG.md @@ -1,5 +1,19 @@ # Review Log +## 2026-07-17 - WS-CON-001-PLAN3 External Review Repair Started + +CodeRabbit posted five consolidated actionable threads and one PR-description +warning on PR #142 after the AUTH/REV current-main reconciliation became ready +for review. The bounded planning-only repair adds deterministic executable +verification gates to 16 active future chunks, moves AUTH registration/context/ +custody/prepared-port requirements into upstream handoffs, preserves the +canonical registration -> hidden behavior -> activation order, and moves +optional CON-09B out of executable `chunks/` as a zero-file deferred proposal +pending separate ART/AUTH/human approval and a fresh contract. It also aligns +the PR trust bundle with the repository template. No runtime successor is +active; exact-SHA internal re-review, evidence rebind, external check rerun, and +thread disposition remain required before merge readiness. + ## 2026-07-17 - WS-AUTH-001-09A Convergence Started After PR #140 merged as `d541521` and signed memory stopped, the user explicitly diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/ARTIFACT_STORAGE_HANDOFF.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/ARTIFACT_STORAGE_HANDOFF.md new file mode 100644 index 00000000..590985b4 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/ARTIFACT_STORAGE_HANDOFF.md @@ -0,0 +1,68 @@ +# Optional Artifact Projection Handoff: WS-CON-001 + +## Status + +Deferred and not approved for implementation. Merged WS-XINT-001 D7 and +`REV_CON_HANDOFF.md` supersede the earlier mandatory contribution-evidence +design. + +## Core boundary + +Core Review/ContributionRecord creation has no synchronous or asynchronous ART +prerequisite. REV supplies the stabilized versioned Submission/packet artifact +digest through locked canonical facts. CON copies that value into +`ContributionRecord.artifact_hash` and does not load, verify, rehash, bind, or +project artifact bytes. + +ART outage or integrity uncertainty may block a Review only where REV's own +stabilized packet contract requires it before judgment. Once REV supplies the +canonical decision facts, CON does not call ART and cannot translate storage +failure into `needs_revision`, `reject`, a missing contribution, or a missing +award. + +## Optional future projection + +A deterministic contribution-evidence document may be proposed later as a +post-commit asynchronous projection. If approved: + +- projection status and failure lifecycle remain separate from Review, + ContributionRecord, CompensationAward, CompensationFulfillmentReceipt, and + CompensationStatusProjection truth; +- CON owns deterministic document semantics and the projection relation only; +- ART owns preparation, scratch, admission, provider execution, verification, + binding, receipts, recovery, retention, and provider abstraction; +- AUTH owns the exact optional action, fixed service admission, evaluator, and + activation; +- PostgreSQL remains canonical; the artifact is an export, not source truth; +- storage failure is retryable projection failure and never a product rollback. + +## Required fresh approval + +CON-09A/09B cannot start from this planning document alone. A future chunk must +refresh and internally review: + +- the then-current ArtifactStore v2/admission/verification/recovery contracts; +- one named ART write capability and, independently, any read capability; +- exact document schema, media type, retention, disclosure, and replay rules; +- one separately registered optional binding ActionId mapped to the stable + `artifact.binding.create` PermissionId; +- exact extension of the existing `workstream.artifact.binding` static service + row, controlled provisioning, AUTH-09E admission, and activation sequence; +- cancellation, commitment drift, idempotency, provider ambiguity, cleanup + custody, and cross-project disclosure proof. + +PR #129 supplies only inactive committed-source preparation. It does not +approve a contribution-evidence port, admission, provider execution, +verification, binding, read, or retention contract. + +## Prohibited coupling + +- No evidence row/event in CON-07. +- No CON-09A/09B prerequisite for CON-10A/B or CON-11. +- No ART prerequisite in the core chunk dependency order or joint live drill. +- No raw ArtifactStore, scratch manager, prepared/committed source, provider + reference, path, credential, or ART repository crossing into CON. +- No optional evidence action counted as a core WS-CON action. +- No storage outcome mutating canonical contribution or award truth. + +This handoff changes no runtime and starts no optional projection work. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/AUTHORIZATION_HANDOFF.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/AUTHORIZATION_HANDOFF.md new file mode 100644 index 00000000..f1bd4e01 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/AUTHORIZATION_HANDOFF.md @@ -0,0 +1,273 @@ +# Authorization Handoff: WS-CON-001 + +## Current baseline + +Trusted `main` is `0302bcf` from merged REV PR #128. It contains AUTH-09A after +AUTH PR #140 and the earlier WS-XINT PR #139 boundary. The runtime catalogue now +contains 74 PermissionIds and 65 ActionIds: nine active and 56 planned. The +eight added planned actions belong to AUTH-09 service-identity administration; +no WS-CON-specific or task-claim ActionId below is registered. PR #140 still +defines the prepared/custody plan; it does not implement AUTH-PREP, transfer +ART/REV custody, register a CON action, or activate a feature action. + +AUTH owns identifiers, stable mappings, activation custody, typed resource and +principal contexts, grants, fixed ServiceIdentity/static matrix, AUTH-09E +admission, prepared mutation handles, evaluator dispatch, decision evidence, +availability, and parity. CON owns canonical product loaders, typed resource +facts, lifecycle guards, hidden behavior, and feature tests. Neither side +imports the other's repositories or mutates the other's state. + +## Required delivery sequence + +Every protected CON surface follows: + +```text +AUTH registration checkpoint + planned ActionId + stable PermissionId + AUTH ActionOwner + principal class + typed context + prepared protocol when mutating +-> CON hidden-behavior checkpoint + canonical resource loader + guards + behavior, real kernel still denies +-> AUTH activation checkpoint + exact evaluator + matched authority + negative proof + active availability +-> joint release checkpoint +``` + +Registration, provisioning, matrix membership, feature behavior, and activation +are distinct. A provisioned service cannot execute a planned action. CON cannot +turn a fake/test decision into a production allow path. + +## Principal models + +### Human + +- task.claim: exact active same-project `submitter` ProjectRoleGrant; +- review.claim and review.decision: exact active same-project `reviewer` + ProjectRoleGrant plus no-self-review and lifecycle guards; +- contribution self/award self: exact actor-self relationship; +- administrative policy, binding, project reads, and operations: one exact + eligible AdminRoleGrant selected by the action evaluator. + +The shipping path consumes exact `submitter` and `reviewer` grants. There is no +combined grant and no unrelated project/admin grant substitutes. WS-CON adds no +adjudication grant or action and has no adjudication readiness dependency; any +separate global project-role catalogue state remains AUTH-owned and outside +this transaction. + +FinalAcceptance creation has no ActionId. It is an internal REV-owned +consequence of an already-authorized `review.decision` with `accept`; CON only +validates and consumes the locked fact when creating `accepted_submission`. + +### Fixed service + +The only service admission path is: + +```text +verified service token +-> active ActorIdentityLink +-> active service ActorProfile +-> immutable closed ServiceIdentity +-> exact static service-action matrix membership +-> AUTH-09E typed service AuthorizationContext +-> CON-composed canonical ResourceContext +-> decision +``` + +There is no database service grant or action-assignment row. AUTH locks the +profile/link and validates unchanged ServiceIdentity, static membership, and +active action. Human grants cannot satisfy service actions and services cannot +use human grant candidates. Missing provisioned rows deny the request and block +release readiness, but do not fail application startup or provisioning. + +## Prepared mutation protocol + +For `T` actions AUTH locks canonical current human actor/link/exact-grant or +fixed-service actor/link authority first and returns one opaque, +non-serializable `PreparedAuthorizationHandle`. The handle is bound exactly to +the caller session, ActionId, actor-reference kind, actor reference, +idempotency key, and canonical request digest. ServiceIdentity, static matrix +membership, and availability are code-owned validations after profile/link +locks, never database lock targets. CON or the owning feature then locks +product rows in the canonical order and recomposes final typed facts; AUTH +consumes the handle, evaluates once, and stages decision evidence. AUTH and all +feature participants flush only; the route/executor/callback command commits +once. Reused, serialized, caller-constructed, cross-session/action/actor/ +request, binding-mismatched, or authority-lost handles deny before product +mutation. A failed substitution attempt does not consume an otherwise valid +handle. + +`Q` reads use request-scoped require plus canonical CON loaders, pre-filtered +pagination, and concealment. No authorization result or grant cache survives a +request. + +## Proposed core action mappings + +These 22 feature-surface mappings preserve existing stable PermissionIds except +for the two explicitly proposed service-only PermissionIds. They are product +proposals, not registered runtime, and they are not a final action count until +the protected execution boundaries are approved. Policy ActionIds use the +canonical `contribution.policy.*` namespace while retaining stable +`compensation.policy.manage` PermissionId compatibility. + +| Proposed ActionId | PermissionId | Principal / target | Protocol | Feature owner | +|---|---|---|---:|---| +| `outbox.dispatch` | proposed `outbox.dispatch` | fixed outbox dispatcher / claimed event | T | shared outbox 02B | +| `compensation.adapter_binding.read` | `compensation.adapter_binding.manage` | Finance / ProjectCompensationAdapterBinding | Q | CON-04A | +| `compensation.adapter_binding.create` | `compensation.adapter_binding.manage` | Finance / project binding collection | T | CON-04A | +| `compensation.adapter_binding.suspend` | `compensation.adapter_binding.manage` | Finance / active binding | T | CON-04A | +| `compensation.adapter_binding.resume` | `compensation.adapter_binding.manage` | Finance / suspended binding | T | CON-04A | +| `compensation.adapter_binding.retire` | `compensation.adapter_binding.manage` | Finance / dependency-free binding | T | CON-10B | +| `contribution.policy.read` | `compensation.policy.manage` | Finance / ContributionPolicyVersion | Q | CON-04B | +| `contribution.policy.create_draft` | `compensation.policy.manage` | Finance / project policy collection | T | CON-04B | +| `contribution.policy.update_draft` | `compensation.policy.manage` | Finance / draft version | T | CON-04B | +| `contribution.policy.publish` | `compensation.policy.manage` | Finance / complete draft version | T | CON-04B | +| `contribution.policy.retire` | `compensation.policy.manage` | Finance / published version | T | CON-04B | +| `compensation.fulfillment.report` | proposed `compensation.fulfillment.report` | exact bound service / award and binding | T | CON-08B | +| `contribution.read_self` | `contribution.read_self` | contributor / own record | Q | CON-10A | +| `contribution.read_project` | `contribution.read_project` | exact eligible AdminRole / project collection | Q | CON-10A | +| `compensation.award.read_self` | `contribution.read_self` | beneficiary / own award | Q | CON-10A | +| `compensation.award.read_project` | `compensation.award.read` | D11 role set / project award collection | Q | CON-10A | +| `compensation.delivery.reconcile` | `compensation.delivery.reconcile` | D11 role set / delivery request | T | CON-10B | +| `compensation.status.read` | `operations.status.read` | Operator / bounded status | Q | CON-10B | +| `compensation.reconcile.run` | `operations.reconcile.run` | reason-bound Operator / durable request | T | CON-10B | +| `contribution.projection.rebuild` | `operations.projection.rebuild` | reason-bound Operator / durable request | T | CON-10B | +| `audit.read` | `audit.read` | D11 role set / bounded WS-CON audit | Q | CON-10B | +| `audit.export` | `audit.export` | D11 role set / bounded export | T | CON-10B | + +PR #140 approves no `AUTH_CON_*` owner identifiers. After a complete +feature-owned manifest exists, AUTH must assign each registered action to one +exact future `WS-AUTH-001-*` activation chunk and prove unchanged mapping plus +planned availability. CON must not predict or add ActionOwner enum values. + +## Core resource guards + +- Policy publish locks one active ContributionPolicy selector, draft version, + both exact ContributionRules, award definitions, and referenced active same- + project/instrument bindings. Published content is immutable. +- Binding create validates canonical service actor, approved adapter capability, + project/instrument, and non-secret route identity. Suspend blocks new freezes + and deliveries but preserves valid callbacks for already-issued awards. +- Binding retire denies any active policy reference, unfinished frozen + assignment/lease, or unfulfilled award. After retirement only exact replay of + a previously accepted receipt may be acknowledged. +- Contribution self/project and award self/project reads use canonical record + ownership, pre-filtered project scope, stable pagination, and concealment. + They expose no provider reference, secret, balance, or ledger data. +- Callback requires exact actor/link/ServiceIdentity/static row, binding route, + award, project, instrument, and receipt-state match. Rate limits bind actor + plus binding, not shared IP alone. +- Reconciliation/rebuild create bounded durable requests and never repair + immutable contribution, award, or receipt truth. + +## Service execution gaps that must be closed + +The 22 mappings above cover human/public queries, management requests, the +callback, and generic outbox dispatch. They do not authorize protected feature +handler execution. `workstream.outbox.dispatcher` with `outbox.dispatch` can +only claim, invoke, and finalize events; it cannot transitively receive every +handler's mutation/provider authority. + +Before CON-02B/08A/10C protected execution, AUTH and the human must approve +exact ServiceIdentity/ActionId/static-row contracts. CON-08B independently +requires the authenticated callback identity/action/static-row contract: + +| Boundary | Discovery candidate identity | Discovery candidate action | Required result | +|---|---|---|---| +| outbox mechanics | `workstream.outbox.dispatcher` | `outbox.dispatch` | exact closed identity and singleton static row | +| outbound fulfillment delivery | `workstream.compensation.delivery` | `compensation.delivery.execute` | independent feature authority; never inherited from dispatcher | +| async compensation reconciliation | `workstream.compensation.reconciler` | `compensation.reconcile.execute` | exact bounded execution action or approved dual-principal evaluator | +| async contribution projection rebuild | `workstream.contribution.projection_rebuilder` | `contribution.projection.rebuild.execute` | exact bounded execution action or approved dual-principal evaluator | +| fulfillment callback | `workstream.compensation.fulfillment_reporter` | `compensation.fulfillment.report` | one approved fixed identity/static row or an explicitly specified closed set | + +Candidate strings are not approved identifiers. If AUTH reuses an existing +request ActionId for fixed-service execution, it must specify a closed dual- +principal evaluator and prove human/service isolation. CON must not infer that +design. Each new identity requires closed enum/static-matrix changes, controlled +ActorProfile/ActorIdentityLink provisioning, service_identity constraint +migration custody, AUTH-09E admission, exact cross-service negative tests, and +activation only after hidden behavior merges. + +## Upstream review and task actions + +Only the stable `task.claim` PermissionId exists on trusted main; there is no +registered task-claim ActionId among the 65 actions. AUTH-PREP, the exact +submitter grant, and the task-owned claim seam precede CON-05A's hidden freeze +participant. CON-05A and task-owned composition must merge first. AUTH-13 then +enumerates/registers the exact task-claim ActionId, integrates its evaluator, +and activates only after the immutable ContributionPolicyVersion freeze and +rollback proof exist. +`review.claim` and `review.decision` are current planned actions; CON-06/07 +provide hidden participants, REV supplies canonical composition, and AUTH +activates only after the complete behavior merges. + +### Required AUTH follow-up from PR #140 + +- The current `WS-AUTH-001-13` contract owns future task-claim ActionId + enumeration/registration, activation, and exact submitter-grant evaluation, + but it does not yet name the CON-05A TaskAssignment + ContributionPolicyVersion freeze as a prerequisite. Its executable refresh + must consume the merged CON-05A manifest and prove task-owned participant + composition before it registers/activates that action. +- Future CON registration contracts must choose exact `WS-AUTH-001-*` + activation custodians from complete feature manifests. The removed + `AUTH_CON_*` planning labels are not approved ActionOwner values. +- `review.claim` activation must consume CON-06 through REV's hidden claim + composition. PR #140 already states that `review.decision` activation + requires the merged mandatory CON participant and one rollback-safe REV+CON + transaction; no additional FinalAcceptance action is needed. + +These are upstream AUTH contract gates. CON does not edit AUTH files, register +identifiers, integrate evaluators, or change availability. + +AUTH must reconcile all 19 current review actions as one complete activation- +custody transfer under `WS-XINT-001/AUTH_REV_HANDOFF.md`. WS-CON declares only +its two dependencies and must not remove or retain individual REV ActionOwner +members locally. The four proposed additive review actions remain absent until +their own registration contract. + +Likewise, the complete 25-action ART transfer belongs to +`WS-XINT-001/AUTH_ART_HANDOFF.md`. WS-CON has no core ART dependency and does not +repeat an eleven-action subset. + +## Optional evidence action + +If optional contribution-evidence projection is separately approved, one +additional action may be proposed: + +```text +artifact.contribution_evidence.binding.create + -> existing artifact.binding.create + -> existing workstream.artifact.binding ServiceIdentity +``` + +AUTH would extend that identity's static row by exactly this action only after a +reviewed ART capability contract exists. This optional action is outside the 22 +core proposal and outside release readiness. It cannot be used to authorize +core ContributionRecord creation or reads. + +## D11 AdminRole decisions + +Before CON-10A/10B registration, the human must choose exact candidates for: + +- Project Manager inclusion in project award detail; +- reason-bound Operator delivery recovery in addition to Finance Authority; +- audit read/export role sets. + +Any difference from merged AUTH definitions is implemented by AUTH through an +action-owned closed role intersection before grant query. Mixed eligible and +excluded grants select only the eligible grant. CON receives matched decision +evidence and contains no role branch. + +## Activation and release proof + +AUTH proof must cover planned denial, exactly one custodian per action, +PermissionId parity, evaluator/context completeness, exact human grants, +ServiceIdentity/static-matrix membership, AUTH-09E admission, cross-service +denial, same-token revocation, prepared-handle misuse, transaction-time +revalidation, and decision-evidence failure. Feature proof covers canonical +facts, lifecycle guards, commit/rollback, and no AUTH persistence import. + +Startup may fail on closed code/catalogue/static-matrix/evaluator/active- +behavior drift. Runtime and release readiness deny on missing provisioned +service rows. Administrative provisioning remains available. + +This handoff changes no AUTH runtime and starts no AUTH or CON chunk. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/CHUNK_MAP.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/CHUNK_MAP.md new file mode 100644 index 00000000..3e96ed0b --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/CHUNK_MAP.md @@ -0,0 +1,139 @@ +# Chunk Map: WS-CON-001 Contribution Record And Compensation Boundary + +## Rule + +One chunk maps to one reviewable PR. No runtime chunk starts until its exact +AUTH, REV, outbox, migration, and human gates are satisfied on trusted `main`. +AUTH owns activation custody; feature ownership never supplies a second +availability writer. Optional evidence chunks are not part of the core order. + +## Chunks + +| Chunk | Title | Risk | Gate | Status | +|---|---|---:|---|---| +| `WS-CON-001-PLAN` | Contribution And Compensation Planning | L0 | None | Complete; unpublished | +| `WS-CON-001-PLAN2` | Final Acceptance Reconciliation | L0 | Human FinalAcceptance/no-adjudication direction | Complete; unpublished | +| `WS-CON-001-PLAN3` | AUTH/REV Current-Main Reconciliation | L0/L1 | Merged AUTH PR #140 plus AUTH-09A and REV PR #128 at `0302bcf` | Complete; unpublished | +| `WS-CON-001-01` | Canonical Contract Adoption And Architecture Decision | L0/L1 | Reconciled plan and human decisions approved | Proposed | +| `WS-CON-001-02A` | Shared Transactional Outbox Persistence | L1 | 01; event ownership approved | Proposed | +| `WS-CON-001-02B` | Shared Outbox Dispatcher And Recovery | L1 | 02A; AUTH registers `outbox.dispatch`, approved `workstream.outbox.dispatcher` ServiceIdentity/static row, AUTH-09E admission, prepared protocol; dispatcher remains disabled until AUTH activation | Proposed | +| `WS-CON-001-02C` | Shared Lifecycle Audit Participant | L1 | 02B; current AuditEvent contract refreshed | Proposed | +| `WS-CON-001-03A` | Project Compensation Adapter-Binding Persistence | L1 | 02C; migration head refreshed | Proposed | +| `WS-CON-001-03B` | Contribution Policy Persistence | L1 | 03A; legacy-data rule; must precede REV-03 ReviewLease FK | Proposed | +| `WS-CON-001-03C` | Contribution And Award Persistence | L1 | 03B; merged REV-04 runtime FinalAcceptance/Review/ReviewLease FK targets | Proposed | +| `WS-CON-001-03D` | Delivery, Receipt, And Status Persistence | L1 | 03C; immutable fulfillment root ordinal/generation contract | Proposed | +| `WS-CON-001-04A` | Hidden Adapter-Binding Service | L1 | 03A; planned AUTH binding actions/contexts/prepared protocol; callback ServiceIdentity/action/static row approved but inactive | Proposed | +| `WS-CON-001-04B` | Hidden Contribution-Policy Service | L1 | 03B, 04A; binding activation merged; planned `contribution.policy.*` actions/contexts/prepared protocol | Proposed | +| `WS-CON-001-05A` | Legacy Economic Terms Cutover And Task Freeze | L1 | 04B; exact Submission/TaskAssignment lineage; AUTH-10 exact submitter grants and AUTH-PREP merged; task.claim PermissionId exists but ActionId remains absent; stable task-owned claim seam; legacy rule | Proposed | +| `WS-CON-001-05B` | Legacy Economic Schema Removal | L1 | 05A; zero-consumer scan; removal migration approval | Proposed | +| `WS-CON-001-06` | Review-Lease Contribution-Policy Freeze Capability | L1 | REV lease schema; 05B; AUTH-PREP; planned review.claim typed contract; exact reviewer grant facts stable | Proposed | +| `WS-CON-001-07` | Atomic Contribution/Award Decision Participant | L1 | 03C-D, 05A, 06; AUTH-PREP and complete REV custody transfer; REV-04 FinalAcceptance plus REV-09B locked lineage; shared audit/outbox; planned review.decision typed contract; two ordered operation-specific inputs | Proposed | +| `WS-CON-001-08A` | Outbound Compensation Delivery Handler | L1 | 07, 02B; exact delivery ServiceIdentity/ActionId/static row registered but planned; AUTH-09E typed context/prepared protocol; ADR 0014 adapter foundation; lifecycle-fence port | Proposed | +| `WS-CON-001-08R` | Bound-Service Callback Rate Control | L1 | 08A; shared API-control contract | Proposed | +| `WS-CON-001-08B` | Inbound Fulfillment Callback | L1 | 08R; exact callback ServiceIdentity/ActionId/static row, AUTH-09E context, prepared protocol, and callback-fence port | Proposed | +| `WS-CON-001-09A` | Optional Contribution Evidence Projection Write | L1 | Separate human approval; refreshed ART/AUTH contract and chunk review | Deferred optional | +| `WS-CON-001-09B` | Optional Authorized Contribution Evidence Read | L1 | 09A plus separate approval; refreshed disclosure contract | Deferred optional | +| `WS-CON-001-10A` | Contribution And Award Product Reads | L1 | 08B; D11 award-role outcome; planned contribution/award read actions and typed contexts | Proposed | +| `WS-CON-001-10B` | Operations Requests, Reads, And Fulfillment Drain Observation | L1 | 10A; D11 complete; operations request/read actions/contexts/prepared protocol; outbox observation port | Proposed | +| `WS-CON-001-10C` | Reconciliation And Projection Executors | L1 | 10B; exact executor identities/actions/static rows; AUTH-09E; hidden behavior then AUTH activation | Proposed | +| `WS-CON-001-11` | Hidden Release Readiness And Dependency Manifest | L1 | 10C; merged REV-10 decision integration; exact AUTH evaluator/action/service manifest; every obligation-writer/dispatch/callback hook; monotonic root ordinal; same-session cutoff/drain port | Proposed | + +## Core dependency order + +```text +PLAN -> PLAN2 -> PLAN3 -> 01 -> 02A -> 02B -> 02C -> 03A -> 03B -> 03C -> 03D +-> 04A -> 04B -> 05A -> 05B -> 06 -> 07 -> 08A -> 08R -> 08B +-> 10A -> 10B -> 10C -> 11 +``` + +Optional successor, not a branch in the core release: + +```text +separate human approval -> refreshed ART/AUTH handoff -> 09A -> 09B +``` + +## Cross-initiative gates + +```text +AUTH registration -> CON hidden behavior -> AUTH activation -> later consumer/release +``` + +- AUTH-09A through 09E must precede protected fixed-service execution. New CON + ServiceIdentity/static-row additions require separate reviewed AUTH contracts; + provisioning never activates a feature action. +- The outbox dispatcher owns only claim/invoke/finalize under + `outbox.dispatch`. Each protected handler has independent approved authority. +- Task claim requires AUTH-PREP and one exact active same-project submitter + grant. CON-05A first lands the hidden freeze participant; task-owned claim + composition consumes it after task/assignment locks; `WS-AUTH-001-13` then + enumerates/registers the exact ActionId, integrates its evaluator, and + activates. Registration/activation before that freeze proof is prohibited. +- Review claim requires one exact active same-project reviewer grant. CON-06 + supplies only the freeze port; REV supplies hidden claim composition; AUTH + activates review.claim after both merge. +- Review decision requires the reviewer grant and no-self-review/lifecycle + guards. CON-07 starts only after the TaskAssignment submitter freeze and REV + ReviewLease reviewer freeze plus accept-only FinalAcceptance persistence and + locked decision-lineage contract are merged with non-null policy-version + lineage. CON-07 then supplies the flush-only participant with no ART/evidence + work; REV consumes that participant in hidden decision composition, stages + shared audit/outbox, and owns the single commit. AUTH activates + `review.decision` only after that hidden REV composition merges. +- CON-07 creates contributions and applicable awards in the Review transaction. + Reviewer work is sourced from Review; submitter work is sourced only from + REV-owned FinalAcceptance. REV stages shared audit/outbox rows, owns the + single commit, and supplies stabilized artifact-hash lineage; no ART call is + made. +- Merged REV PR #128 is planning authority, not runtime readiness. CON-03B must + precede REV-03; CON-02A/02C precede REV-04; REV-04 precedes CON-03C; CON-06 + precedes REV-06; REV-09B plus CON-03C/07 precede REV-10; and CON-11's exact + obligation hooks/ordinal/drain manifest precedes REV-12A. +- CON-08A/B and 10C cannot reuse outbox dispatcher authority for delivery, + callback, reconciliation, or rebuild execution. +- CON-10A owns core PostgreSQL contribution/award reads directly; it does not + wait for optional evidence reads. +- CON-11 has no ART or evidence-projection prerequisite. It hands mandatory + obligation-writer, dispatch, callback, maximum-ordinal, and drain-observation + seams to REV-12A's single shared lifecycle controller and registers no route. +- AUTH PR #140's complete ART and REV activation-custody transfer contracts are + consumed by reference to AUTH/WS-XINT handoffs. The runtime transfers remain + upstream gates; WS-CON does not define partial subsets. + +## Chunk boundaries + +- 01 owns current specification/ADR adoption and scanner-safe active wording; + it does not edit archival inputs. +- 02A owns persistence/append; 02B owns generic dispatcher mechanics only; 02C + owns the shared caller-transaction audit participant. +- 03A uses `ProjectCompensationAdapterBinding`; 03B owns ContributionPolicy, + versions, rules, and award definitions; 03C/D own contribution/award and + downstream fulfillment records respectively. 03C references but never owns + REV's FinalAcceptance. +- 04A/04B add hidden binding and policy services while AUTH actions remain + planned. +- 05A removes semantic consumers and freezes task assignments; 05B removes dead + physical schema. +- 06 exposes only a CON policy-freeze capability; REV owns ReviewLease schema + and wiring. +- 07 exposes only the flush-only decision participant; REV owns Review, + FinalAcceptance, shared audit/outbox staging, and the single commit. No + evidence projection is staged. +- 08A is a feature handler with its own protected execution boundary; 08R owns + rate-control scope; 08B owns callback authentication/composition. +- 09A/09B are deferred optional projection chunks and must be re-reviewed if + activated later. +- 10A owns core PostgreSQL product reads; 10B owns bounded operations requests + and typed drain observation; 10C owns independently authorized executors. +- 11 proves hidden readiness and blocks runtime requests on missing provisioned + service rows while leaving application startup and provisioning available. + +## Required reviewer tracks + +Every chunk: senior engineering, QA/test, security/auth, product/ops, +architecture, docs, and reuse/dedup. Runtime/test chunks add test-delta. Add CI +integrity for workflows, scripts, dependencies, test configuration, or coverage. + +## Stop condition + +Planning ends after required plan review and human discussion. Do not start 01, +09A, or any runtime chunk automatically. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/CONFORMANCE_MATRIX.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/CONFORMANCE_MATRIX.md new file mode 100644 index 00000000..d33d3481 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/CONFORMANCE_MATRIX.md @@ -0,0 +1,24 @@ +# Conformance Matrix: WS-CON-001 + +| Family | Owning chunks | Required proof | Final gate | +|---|---|---|---| +| Canonical policy model | 01,03B,04B | ContributionPolicy/version/rules/definitions; explicit unpaid; immutable publish; one active policy; stable binding references | CON-11 | +| Legacy clean cut | 05A,05B | zero semantic consumers before schema removal; deterministic row treatment; no alias/fallback; migration upgrade/downgrade | CON-11 | +| Authorization | AUTH + each feature | current 74-65-9-56 baseline after AUTH-09A; proposed mappings remain unregistered; full ART/REV custody referenced; one future AUTH custodian; planned denial; exact grant/static row; AUTH-09E; prepared handle bound to session/action/actor-ref/idempotency/request digest with substitution non-consumption; no local role logic | AUTH activation + CON-11 | +| Final acceptance | REV + 03C,07 | accept creates one immutable FinalAcceptance per task/Review/Submission; needs_revision/reject create none; no create API/action, reopen, replacement, or adjudication path | joint live drill | +| Contribution cardinality | 03C,07 + REV | one completed_review per valid Review with direct Review/lease lineage; one accepted_submission per FinalAcceptance with assignment lineage; mutually exclusive sources; revision Reviews distinct; automated outcomes create none | joint live drill | +| Policy freeze | 05A,06 + task/REV | exact submitter/reviewer fields; published version; no drift; publish/suspend races both orders | joint live drill | +| Award evaluation | 03C,07 | matching frozen ContributionRule; unpaid creates none; at most one money/points; exact decimal; replay stable | joint live drill | +| Atomic REV/CON | 07 + REV | reviewer operation before branch; accept-only submitter operation after FinalAcceptance/accepted effects; stabilized digest; REV stages audit/outbox; CON flushes contributions/awards; zero ART calls; complete rollback | REV-10 + joint live drill | +| Outbox isolation | 02A,02B | stable event/task IDs; claim fencing; retry/dead-letter/replay; dispatcher cannot inherit feature authority; handler returns typed outcome | CON-11 | +| Delivery and callback | 08A,08R,08B | exact feature service authority; no I/O under locks; callback/binding/award match; replay and callback-before-ack; immutable receipts | joint live drill | +| Product reads | 10A | PostgreSQL contribution/award truth; D11 exact role sets; stable pagination/concealment; no ART/provider data | AUTH activation + joint drill | +| Operations requests and observation | 10B | bounded durable requests; AdminRole and prepared-protocol proof; audit redaction; same-session outbox/fulfillment counts plus maximum immutable root ordinal; no executor authority | REV-12A + joint drill | +| Operations executors | 10C | exact independent fixed-service authority; dispatcher/cross-executor denial; retry/replay/finding proof; projection-only rebuild mutation; immutable contribution/award/receipt truth | AUTH activation + joint drill | +| Public release | 11 + REV | hidden before release; exact `/api/v1` manifest; provisioning-aware readiness; no optional evidence/ART gate | joint live drill | +| Fulfillment cutoff | 03D,08A/B,10B/C,11 + REV-12A | one immutable monotonic ordinal per obligation root; shared fence before every writer; persisted generation cutoff; same-generation at-or-below-cutoff completion only; no provider I/O under fence | independent-session writer/dispatch/callback races | +| Optional evidence | 09A,09B only if approved | separately reviewed ART/AUTH capability; independent status/failure; no effect on canonical truth or core release | separate optional release | +| No adjudication | all core | only accept/needs_revision/reject; no adjudication grant/action/state/queue/lease/decision/contribution/branch/readiness or initiative dependency | CON-11 + joint drill | + +Executable node IDs and retained evidence are added by each implementation +chunk. Planning rows are contracts, not claims that tests already ran. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/DECISIONS.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/DECISIONS.md new file mode 100644 index 00000000..7f8a204a --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/DECISIONS.md @@ -0,0 +1,275 @@ +# Decisions: WS-CON-001 Contribution Record And Compensation Boundary + +## D1 - Canonical Contract Is Repository-Owned + +**Status:** accepted. + +The supplied reference files are archival inputs. The active implementation +contract is the repository specification produced by CON-01 and reconciled with +trusted `main`, including AUTH PR #140 and WS-XINT-001 PR #139. Archival files +are not edited or treated as runtime authority. + +## D2 - ContributionPolicy Is The Only Award-Eligibility Policy + +**Status:** accepted; supersedes the older WS-CON naming. + +The canonical aggregate is `ContributionPolicy`, immutable +`ContributionPolicyVersion`, `ContributionRule`, and +`ContributionAwardDefinition`. It decides whether a ContributionRecord is +unpaid or creates money and/or project-points CompensationAwards. The retired +guide-bound economic schema is completely removed in CON-05A/05B. There is no +alias, automatic conversion, historical fallback, or second executable policy. + +## D3 - Existing Submission Is The Version Identity + +**Status:** accepted. + +Existing `Submission` plus its `version` and `supersedes_submission_id` is the +versioned identity. ContributionRecord uses `submission_id` and the stabilized +artifact-hash lineage supplied by REV. WS-CON does not add a +`SubmissionVersion` table or reload artifact bytes through ART. + +## D4 - AUTH Owns Registration, Evaluation, And Activation + +**Status:** accepted by WS-XINT-001 D1/D2. + +WS-CON proposes product actions and typed facts, but AUTH owns ActionId, +PermissionId mapping, ActionOwner activation custody, typed resource contexts, +principal admission, evaluator dispatch, decision evidence, grants, the fixed +service static matrix, and availability. Each action follows planned +registration -> hidden feature behavior -> AUTH evaluator integration and +activation. CON never changes availability or implements a local role fallback. + +The stable PermissionIds may retain older broad namespace strings. New policy +ActionIds use `contribution.policy.*` and map to existing +`compensation.policy.manage`; the PermissionId string does not rename the +canonical product model. + +## D5 - Derived Contributions And Awards Are Review Participants + +**Status:** accepted by WS-XINT-001 D7 and the REV/CON handoff. + +The authorized `review.decision` transaction invokes one mandatory CON +participant in the caller's AsyncSession. It creates a reviewer +`completed_review` for every committed Review. For accept only, REV first +creates FinalAcceptance and CON creates `accepted_submission` from that locked +fact, never directly from Review.decision. CON evaluates each applicable frozen +ContributionRule, stages applicable contribution/award rows, returns typed +audit/outbox inputs to REV, flushes, and never commits. REV stages the shared +audit/outbox records and owns the single commit. There is no `contribution.materialize` or +`compensation.award.materialize` action and no no-op production participant. + +## D6 - ART Is Not A Core Contribution Dependency + +**Status:** accepted by WS-XINT-001 D7; supersedes the prior mandatory evidence +design. + +Core contribution creation performs no ART capability call, artifact +authorization, provider I/O, or evidence projection. CON copies the stabilized +Submission/packet digest supplied by REV into +`ContributionRecord.artifact_hash` and does not verify or rederive it. + +An evidence document may be proposed later only as an optional asynchronous +projection with independent status/failure semantics, a separately reviewed ART +capability, and a separate AUTH action. Its failure cannot alter Review, +ContributionRecord, CompensationAward, fulfillment receipt, or status truth. + +## D7 - Shared Outbox Is A Prerequisite + +**Status:** recommended; human approval required with the chunk sequence. + +One generic shared outbox owns append, claim, retry, dead-letter, replay, and +finalization mechanics. Feature handlers return typed outcomes and do not query +or mutate outbox persistence directly. No review-private or compensation- +private dispatcher is allowed. + +## D8 - Coherent Public Activation + +**Status:** recommended; human approval required. + +Contribution-policy, binding, contribution, award, callback, and operations +routes remain hidden until exact AUTH actions/evaluators/principals, required +REV participants, outbox/audit, migrations, and release proof are complete. +Optional contribution-evidence projection is not a release dependency. + +## D9 - External Rails Fulfill Awards But Never Decide Eligibility + +**Status:** accepted. + +Workstream persists immutable awards, exact outbound instructions, delivery +evidence, immutable fulfillment receipts, and rebuildable status. External +money settlement and project-points adapters own provider execution, accounts, +balances, and ledger entries. They cannot create, change, void, or infer award +eligibility. + +## D10 - AUTH Owns Prepared Cross-Domain Mutation Authorization + +**Status:** required architecture contract. + +AUTH locks and revalidates human actor/link/grant rows or fixed-service +actor/link rows first. Fixed services additionally require immutable +ServiceIdentity, exact static service-action matrix membership, AUTH-09E typed +admission, and active action as code-owned validations rather than lock targets. +AUTH returns one opaque, single-use `PreparedAuthorizationHandle` bound exactly +to session, ActionId, actor-reference kind/reference, idempotency key, and +canonical request digest. The feature then locks product rows and recomposes +final typed facts; AUTH consumes the handle, evaluates exactly once, and stages +decision evidence. AUTH and feature participants flush only; the route or +service command commits once. + +Missing, reused, serialized, caller-constructed, cross-session/action/actor/ +request, binding-mismatched, or authority-lost handles fail closed before +feature mutation. A failed substitution does not consume an otherwise valid +handle. Product-first locks, unlocked resource snapshots, double decisions, +and feature-side catalogue changes are rejected. + +## D11 - Project Roles Are Independent; Admin Candidate Differences Remain Exact + +**Status:** project-role model resolved by ADR 0015; AdminRole surface choices +remain human gates before CON-10A/10B. + +The current shipping path requires exact `submitter` for task claim and exact +`reviewer` plus no-self-review for review claim/decision. Any unrelated project +or administrative grant does not substitute. The existing global AUTH project- +role catalogue remains AUTH-owned, but WS-CON adds no adjudication grant, +action, invalidation consumer, or readiness dependency. + +Merged AUTH currently gives Finance Authority +`compensation.delivery.reconcile` but not Operator, while the earlier WS-CON +candidate also proposed reason-bound Operator recovery. Merged Project Manager +has `compensation.award.read`, while the earlier candidate narrowed award +detail. Audit candidates also differ. The human must select each exact action +candidate set before registration. Any change is AUTH-owned and evaluator- +closed; CON never queries roles or infers access from PermissionId membership. + +## D12 - ActionOwner Is AUTH Activation Custody + +**Status:** resolved by WS-XINT-001 D1-D3; no local alternative remains. + +AUTH must provide one exact activation custodian for each proposed CON action +and complete, not partially repeat, the canonical transfers for all current ART +and REV actions. Every ActionId-to-PermissionId mapping is preserved, and closed +typed/SQL/audit/definition-owner parity rejects dual, missing, unused, or extra +owners. WS-CON depends on review.claim/review.decision but does not prescribe a +two-action REV transfer or an eleven-action ART subset. + +## D13 - Fixed Service Admission Uses Static Matrix Membership + +**Status:** accepted architecture; exact new identities/actions remain an +AUTH/human registration gate. + +There is no database service-grant or service-action-assignment model. A fixed +service uses verified token -> ActorIdentityLink -> service ActorProfile -> +immutable closed ServiceIdentity -> exact static ActionId row -> AUTH-09E typed +context -> feature resource facts -> decision. + +The shared outbox dispatcher may only claim/invoke/finalize outbox work under +`outbox.dispatch`; it does not inherit protected handler or provider authority. +Outbound delivery, asynchronous reconciliation, contribution projection +rebuild, and fulfillment callback each require an exact approved service +identity/action/static row or an explicitly approved closed dual-principal +evaluator before implementation. Missing provisioned rows deny runtime but do +not prevent application startup or administrative provisioning. + +## D14 - Optional Evidence Is A Deferred Successor + +**Status:** deferred and not approved for implementation. + +CON-09A/09B are outside the core dependency order. If the human later approves +them, their chunk contracts must be refreshed against then-current ART/AUTH +contracts and internally reviewed again. The optional evidence action is not +counted as a core release action and cannot gate product reads or release. + +## D15 - FinalAcceptance Is The Sole Submitter-Acceptance Source + +**Status:** accepted by explicit human direction on 2026-07-17; REV merge is an +upstream implementation gate. + +REV owns immutable FinalAcceptance and creates it only inside an authorized +`Review(accept)` transaction. There is no manual/public create API and no +separate authorization action: creation is a lifecycle consequence of the +already-authorized review operation. `needs_revision` and `reject` create none. + +The non-accept effects follow REV's canonical lifecycle: `needs_revision` sets +the Task to `needs_revision` and keeps its TaskAssignment `active`; `reject` +sets the Task to `rejected` with a bounded human reason and blocks only the +same-task TaskAssignment with its source Review. Reject changes no grant or +unrelated task. The archival `closed/review_rejected` wording is not adopted. + +The repository's existing immutable `Submission` row is already the submission +version identity. Therefore FinalAcceptance stores canonical `submission_id`, +not `submission_version_id`, and enforces unique task, source Review, and +Submission lineage. Merged REV-04 retains `policy_context_ref` as the foreign +key to canonical immutable `ReviewPolicy.id` and retains `recorded_by` as the +reviewer ActorProfile field; REV proves the locked same-chain lineage. CON adds +no aliases and does not interpret review policy as contribution policy or use +it to decide awards. + +`completed_review` keeps direct Review/ReviewLease lineage and is unique per +Review. `accepted_submission` requires `source_final_acceptance_id` plus the +exact TaskAssignment and is unique per FinalAcceptance; its direct +`source_review_id` is null because the FinalAcceptance already owns that link. +Database checks enforce the mutually exclusive source shapes. + +REV creates Review and optional FinalAcceptance, applies task/assignment +effects, invokes the mandatory CON flush-only participant, stages shared audit/ +outbox records, and commits once. CON failure rolls the entire unit back. ART +and provider calls remain absent; fulfillment begins asynchronously after +commit. V0.1 has no adjudication policy, queue, lease, state, decision, +contribution type, branch, action, readiness check, or initiative dependency. + +## D16 - AUTH PR 140 Is Planning Authority, Not Runtime Activation + +**Status:** accepted by merged AUTH PR #140 on 2026-07-17. + +Trusted main after AUTH-09A and merged REV PR #128 has 74 PermissionIds, 65 +ActionIds, nine active actions, and 56 planned actions, with no registered CON +or task-claim ActionId. The eight additional planned actions are AUTH-09 +identity-administration surfaces. PR #140 supplies the exact prepared protocol, +complete ART/REV custody maps, and feature-manifest activation rule; their +runtime implementation remains upstream work. + +CON removes speculative `AUTH_CON_*` owner labels. Its proposed action mappings +remain unregistered and non-final until each complete feature manifest exists +and AUTH assigns an exact `WS-AUTH-001-*` custodian. Only the `task.claim` +PermissionId exists today; AUTH-13 must not register or activate a task-claim +ActionId before task-owned composition consumes CON-05A's immutable +TaskAssignment policy freeze. `review.claim` similarly consumes CON-06 through +REV, and `review.decision` consumes CON-07 through the rollback-safe REV-owned +transaction. AUTH alone registers/evaluates/activates; CON alone supplies its +hidden facts and participants. + +## D17 - Review Contribution Integration Uses Two Ordered Operations + +**Status:** accepted from merged REV PR #128 on 2026-07-17. + +One mandatory CON participant exposes two operation-specific flush-only methods +in REV's caller session. The reviewer method runs after immutable Review/ +finding/resolution creation plus lease/queue closure and before the decision +branch. It accepts no FinalAcceptance, submitter source, or submitter policy. +The submitter method exists only after `accept` creates FinalAcceptance and +applies accepted Task/TaskAssignment effects. It accepts no direct Review/ +ReviewLease contribution-source shape. An omnibus input with nullable +FinalAcceptance or both actors' policy contexts is prohibited. + +Each method evaluates only its frozen ContributionRule, creates its own +contribution and eligible awards, returns typed shared-audit/outbox inputs, and +never commits. REV collects the invoked results, stages the shared rows, and +the request route or service command commits once. + +## D18 - REV Owns One Joint Controller; CON Supplies Fenced Fulfillment Hooks + +**Status:** accepted from merged REV PR #128 on 2026-07-17. + +REV-12A owns the sole PostgreSQL `JointLifecycleReleaseControl` and shared +`JointLifecycleMutationFence`. CON creates no parallel phase/controller. Every +fulfillment-obligation root creation, requeue, successor, and repair writer +must acquire that fence before it allocates one immutable, monotonically +increasing root ordinal or locks obligation rows. + +CON's same-session drain observation returns outbox/fulfillment counts and the +current maximum ordinal. REV atomically persists that value as the generation +cutoff after admitted writers drain. During `delivery_draining`, dispatch and +callback may finalize only a same-generation root at or below the cutoff and +cannot create follow-on obligations. Provider I/O occurs after the fenced +pre-I/O transaction commits and releases every database/advisory lock. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/DISCOVERY.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/DISCOVERY.md new file mode 100644 index 00000000..af357dc0 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/DISCOVERY.md @@ -0,0 +1,205 @@ +# Discovery: WS-CON-001 Contribution Record And Compensation Boundary + +## Baseline inspected + +- trusted `origin/main` at `0302bcf`, merged REV PR #128, including AUTH-09A, + AUTH PR #140, and the earlier WS-XINT PR #139 boundary; +- complete WS-XINT intent, decisions, plan, REV/CON, AUTH/role-service, + AUTH/REV, AUTH/ART, and ART/REV handoffs; +- current WS-CON initiative package and archival reference inputs; +- canonical README, glossary, architecture lockdown/data model/lifecycle, + authorization spec, artifact spec, roles/operations docs, and ADRs 0012-0015; +- current backend project/task/submission/checker, AUTH, audit, artifact, and + migration code/tests; +- human-approved 2026-07-17 FinalAcceptance/no-adjudication direction and the + complete merged WS-REV-001 planning package; +- stale wording, authorization, artifact, link, loop-memory, and agent-gate + scanners/tests. + +## Current runtime observations + +- The backend stops before the human Review/ContributionRecord implementation. +- Project code still has the retired guide-bound economic schema. There is no + canonical ContributionPolicy aggregate, ContributionRecord, + CompensationAward, fulfillment receipt, or status projection runtime. +- Existing Submission rows carry `version` and supersession lineage. A separate + SubmissionVersion model would duplicate current identity. The handoff field + named `submission_version_id` therefore maps to canonical `Submission.id` and + is stored as `submission_id`. +- No FinalAcceptance runtime exists yet. Merged REV PR #128 is reviewed planning + authority and defines the exact schema/transaction, but CON-03C still waits + for the REV-04 runtime target. +- The merged AUTH catalogue has 74 PermissionIds and 65 ActionIds. Nine actions + are active and 56 are planned. AUTH-09A added eight planned identity- + administration actions; no WS-CON or task-claim ActionId is registered. +- Current AUTH supports actor-self and AdminRoleGrant evaluation. Independent + ProjectRoleGrant runtime, fixed-service runtime admission, CON evaluators, + ART/REV custody transfer, and the cross-domain prepared mutation protocol + remain future AUTH work. PR #140 adds their reviewed plans, not runtime. +- AUTH's static service-action matrix is typed code; it is not a database grant + table. AUTH-09E is the required runtime admission path. +- PR #129 added inactive ART preparation/source values only. It added no + contribution-evidence capability, ART admission/provider execution, binding, + action, permission, or CON dependency. +- No shared transactional outbox exists with the required generic dispatcher, + claim fencing, replay, and typed handler outcome contract. + +## Canonical merged changes affecting CON + +1. `ContributionPolicy`, `ContributionPolicyVersion`, `ContributionRule`, and + `ContributionAwardDefinition` decide award eligibility. CompensationAward + is the evaluated downstream result. +2. Every valid Review creates reviewer `completed_review`. REV creates exactly + one FinalAcceptance for `accept`; submitter `accepted_submission` consumes + FinalAcceptance rather than inferring acceptance from Review.decision. +3. Core contribution creation is a flush-only CON participant in the REV-owned + transaction. It performs no ART call or evidence projection. +4. CON copies the stabilized versioned Submission/packet digest supplied by REV + into `ContributionRecord.artifact_hash`; it does not verify or rederive it. +5. The current shipping path consumes exact submitter and reviewer grants only. + The separate global AUTH role catalogue is not expanded here; no adjudication + behavior or readiness dependency enters WS-CON. +6. ActionOwner is AUTH activation custody. ART and REV transfers must be + complete across their full current catalogues; WS-CON cannot prescribe + partial subsets. +7. Fixed services use provisioned ActorProfile/ActorIdentityLink, immutable + ServiceIdentity, exact static ActionId row, and AUTH-09E admission. +8. The shared outbox dispatcher cannot inherit protected feature-handler + authority. Delivery, reconciliation, rebuild, and callback boundaries need + exact approved service contracts. +9. REV owns FinalAcceptance persistence, Review/task effects, shared audit/ + outbox staging, and the single commit. CON validates the locked acceptance + fact, flushes contributions/awards, returns a typed result, and never commits. +10. PR #140 fixes the prepared handle to exact session, ActionId, + actor-reference kind/reference, idempotency key, and canonical request + digest bindings. Final resource facts are recomposed after feature locks; + AUTH consumes the handle, evaluates once, and stages evidence. +11. PR #140 publishes complete 25-ART/19-REV custody-transfer maps, but those + availability-neutral runtime transfers remain proposed. CON depends on the + complete REV transfer and never restates a two-action subset. +12. Trusted main has stable PermissionId `task.claim` but no task-claim + ActionId. CON-05A's hidden TaskAssignment policy freeze must merge into + task-owned claim composition before AUTH-13 enumerates/registers and + activates that action. +13. Merged REV rejects the prior omnibus CON decision input. One mandatory + participant exposes a reviewer operation before the decision branch and an + accept-only submitter operation after FinalAcceptance and accepted task + effects. Neither input carries nullable cross-actor source/policy facts. +14. REV-12A requires one shared `JointLifecycleMutationFence`. Every CON + fulfillment-obligation creation/requeue/successor/repair writer must fence + before allocating an immutable monotonic root ordinal. CON must expose the + current maximum ordinal with drain counts; delivery-draining dispatch and + callback may complete only same-generation roots at or below REV's cutoff. + +## Relevant files and symbols + +| Source | Observation | +|---|---| +| `docs/architecture_data_model.md` | Canonical policy/rule/definition, binding, contribution, award, receipt, and projection names/fields | +| `docs/decision_0015_project_contributor_roles_are_independent.md` | Exact project role values and independent revocation | +| `docs/spec_authorization_service.md` | Stable permissions, current actions, ActionOwner semantics, static service matrix, AUTH-09E order | +| `WS-AUTH-001/ACTIVATION_CUSTODY.md` | Exact complete custody transfers, feature-manifest activation gates, and mandatory CON participant prerequisite for review.decision | +| `WS-AUTH-001-PREP` chunk | Exact prepared-handle bindings, authority-first locks, single use, caller-owned commit, and concurrency/rollback proof | +| `WS-AUTH-001-13` chunk | Future task-claim ActionId enumeration, registration, evaluator integration, and activation owner; exact submitter grant, task-owned resource composition, and AUTH-PREP dependency | +| `WS-AUTH-001-16` chunk | Aggregate proof that active review.decision uses one rollback-safe REV+CON transaction with no ART/fallback | +| `WS-XINT-001/REV_CON_HANDOFF.md` | Exact core participant sequence and optional-evidence boundary | +| `WS-REV-001/CON_INTEGRATION_REVIEW.md` | Merged two-operation participant, exact lineage, interleaving, and release-control dependencies | +| `WS-REV-001-08/10` chunks | Decision input freeze followed by first hidden canonical Review commit only after exact CON participant merge | +| `WS-REV-001-12A` chunk | Single shared lifecycle fence, obligation-writer ordinal order, cutoff capture, and drain-phase behavior required from CON | +| `WS-XINT-001/AUTH_ROLE_SERVICE_HANDOFF.md` | Fixed service and project grant contract | +| `WS-XINT-001/AUTH_REV_HANDOFF.md` | Full review activation-custody/hidden behavior sequence | +| `WS-XINT-001/AUTH_ART_HANDOFF.md` | Full 25-action ART transfer; not a core CON gate | +| `backend/app/modules/projects/{models,schemas,repository,service}.py` | Current guide-bound economic fields and consumers to cut over/remove | +| `backend/app/modules/tasks/**` | TaskAssignment creation and future submitter policy freeze seam | +| `backend/app/modules/tasks/models.py::Submission` | Existing immutable version identity: `id`, integer `version`, and `supersedes_submission_id`; no SubmissionVersion table | +| `backend/app/modules/authorization/{catalogue,policy,kernel,schemas}.py` | Current 74/65/9/56 runtime and stable PermissionIds; no CON/task-claim ActionId | +| `backend/app/modules/audit/**` | Shared append-only audit extension point | +| `backend/app/modules/artifacts/{preparation,sources}.py` | Inactive ART-only preparation; no core CON import | + +## Existing tests and gaps + +- Project/task tests cover current setup/claim/submission behavior but not + ContributionPolicy freezes or retirement of the legacy economic schema. +- AUTH tests cover catalogue parity, planned denial, actor-self/admin grants, + decision digest, scope evidence, and route commit/rollback. PR #140 changes + planning/tests for documentation gates but does not implement CON contexts, + independent project grants at CON call sites, AUTH-09E CON identities, + custody transfer, or prepared cross-domain mutations. +- ART tests prove preparation only. No optional evidence projection capability + exists or is needed for core contribution tests. +- No tests yet cover ContributionRecord cardinality, frozen rule evaluation, + money/points award uniqueness, fulfillment callback, delivery replay, + shared-outbox handler isolation, or REV/CON atomic rollback. +- No tests yet cover FinalAcceptance one-per-task/Review/Submission constraints, + accept-only creation, source-lineage exclusivity, or rollback when CON fails. +- No tests yet cover the two ordered CON operation inputs, reviewer-before- + branch fault boundaries, immutable fulfillment root ordinals, every writer + versus cutoff capture, or same-generation pre-cutoff drain completion. + +## Dependencies + +- AUTH: AUTH-10 independent project grants, AUTH-09A-E fixed-service sequence, + complete ART/REV custody transfers, AUTH-PREP, reviewed CON registration and + later activation chunks, exact CON service identities/static rows, and + action-specific evaluators. Task claim activation must consume the merged + CON-05A freeze participant; review.decision activation must consume CON-07. +- REV: ReviewLease reviewer policy FK; canonical claim/decision composition; + REV-owned FinalAcceptance with exact policy-context typing; stabilized + artifact-hash facts; mandatory CON participant injection; REV-staged shared + audit/outbox; single route commit; and no no-op fallback. +- REV release control: CON writer/dispatch/callback hooks, immutable root + ordinal allocation under the shared fence, and same-session maximum-ordinal/ + drain observation must merge before REV-12A. +- Task/Submission: submitter policy freeze and stable assignment/version lineage. +- Shared outbox/audit: caller-transaction append and feature-neutral dispatch. +- ADR 0014 adapters: typed capability port, factory, and composition-root + registration for external fulfillment. +- ART: no core dependency; optional projection only after separate approval. + +## Risks + +| Risk | Mitigation | +|---|---| +| Two award-eligibility models | Clean semantic then physical cutover; no fallback | +| Contribution missing after Review | Mandatory flush-only participant and one caller commit | +| Reviewer contribution ordered after branch | Two operation-specific inputs; reviewer operation always precedes branch and cannot depend on branch effects | +| Submitter contribution inferred from Review decision | REV-owned immutable FinalAcceptance is the only submitter source; exact one-to-one constraints and lineage checks | +| ART outage suppresses contribution | No core ART/evidence operation | +| Wrong policy version | Assignment/lease freeze before work; immutable published versions | +| Cross-domain deadlock | AUTH-first lock order and two-order PostgreSQL tests | +| Dispatcher gains feature authority | Exact dispatcher-only action plus independent handler authorization | +| Dynamic/broad service access | Closed ServiceIdentity/static rows, AUTH-09E, cross-service denial | +| Role coupling | Independent grants and role-specific invalidation consumers | +| Partial activation transfer | Consume complete WS-XINT AUTH handoffs, never local subsets | +| Legacy row ambiguity | Human-approved deterministic rebuild/classification before migration | +| Premature public surface | Hidden behavior until AUTH activation and joint release proof | +| Shutdown loses or admits fulfillment work | Shared fence before every writer ordinal; immutable cutoff; same-generation pre-cutoff completion only; exact drain counts | +| Adjudication leaks into v0.1 | No adjudication type/action/state/queue/readiness dependency; reject and accept remain terminal | + +## Resolved FinalAcceptance policy lineage + +Merged REV-04 retains the handoff's `policy_context_ref` field as a foreign key +to canonical immutable `ReviewPolicy.id` and retains `recorded_by` for the +reviewer ActorProfile. REV must enforce that exact locked policy and its same +project/task/Submission/Review lineage. CON adds no renamed aliases and does not +interpret review policy as contribution policy or award authority. + +## Open questions + +- Exact D11 AdminRole candidates for award detail, delivery recovery, and audit. +- Exact ServiceIdentity/ActionId/static-row contracts for delivery, + reconciliation, projection rebuild, and callback execution. +- Deterministic treatment of pre-production legacy rows. +- Whether optional evidence projection is ever approved; it is not part of the + current core plan. + +## Conventions to preserve + +- Review decisions are only `accept`, `needs_revision`, and `reject`. +- PostgreSQL owns canonical contribution/award/receipt truth. +- External I/O occurs only after commit and outside lifecycle/database locks. +- Domain participants flush and never commit. +- AUTH and feature repositories never cross-import. +- Fixed service identity is authorization; Celery executor/generation is + separate execution fencing. +- `/api/v1` is the only public prefix. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/INTENT.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/INTENT.md new file mode 100644 index 00000000..19377aa5 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/INTENT.md @@ -0,0 +1,88 @@ +# Intent: WS-CON-001 Contribution Record And Compensation Boundary + +## Human-level goal + +Implement the canonical contribution-policy, ContributionRecord, +CompensationAward, fulfillment, and operations boundary that participates +atomically in human Review without taking ownership of authentication, +authorization, review decisions, artifact storage, external settlement, a +points ledger, or reputation scoring. + +The supplied WS-CON reference pair is input to reconcile, not authority to +accept blindly. The active contract follows trusted repository decisions and +merged REV PR #128 at `0302bcf`, AUTH PR #140, and the underlying WS-XINT-001 +boundary from PR #139. + +## Success state + +- Every valid recorded human Review creates one immutable reviewer + `completed_review` contribution. +- REV creates one immutable `FinalAcceptance` only for `Review(accept)`. + `accepted_submission` consumes that FinalAcceptance; it is never inferred + directly from `Review.decision`. `needs_revision` and `reject` create neither. +- TaskAssignment and ReviewLease freeze independent published + ContributionPolicyVersions before work is performed. +- Explicit unpaid rules create no award; compensated rules create at most one + money and one project-points CompensationAward. +- REV owns the request and single commit: Review/task effects, optional + FinalAcceptance, CON-flushed contributions/awards, and REV-staged shared + audit/outbox rows commit or roll back together. +- One mandatory CON participant exposes a reviewer operation before the + decision branch and an accept-only submitter operation after FinalAcceptance + and accepted task effects; no nullable cross-actor omnibus input exists. +- Core contribution creation copies stabilized artifact-hash lineage supplied + by REV and has no ART or provider dependency. +- Downstream adapters fulfill awards but never determine eligibility. +- Every fulfillment-obligation writer uses REV-12A's one shared lifecycle fence + before monotonic root-ordinal allocation; drain dispatch/callback completes + only same-generation roots at or below the persisted cutoff. +- Every protected human/service surface uses AUTH's exact grant or + ServiceIdentity/static-matrix path, prepared mutation protocol when needed, + and AUTH-owned activation. +- Public APIs use `/api/v1` only. + +## Non-goals + +- Workstream-owned login, sessions, passwords, or token-role authority. +- AUTH catalogue, grant, static-matrix, evaluator, or activation implementation. +- REV models, routes, lifecycle decisions, or commits. +- Mandatory contribution-evidence artifacts. A future projection is optional + and separately approved. +- Provider-specific settlement SDKs, attempts, payout batches, accounts, + balances, points ledgers, credits, or blockchain work. +- Reputation scores, aggregates, adjudication, appeals, reversals, or mutable + contribution/award truth. V0.1 has no adjudication policy, action, queue, + lease, state, decision, contribution, branch, readiness gate, or initiative + dependency. +- A second artifact store, raw provider references, or ArtifactStore injection. +- Frontend work before backend contracts and guards stabilize. + +## Context + +Workstream certifies useful human work independently from external fulfillment. +Reviewer work is a contribution for every valid Review. ContributionPolicy +decides what that work earns. FinalAcceptance is the stable REV-owned fact that +allows CON to recognize accepted submitter work without treating the mutable +shape of a Review decision as its source. Immutable awards record the result; +adapters carry out fulfillment later. + +## Human judgment required + +1. Approve the repository-owned active specification while preserving archival + reference inputs. +2. The complete removal of the retired guide-bound economic schema remains + approved; choose only the deterministic pre-production row classification + for migration. +3. Resolve D11 action-specific AdminRole candidates for award detail, delivery + recovery, and audit. +4. Approve exact ServiceIdentity/ActionId/static-row boundaries for dispatcher, + delivery, reconciliation, projection rebuild, and callback execution. The + shared dispatcher cannot inherit handler authority. +5. Optional contribution-evidence projection remains deferred unless separately + approved. + +## Risk class + +L0 for planning/contract reconciliation. Each runtime chunk is L1 because it +touches authorization, economic records, schema, lifecycle, audit, or cross- +domain transactions. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/JOINT_RELEASE_HANDOFF.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/JOINT_RELEASE_HANDOFF.md new file mode 100644 index 00000000..13d43fd2 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/JOINT_RELEASE_HANDOFF.md @@ -0,0 +1,152 @@ +# Joint REV/CON Release Handoff + +## Boundary + +REV owns Review decisions, FinalAcceptance, queue/lease/task effects, shared +audit/outbox staging for the decision transaction, release-control state, and +the single route commit. CON owns ContributionPolicy, ContributionRecord, +CompensationAward, fulfillment behavior, and CON projections. AUTH owns all +authorization and activation. + +The canonical cross-boundary source is merged +`WS-XINT-001/REV_CON_HANDOFF.md`. Merged REV PR #128 at trusted main `0302bcf` +is the reviewed owner contract; runtime REV behavior remains unimplemented. + +## Required decision composition + +```text +AUTH locks exact reviewer authority and prepares review.decision handle bound to +session/action/actor reference/idempotency key/canonical request digest +-> REV locks and recomposes canonical facts +-> AUTH consumes the handle, evaluates once, and stages decision evidence +-> REV stages Review/findings/resolutions, consumes ReviewLease, closes queue +-> CON reviewer operation creates completed_review from Review/ReviewLease, + evaluates only the lease-frozen reviewer rule, and returns typed staging inputs +-> on accept, REV creates immutable FinalAcceptance linked to Review, + canonical Submission, Task, submitter, reviewer and locked ReviewPolicy + then accepts Task and completes TaskAssignment + -> CON submitter operation creates accepted_submission from FinalAcceptance + and TaskAssignment, evaluates only the assignment-frozen submitter rule, + and returns typed staging inputs +-> on needs_revision, REV sets Task to needs_revision and keeps TaskAssignment active +-> on reject, REV sets Task to rejected with a bounded human reason and blocks + only the same-task TaskAssignment with its source Review +-> REV stages shared audit/outbox rows from the typed participant result +-> request route or service command commits once +``` + +The participant is one mandatory interface with two ordered operation-specific +inputs. The reviewer input never carries nullable FinalAcceptance or submitter +policy/source facts. The submitter input does not exist outside `accept` and +never uses direct Review/ReviewLease contribution-source fields. + +No no-op participant, post-commit repair, ART call, evidence projection, or +provider I/O exists in this transaction. CON copies stabilized artifact-hash +lineage from REV facts. + +## FinalAcceptance contract + +The external shorthand `submission_version_id` means canonical +`Submission.id`; the repository stores `submission_id` because each immutable +Submission row is already one version. Merged REV-04 retains +`policy_context_ref` as the foreign key to the exact locked `ReviewPolicy.id` +and retains `recorded_by` for the canonical reviewer ActorProfile. CON consumes +those owner-defined names without aliases. REV owns this record and the +composite same-chain constraints. + +```text +FinalAcceptance + id + project_id + task_id UNIQUE + submission_id UNIQUE + source_review_id UNIQUE + accepted_submitter_id + accepted_at + recorded_by + policy_context_ref +``` + +It is created only inside `Review(accept)`. There is no public/manual creation +API and no separate authorization action. `needs_revision` and `reject` create +none. Accept/reject are terminal in v0.1; there is no adjudication, appeal, +replacement acceptance, or reopen path. + +For `needs_revision`, REV keeps the same TaskAssignment `active`. For `reject`, +REV blocks only that same-task TaskAssignment, binds the block to the reject +Review, and sets the Task to canonical `rejected` with its bounded human reason; +it changes no grant or unrelated task. The archival `closed/review_rejected` +wording is not a lifecycle token. + +Optional reviewer-quality sampling is non-mutating audit only. It does not +delay or replace FinalAcceptance and cannot change Review/task/contribution +truth. + +`completed_review` binds directly to Review and ReviewLease and is unique per +Review. `accepted_submission` binds to FinalAcceptance and TaskAssignment and +is unique per FinalAcceptance. Database checks make those source shapes +mutually exclusive; CON never infers a submitter record by reading +Review.decision. + +## Release prerequisites + +- ContributionPolicy publish/freeze and adapter-binding behavior are merged. +- TaskAssignment and ReviewLease carry exact frozen policy-version IDs. +- REV FinalAcceptance persistence and its locked decision-lineage contract are + merged, including exact task/Review/Submission uniqueness and ReviewPolicy + lineage. +- Shared outbox/audit participants and CON-07 are mandatory and merged. +- REV hidden claim/decision composition then consumes CON-06/07 and has no + fallback. +- AUTH complete REV custody transfer, exact evaluators, reviewer grant path, + prepared protocol, and activation are merged. The transfer is the complete + PR #140 19-action map, not a local review.claim/review.decision subset. +- Every public/service CON action has exact AUTH registration, evaluator, + principal path, and activation after hidden behavior. +- Protected outbox handlers have their own exact service authority; dispatcher + authority is not inherited. +- Every CON fulfillment-obligation creation, requeue, successor, and repair + writer exposes a mandatory hook that acquires REV-12A's shared + `JointLifecycleMutationFence` before allocating an immutable monotonically + increasing root ordinal or locking obligation rows. +- CON dispatch and callback hooks consume that shared fence. In + `delivery_draining`, they may complete only the same generation and a root + ordinal at or below REV's persisted cutoff; they cannot create successor, + retry-root, repair, or other follow-on obligations. +- `FulfillmentLifecycleDrainObservationPort` is same-session/read-only and + returns pending/claimed/retryable/in-flight counts, nonterminal delivery and + callback obligations, and the current maximum root ordinal through typed + shared-outbox capability. REV imports no CON/outbox repository. +- Exact migrations, handler registry, task IDs, route inventory, and retained + tests are bound to merged SHAs. + +ART storage and optional contribution-evidence projection are not prerequisites. + +## Startup and readiness + +Startup fails on closed catalogue/static-matrix/context/evaluator/active-feature +parity drift. Missing provisioned fixed-service ActorProfile/link rows do not +stop startup or administrative provisioning, but runtime calls deny and release +readiness remains false until exact rows exist. + +## Joint live proof + +The release drill covers accept with exactly one FinalAcceptance, accepted Task, +completed Assignment, and submitter contribution; needs_revision with an active +Assignment and neither acceptance fact nor submitter contribution; reject with +canonical rejected Task, same-task blocked Assignment/source Review, and neither +acceptance fact nor submitter contribution; one reviewer contribution per +Review, explicit unpaid, money+points, frozen-version changes, +repeated/revision Reviews, no-self-review, grant revocation, source-shape and +uniqueness conflicts, atomic rollback, adapter outage/replay, +callback-before-ack, failure then fulfillment, reconciliation, every obligation +writer versus cutoff capture in both orders, same-generation pre-cutoff +dispatch/callback completion, post-cutoff denial before provider I/O, drain +fencing, and hidden-to-active route transition. It asserts zero ART calls and +no adjudication action/state/queue/readiness dependency. + +## Ownership and stop + +CON-11 publishes the hidden dependency manifest but registers no route. The +reviewed REV release chunk consumes that manifest and owns public activation and +the joint live drill. This handoff starts neither chunk automatically. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/PLAN.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/PLAN.md new file mode 100644 index 00000000..3dc49002 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/PLAN.md @@ -0,0 +1,445 @@ +# Plan: WS-CON-001 Contribution Record And Compensation Boundary + +## Proposed approach + +Adopt merged REV PR #128 at trusted main `0302bcf`, including AUTH-09A, AUTH PR +#140, and the underlying WS-XINT PR #139 boundary before runtime work, then +deliver WS-CON through hidden, reviewable chunks. The core path is +PostgreSQL-local and has no ART dependency: + +```text +AUTH prepares review.decision and locks reviewer authority +-> REV locks and recomposes canonical Review/Submission facts +-> AUTH evaluates once and stages decision evidence +-> REV stages Review/findings/resolutions, consumes ReviewLease, and closes queue +-> CON reviewer operation creates completed_review and applicable reviewer awards +-> on accept, REV creates immutable FinalAcceptance, accepts Task, and completes Assignment + -> CON submitter operation creates accepted_submission and applicable submitter awards +-> on needs_revision, REV sets Task to needs_revision and keeps Assignment active +-> on reject, REV sets Task to rejected with a bounded human reason and blocks + only the same-task Assignment with its source Review +-> REV stages shared audit and outbox rows +-> request route or service command commits once +``` + +Public contribution, policy, award, fulfillment, and operations surfaces stay +hidden until their exact AUTH registration -> feature behavior -> AUTH +activation sequence and the joint REV/CON release gate pass. + +## Canonical product model + +- `ContributionRecord` is immutable. Every valid recorded human Review creates + one reviewer `completed_review`. REV creates `FinalAcceptance` only for + `accept`; one submitter `accepted_submission` consumes that stable fact. +- `FinalAcceptance` is an immutable REV-owned internal derived fact, not a + public resource command. It has no independent authorization action or manual + creation API. +- Existing `Submission` plus its `version` and `supersedes_submission_id` is the + versioned submission identity. WS-CON does not add `SubmissionVersion`. +- `ContributionPolicy` is the stable project aggregate. It has one active + policy per project and points to an immutable published + `ContributionPolicyVersion`. +- Each published version has exactly one `ContributionRule` for + `accepted_submission` and one for `completed_review`. A rule is explicitly + `unpaid` or `compensated`. +- An unpaid rule creates no award. A compensated rule references one or two + immutable `ContributionAwardDefinition` rows: at most one `money` and one + `project_points` definition. +- `CompensationAward` is the immutable evaluated result. Delivery, + acknowledgement, immutable `CompensationFulfillmentReceipt`, and rebuildable + `CompensationStatusProjection` are downstream fulfillment concerns and never + decide eligibility. +- `ProjectCompensationAdapterBinding` binds one project/instrument to a + non-secret adapter route and canonical service actor. Credentials and + provider endpoints remain deployment configuration. +- The retired guide-bound economic schema and every semantic consumer are + removed in two fail-closed chunks. No alias, automatic conversion, or + executable fallback survives. + +## Review and contribution boundary + +One mandatory `ContributionCompensationDecisionParticipant` exposes two ordered +operation-specific methods in the caller-owned `AsyncSession`; it does not +accept one omnibus request with nullable FinalAcceptance or both actors' policy +contexts. + +The reviewer operation is required for every valid decision after REV appends +Review/findings/resolutions, consumes ReviewLease, and closes the queue but +before REV applies the decision branch. Its typed input contains only exact +locked Review, ReviewLease, versioned Submission, project/task, reviewer, +lease-frozen reviewer `ContributionPolicyVersion`, originating allowed +`review.decision` AuthorizationDecision, request/correlation references, and +the stabilized server-derived `Submission.artifact_hash`. It contains no +FinalAcceptance, TaskAssignment source field, submitter, or submitter policy. + +The submitter operation exists only after the `accept` branch creates +FinalAcceptance and applies Task `accepted` plus TaskAssignment `completed`. Its +typed input contains exact locked FinalAcceptance, TaskAssignment, versioned +Submission, project/task, submitter, assignment-frozen submitter +`ContributionPolicyVersion`, the same authorization/request/correlation +references, and stabilized artifact hash. It contains no direct Review or +ReviewLease contribution-source fields and is unavailable for `needs_revision` +or `reject`. + +Each operation validates only its supplied locked lineage, copies the stabilized +digest into `ContributionRecord.artifact_hash`, evaluates its matching frozen +`ContributionRule`, stages applicable contribution/award rows, returns typed +audit/outbox inputs to REV, flushes, and never commits. CON never reads REV or +AUTH repositories, evaluates `review.decision`, calls ART, rehashes artifact +bytes, performs provider I/O, or offers a no-op production participant. Any CON +failure rolls back the complete Review decision. + +`needs_revision` and `reject` still create the reviewer contribution and any +award earned by its frozen reviewer rule. They create no FinalAcceptance or +submitter contribution. Automated checker outcomes create neither contribution +type. + +The REV-owned lifecycle effects are exact and remain inputs to CON rather than +CON behavior: `needs_revision` sets `Task.status = needs_revision` and keeps the +same TaskAssignment `active`; `reject` sets `Task.status = rejected` with the +bounded human reason and sets only the same-task TaskAssignment to `blocked` +with its reject Review reference. Reject changes no actor grant and no other +task or assignment. The archival `closed/review_rejected` wording is not a +canonical status. + +### FinalAcceptance lineage + +REV persists the minimal same-chain fact: + +```text +FinalAcceptance + id + project_id + task_id + submission_id + source_review_id + accepted_submitter_id + accepted_at + recorded_by + policy_context_ref +``` + +The external handoff's `submission_version_id` maps to `submission_id` because +the existing immutable Submission row is already the version identity. Merged +REV-04 retains `policy_context_ref` as the foreign key to the exact locked +`ReviewPolicy.id` and `recorded_by` as the reviewer ActorProfile field; CON adds +no alias. REV must prove the Review, policy, project, task, Submission, +submitter and reviewer chain. PostgreSQL enforces `UNIQUE(task_id)`, +`UNIQUE(source_review_id)`, and +`UNIQUE(submission_id)`. There is no reopen, replacement, adjudication, or +second acceptance path in v0.1. + +Any reviewer-quality sampling is a non-mutating audit after the transaction. It +does not delay FinalAcceptance, create a second Review decision, or alter +acceptance/contribution truth. + +Reviewer contributions require direct `source_review_id` and +`source_review_lease_id`, with `source_final_acceptance_id` null. Submitter +contributions require `source_final_acceptance_id` and +`source_task_assignment_id`, with direct `source_review_id` and +`source_review_lease_id` null. Partial unique constraints enforce one +`completed_review` per Review and one `accepted_submission` per +FinalAcceptance; checks reject mixed or missing source shapes. + +## Contribution-policy freezing + +TaskAssignment freezes `submitter_contribution_policy_version_id` during an +authorized task claim. ReviewLease freezes +`reviewer_contribution_policy_version_id` during an authorized review claim. +Both use a narrow CON-owned lookup/freeze participant, lock the active +`ContributionPolicy` and current published version plus referenced award +definitions and adapter bindings, return one exact version ID, flush only their +own state, and never commit. + +Later policy publication changes only new assignments or leases. Retired frozen +versions remain valid for started work. Missing policy configuration is not an +implicit unpaid rule. + +TaskAssignment and task-claim wiring remain task-owned. ReviewLease and review- +claim wiring remain REV-owned. CON supplies typed participants, not foreign +models, routes, lifecycle decisions, or commits. + +## Authorization boundary + +Trusted `main` is `0302bcf`, merging REV PR #128 and AUTH-09A after AUTH PR +#140 and WS-XINT PR #139. Runtime catalogue counts are 74 PermissionIds, 65 +ActionIds, nine active actions, and 56 planned actions. No WS-CON or task-claim +ActionId is registered. PR #140 +adds reviewed AUTH custody/PREP/activation contracts only; the custody +transfers and prepared protocol remain proposed runtime work. + +WS-XINT D1/D2 is final for this plan: `ActionOwner` is the exact AUTH activation +custodian. Each protected surface follows: + +```text +AUTH registers planned ActionId, stable PermissionId mapping, typed context, +principal path, and activation custodian +-> CON merges hidden canonical resource composition, guards, and behavior +-> AUTH integrates the evaluator and alone changes planned to active +-> joint release exposes the surface +``` + +CON never reads grants, imports AUTH repositories, constructs PermissionIds or +roles, changes availability, or supplies a production allow fallback. AUTH +never imports CON repositories or mutates contribution/award state. + +PR #140's complete ART and REV custody-transfer contracts are AUTH-owned +coordination work; their runtime transfers have not yet merged. WS-CON +references the canonical AUTH `ACTIVATION_CUSTODY.md` plus WS-XINT +`AUTH_ART_HANDOFF.md` and `AUTH_REV_HANDOFF.md`; it does not prescribe a partial +transfer. CON depends on `review.claim` and `review.decision`, but AUTH must +transfer every current REV action as one complete boundary. The four proposed +additive REV actions remain unregistered until their own reviewed registration +contract. + +### Human project grants + +The shipping path consumes exactly two project authorities: task claim requires +one active exact-project `submitter` grant, while review claim/decision require +one active exact-project `reviewer` grant plus no-self-review and lifecycle +guards. Any unrelated project or administrative grant does not substitute. +WS-CON introduces no adjudicator grant/action, adjudication invalidation +consumer, or readiness dependency; the separate global AUTH role catalogue is +outside this lifecycle contract. + +### Prepared mutation protocol + +For mutations, AUTH first locks and revalidates either human actor/link/exact- +grant rows or fixed-service actor/link rows. It returns an opaque, single-use, +non-serializable `PreparedAuthorizationHandle` bound exactly to session, +ActionId, actor-reference kind/reference, idempotency key, and canonical +request digest. A fixed service additionally requires closed ServiceIdentity, +exact static service-action matrix membership, AUTH-09E admission, and active +action as code-owned validations after profile/link locks, not database lock +targets. The feature then locks canonical rows and recomposes final typed +facts; AUTH consumes the handle, evaluates once, and stages decision evidence. +AUTH and feature participants flush only; the route or service command commits +once. Substitution/reuse denial does not consume an otherwise valid handle. +Reads use request-scoped `require()` and canonical feature loaders. + +Missing provisioned service ActorProfile/ActorIdentityLink rows deny that +runtime request and block release readiness, but do not fail application startup +or the Access Administrator provisioning surface. Startup may fail on closed +catalogue/matrix/context/evaluator/active-behavior parity drift. + +### Fixed services and handler authority + +The shared outbox dispatcher is not a catch-all feature executor. +`workstream.outbox.dispatcher` with exact `outbox.dispatch` static membership +may claim, invoke, and finalize outbox work only. It cannot inherit compensation +delivery, reconciliation, contribution projection, callback, ART, or provider +authority from an event type. + +Before a protected feature handler is implemented, its owning specification and +AUTH must approve one exact ServiceIdentity/ActionId/static-row contract. The +current candidate boundaries requiring decisions are: + +- outbound compensation delivery execution; +- asynchronous compensation reconciliation; +- asynchronous contribution projection rebuild; +- fulfillment result reporting by the bound external service; +- optional contribution-evidence binding, if that projection is later adopted. + +Suggested semantic identifiers are discovery candidates only, not approved +catalogue strings: `workstream.compensation.delivery`, +`workstream.compensation.reconciler`, +`workstream.contribution.projection_rebuilder`, and +`workstream.compensation.fulfillment_reporter`. AUTH may instead approve a +closed dual-principal evaluator for an existing action, but CON must not infer +one. Therefore the previously proposed 22 core WS-CON ActionIds are not a final +closed runtime count until these service execution boundaries are decided. + +The callback path requires a verified service token, provisioned service +ActorProfile/ActorIdentityLink, immutable approved ServiceIdentity, its exact +static matrix row, matching `ProjectCompensationAdapterBinding`, and AUTH-09E. +It never uses a human role or dynamic service grant. + +## Operation-specific lock and commit order + +There is no global sequence that moves CON policy rows ahead of REV lifecycle +rows. Every mutation first locks AUTH human actor/link/grant or fixed-service +actor/link authority, then its idempotency row and applicable lifecycle fence. +After that common prefix, the owning operation uses one explicit order: + +- `review.decision`: REV follows its canonical idempotency/fence, queue, lease, + task, assignment, Submission, predecessor Review, finding/resolution order; + the reviewer operation then locks only the lease-frozen policy/rule/definition/ + binding and reviewer contribution/award rows. REV applies the branch. For + accept, REV creates FinalAcceptance and applies accepted task/assignment + effects before the submitter operation locks only the assignment-frozen + policy/rule/definition/binding and submitter contribution/award rows. REV then + stages shared audit and outbox rows; +- task/review claim freeze: the owning task/assignment/Submission or REV + queue/lease rows first, then the selected published policy version, + rule/definition and referenced binding, then the frozen lineage write; +- binding retirement or reconciliation that inspects task/assignment/lease + dependencies: affected lifecycle rows in the same task/REV order first, then + binding/policy and CON delivery/receipt/projection rows. If the bounded rows + cannot be enumerated before locking, the operation takes its approved + project-scoped advisory fence before either family and still locks lifecycle + rows before policy/binding rows; +- an outbox handler: immutable claim-generation validation without handler + ownership of outbox transitions, then its feature-owned award, binding, + delivery, receipt, request, finding, or rebuildable projection rows. + +Pure policy/binding administration that does not inspect lifecycle dependencies +locks Project and its own aggregate only. Rows of one type lock by ascending +primary key/UUID. Missing classes are skipped without reordering. Provider or +external I/O happens only after durable pre-I/O state commits and every database +transaction/fence is released. + +The dispatcher owns claim, retry, dead-letter, and finalization transitions. +Feature handlers validate the committed claim generation through a typed port, +stage feature state, perform post-commit I/O under their own exact authority, +and return a typed outcome. They do not lock or mutate OutboxEvent rows. + +## Optional contribution-evidence projection + +A deterministic contribution-evidence document is optional later work. It is +not written or requested by CON-07, does not gate ContributionRecord creation, +and is excluded from core reads, operations, release readiness, and the joint +live drill. + +If separately approved, CON-09A/09B may implement an asynchronous projection +with independent status/failure semantics through a separately reviewed ART +capability and AUTH action. Storage failure cannot change Review, +ContributionRecord, CompensationAward, fulfillment receipt, or status +projection truth. The future contract must revalidate the then-current ART and +AUTH boundaries, exact media/schema/retention/disclosure rules, and service +identity. CON never receives ArtifactStore, scratch/preparation types, provider +references, or ART repositories. PR #129's preparation foundation does not +approve this capability. + +Core contribution and award reads move directly to CON-10A and read PostgreSQL +truth. They do not depend on an evidence artifact or ART read port. + +## Shared outbox + +CON-02A provides generic PostgreSQL persistence and caller-transaction append. +CON-02B provides the feature-neutral dispatcher, stable task IDs, claim fencing, +retry/dead-letter/replay, retention, explicit handler registry, +`OutboxClaimValidationPort`, and same-session drain observation. The outbox +subsystem owns no contribution, award, adapter, review, or provider semantics. + +## Rollout + +1. CON-01 adopts the merged WS-XINT contract and publishes the active + contribution/compensation specification without altering archival inputs. +2. CON-02A/B/C land shared outbox persistence/dispatch and shared lifecycle + audit participation, with outbox execution still disabled until its AUTH + registration, static service identity, AUTH-09E admission, hidden behavior, + and activation gates pass. +3. CON-03A-D add inactive policy, binding, contribution, award, delivery, + receipt, and status persistence using the canonical names and boundaries. + CON-03C lands only after REV's FinalAcceptance persistence target is merged. +4. CON-04A/B add hidden binding and ContributionPolicy behavior behind planned + AUTH actions. +5. After AUTH-PREP, exact-project submitter grants, and the planned task-claim + contract exist, CON-05A removes retired semantic consumers and lands the + hidden participant that freezes the published ContributionPolicyVersion on + new TaskAssignments. Task-owned claim composition consumes it before + `WS-AUTH-001-13` enumerates/registers the task-claim ActionId, integrates its + evaluator, and activates; 05B then drops unreachable physical schema after + zero-consumer proof. +6. CON-06 supplies reviewer policy freeze; the REV owner wires it into hidden + review claim behavior before AUTH activates `review.claim`. +7. CON-07 supplies the flush-only decision participant that consumes REV-owned + FinalAcceptance for submitter work; the REV owner wires it into the complete + hidden decision path and owns audit/outbox staging before AUTH activates + `review.decision`. +8. CON-08A/R/B add fulfillment delivery and callback behavior only after exact + service execution/callback identities, actions, static rows, AUTH-09E, and + lifecycle fencing are approved. Every fulfillment-obligation root writer, + requeue, successor, and repair path acquires the shared lifecycle fence + before allocating its immutable monotonic ordinal. Dispatch and callback + composition exposes same-generation/pre-cutoff completion behavior without + provider I/O under the fence. +9. CON-10A/B add PostgreSQL product reads and bounded operation requests; 10C + adds independently authorized reconciliation/rebuild executors. Optional + 09A/09B remain outside the core dependency sequence. +10. CON-11 proves hidden readiness. It enumerates every obligation writer and + supplies mandatory dispatch/callback hooks plus a same-session observation + port returning outbox/fulfillment counts and the maximum root ordinal. REV- + 12A injects the one shared `JointLifecycleMutationFence`, persists the + generation cutoff, and owns release-control state; CON creates no second + controller. REV-13 owns final public release and the joint live drill. + +Every chunk refreshes trusted-main SHA, migration custody, exact port/action +symbols, and merged dependency evidence. No cross-initiative successor starts +automatically. + +### Merged REV interleaving + +Merged REV PR #128 fixes cross-initiative gates without starting either +initiative automatically: + +```text +REV-02 immutable Submission/TaskAssignment attribution + -> CON-05A/B task freeze and retired-field cutover + +CON-03B ContributionPolicyVersion persistence + -> REV-03 ReviewLease foreign key + +CON-02A shared outbox + CON-02C lifecycle audit participant + -> REV-04 Review/FinalAcceptance persistence + -> CON-03C exact contribution source schema + +CON-06 reviewer policy freeze + -> REV-06 claim composition + +REV-09B stable lineage + CON-03C schema + CON-07 two-operation participant + -> REV-10 first canonical Review-committing transaction + +CON-11 writer/dispatch/callback/ordinal/drain manifest + REV-12 observations + -> REV-12A shared lifecycle controller/fence + -> AUTH action-specific activation + -> REV-13 joint release +``` + +The merged REV plan proves ownership and ordering only. Each arrow still waits +for the exact runtime predecessor on then-current trusted main. + +## Verification strategy + +- Isolated PostgreSQL migration, constraint, rollback, idempotency, and both- + order concurrency tests. +- Same-run repository coverage at or above 78 percent and each new/materially + changed subsystem at or above 90 percent. +- Exact contribution cardinality for all three decisions and repeated/revision + Reviews; accept-only FinalAcceptance one-to-one constraints; mutually + exclusive reviewer/submitter source shapes; automated checks create none. +- Policy publication/freeze races, explicit unpaid rules, immutable published + versions, and at most one award per contribution/instrument. +- Participant fault injection proving Review/FinalAcceptance/task/contribution/ + award/audit/outbox atomic rollback and no ART call. +- AUTH tests for planned denial, exact grant/static-matrix candidates, prepared + handle misuse, role-specific revocation, cross-service denial, and one + activation custodian per action. +- Outbox tests proving the dispatcher cannot execute feature authority and each + protected handler has an approved independent authorization path. +- Callback/delivery/reconciliation tests with no provider I/O under database + locks and immutable receipt/award identities under replay. +- Hidden OpenAPI proof before release; exact `/api/v1` inventory at release. +- Stale wording, stale authorization/artifact contracts, Markdown links, loop + memory, `git diff --check`, and one-sheet roadmap checks when local sheets are + present. + +## Open human/AUTH decisions + +- D11 exact AdminRole candidate sets for award detail, delivery recovery, and + WS-CON audit actions. +- Exact ServiceIdentity/ActionId/static-row design for each protected feature + handler and fulfillment callback; proposed strings are not executable until + approved and registered by AUTH. +- Legacy pre-production row classification before CON-05A/05B migration. +- Optional evidence projection remains deferred unless separately approved. +- No adjudication decision remains: v0.1 accept/reject are terminal and no + adjudication initiative or readiness gate may enter the core order. + +## Review and stop + +Planning and every specification/runtime chunk require senior engineering, +QA/test, security/auth, product/ops, architecture, docs, and reuse/dedup. +Runtime/test chunks add test-delta; background-execution/script/config/CI changes add CI +integrity. Stop after planning reconciliation. Do not start CON-01 or another +initiative without explicit human instruction. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/RISKS.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/RISKS.md new file mode 100644 index 00000000..4be86f60 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/RISKS.md @@ -0,0 +1,26 @@ +# Risks: WS-CON-001 Contribution Record And Compensation Boundary + +| Risk | Impact | Mitigation | Owner | +|---|---|---|---| +| Competing award-eligibility models | Critical | ContributionPolicy is sole authority; semantic then physical clean cut with no fallback | CON-05A/B | +| Review commits without contribution | Critical | Mandatory flush-only participant and one REV-owned commit; fault-injection rollback | CON-07 + REV | +| Reviewer contribution depends on branch state | Critical | Required reviewer operation precedes every branch and has no FinalAcceptance/submitter input; separate accept-only submitter operation | CON-07 + REV-08/10 | +| Submitter contribution inferred from mutable decision shape | Critical | REV-owned immutable FinalAcceptance is the sole accepted_submission source; unique task/Review/Submission and source-shape constraints | REV + CON-03C/07 | +| Mandatory ART projection blocks product truth | Critical | No ART/evidence work in core transaction or release; optional successor only | CON-07/09/11 | +| Wrong frozen policy | Critical | Assignment/lease freeze before work; immutable versions; concurrency proof | CON-05A/06 | +| task.claim activates before submitter policy freeze | Critical | AUTH-PREP + task seam -> CON-05A hidden participant -> task-owned composition -> AUTH-13 activation; pre-activation real-kernel denial | AUTH + task + CON-05A | +| Dispatcher inherits handler authority | Critical | Dispatcher-only action; exact independent service authority for protected handlers | CON-02B/08A/10C + AUTH | +| Release cutoff misses admitted fulfillment work | Critical | Shared fence before every writer ordinal; maximum-ordinal same-session observation; both-order cutoff races; completion-only drain | CON-03D/08/10B/C/11 + REV-12A | +| Operations request authority leaks into execution | Critical | 10B persists bounded human requests only; 10C uses exact fixed-service actions, cross-executor denial, replay/finding proof, and projection-only mutation | CON-10B/10C + AUTH | +| Broad or dynamic service access | Critical | Closed ServiceIdentity/static rows, controlled provisioning, AUTH-09E, cross-service denial | AUTH + CON | +| Partial ART/REV custody transfer | High | Reference complete WS-XINT handoffs; no local subset or dual writer | AUTH | +| Cross-domain deadlock/partial commit | Critical | AUTH-first common prefix; operation-specific REV/task lifecycle-before-policy order; one session/commit; both-order PostgreSQL tests | AUTH + REV + CON | +| Prepared handle substitution or stale authority | Critical | Exact session/action/actor-ref/idempotency/request-digest binding; AUTH consumption after final-fact recomposition; single use and non-consumption on rejected substitution | AUTH + each mutation owner | +| Wrong grant substitutes for shipping authority | High | Exact submitter and reviewer grants only; unrelated project/admin grants deny; no adjudication dependency | AUTH + task/REV | +| Provider I/O under locks | Critical | Durable pre-I/O state; release transaction/fence before adapter call | CON-08A/outbox | +| Callback spoofing/replay | Critical | Exact service identity/static row, binding match, prepared protocol, idempotent receipt | CON-08B + AUTH | +| Legacy row ambiguity | High | Human-approved deterministic rebuild/classification; migration fails closed | Human + CON-05 | +| Premature public release | High | Hidden OpenAPI, exact manifest, AUTH activation, joint REV/CON gate | CON-11 + REV | +| Adjudication scope leaks into v0.1 | High | Accept/reject are terminal; no adjudication model/action/queue/state/contribution/readiness or initiative gate | REV + CON | + +No runtime work starts while a blocking decision or prerequisite remains open. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/RUNTIME_VERIFICATION.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/RUNTIME_VERIFICATION.md new file mode 100644 index 00000000..f017b5c2 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/RUNTIME_VERIFICATION.md @@ -0,0 +1,49 @@ +# Runtime Verification Contract: WS-CON-001 + +Every runtime chunk executes this template exactly after replacing +`` and `` with its row. It then runs one separate focused +report command for every concrete subsystem pattern in that row. The initial +erase, isolated PostgreSQL run, repository threshold, and all focused reports +are one evidence run; a pre-existing `.coverage` file is never accepted. + +```bash +ATTEMPT_ID="${ATTEMPT_ID:-$(date -u +%Y%m%dT%H%M%SZ)-$$}" +EVIDENCE_JSON="$(pwd)/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/evidence/-${ATTEMPT_ID}-isolated-tests.json" +mkdir -p "$(dirname "$EVIDENCE_JSON")" +test ! -e "$EVIDENCE_JSON" +(cd backend && .venv/bin/python -m coverage erase) +(cd backend && WORKSTREAM_TEST_ADMIN_DATABASE_URL=postgresql+asyncpg://workstream:workstream@localhost:5433/postgres .venv/bin/python scripts/run_isolated_tests.py --metadata-json "$EVIDENCE_JSON" --timeout-seconds 12600 -- .venv/bin/python -m pytest -q --ignore=tests/test_isolated_database_runner.py --cov=app --cov-report=term-missing --cov-fail-under=78) +(cd backend && .venv/bin/python -m coverage report --include='' --fail-under=90) +(cd backend && .venv/bin/ruff check ) +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +git diff --check +``` + +| Chunk | Separate focused subsystem reports (one `coverage report` per entry) | `` | +|---|---|---| +| CON-02A | `app/modules/outbox/*` | `app/modules/outbox app/db/models.py tests/test_outbox.py alembic/versions/.py` | +| CON-02B | `app/modules/outbox/*`; `app/workers/outbox.py` | `app/modules/outbox app/workers/outbox.py app/workers/celery_app.py app/core/config.py tests/test_outbox.py tests/test_config.py` | +| CON-02C | `app/modules/audit/*` | `app/modules/audit tests/test_audit.py` | +| CON-03A | `app/modules/compensation/*` | `app/modules/compensation app/db/models.py tests/test_compensation.py alembic/versions/.py` | +| CON-03B | `app/modules/contributions/*` | `app/modules/contributions app/modules/projects/models.py app/db/models.py tests/test_contributions.py tests/test_projects.py alembic/versions/.py` | +| CON-03C | `app/modules/contributions/*`; `app/modules/compensation/*` | `app/modules/contributions app/modules/compensation app/db/models.py tests/test_contributions.py tests/test_compensation.py alembic/versions/.py` | +| CON-03D | `app/modules/compensation/*` | `app/modules/compensation app/db/models.py tests/test_compensation.py alembic/versions/.py` | +| CON-04A | `app/modules/compensation/*` | `app/modules/compensation app/composition/compensation.py tests/test_compensation.py tests/test_authorization.py tests/test_api_contract_e2e.py` | +| CON-04B | `app/modules/contributions/*` | `app/modules/contributions app/modules/projects/repository.py app/composition/contributions.py tests/test_contributions.py tests/test_projects.py tests/test_authorization.py tests/test_api_contract_e2e.py` | +| CON-05A | `app/modules/contributions/*`; `app/modules/projects/*`; `app/modules/tasks/*`; `app/modules/checkers/*` | `app/modules/contributions app/modules/projects app/modules/tasks app/modules/checkers app/db/models.py tests/test_contributions.py tests/test_projects.py tests/test_tasks.py tests/test_checkers.py tests/test_authorization.py tests/test_alembic.py tests/test_api_contract_e2e.py alembic/versions/.py` | +| CON-05B | `app/modules/projects/models.py`; `app/modules/tasks/models.py`; `app/modules/checkers/models.py`; `app/db/models.py` | `app/modules/projects/models.py app/modules/tasks/models.py app/modules/checkers/models.py app/db/models.py tests/test_projects.py tests/test_tasks.py tests/test_checkers.py tests/test_alembic.py alembic/versions/.py` | +| CON-06 | `app/modules/contributions/*` | `app/modules/contributions tests/test_contributions.py tests/test_authorization.py` | +| CON-07 | `app/modules/contributions/*`; `app/modules/compensation/*` | `app/modules/contributions app/modules/compensation tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_outbox.py` | +| CON-08A | `app/modules/compensation/*`; `app/workers/compensation.py`; `app/interfaces/compensation.py`; `app/adapters/compensation/*` | `app/interfaces/compensation.py app/adapters/compensation app/modules/compensation app/modules/outbox/handlers.py app/workers/compensation.py app/workers/celery_app.py app/composition/compensation.py tests/test_compensation.py tests/test_outbox.py tests/test_external_service_adapters.py` | +| CON-08R | `app/modules/api_controls/*`; `app/api/deps/api_controls.py`; `app/core/config.py` | `app/modules/api_controls app/api/deps/api_controls.py app/core/config.py tests/test_api_rate_controls.py tests/test_config.py tests/test_alembic.py alembic/versions/.py` | +| CON-08B | `app/modules/compensation/*` | `app/modules/compensation app/api/internal_compensation.py app/composition/compensation.py tests/test_compensation.py tests/test_authorization.py tests/test_api_controls.py tests/test_api_rate_controls.py tests/test_api_contract_e2e.py` | +| CON-09A (optional) | Defined only by a separately approved refreshed contract | Do not execute from this table alone | +| CON-09B (optional) | Defined only by a separately approved refreshed contract | Do not execute from this table alone | +| CON-10A | `app/modules/contributions/*`; `app/modules/compensation/*` | `app/modules/contributions app/modules/compensation app/api/internal_contributions.py app/api/internal_compensation.py app/composition/contributions.py app/composition/compensation.py tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_api_contract_e2e.py` | +| CON-10B | `app/modules/contributions/*`; `app/modules/compensation/*`; `app/modules/audit/*` | `app/modules/contributions app/modules/compensation app/modules/audit app/api/internal_operations.py app/composition/contributions.py app/composition/compensation.py tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_outbox.py tests/test_audit.py` | +| CON-10C | `app/modules/contributions/*`; `app/modules/compensation/*`; `app/workers/contributions.py`; `app/workers/compensation.py` | `app/modules/contributions app/modules/compensation app/modules/outbox/handlers.py app/workers/contributions.py app/workers/compensation.py app/composition/contributions.py app/composition/compensation.py tests/test_contributions.py tests/test_compensation.py tests/test_outbox.py tests/test_authorization.py` | +| CON-11 | `app/modules/contributions/*`; `app/modules/compensation/*`; `app/modules/outbox/*`; `app/modules/audit/*`; `app/modules/api_controls/*`; `app/api/deps/api_controls.py`; `app/core/config.py`; `app/modules/projects/*`; `app/modules/tasks/*`; `app/modules/checkers/*`; `app/interfaces/compensation.py`; `app/adapters/compensation/*`; `app/workers/outbox.py`; `app/workers/contributions.py`; `app/workers/compensation.py`; `app/composition/contributions.py`; `app/composition/compensation.py`; `app/composition/outbox.py`; `app/api/internal_contributions.py`; `app/api/internal_compensation.py`; `app/api/internal_operations.py` | `app/composition/contributions.py app/composition/compensation.py app/composition/outbox.py tests/test_api_contract_e2e.py tests/test_authorization.py tests/test_contributions.py tests/test_compensation.py tests/test_outbox.py tests/test_audit.py` | + +If a named path differs after prerequisite merges, the chunk stops and its +contract is re-reviewed; it may not silently broaden a glob or skip the target. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/SOURCE_MANIFEST.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/SOURCE_MANIFEST.md new file mode 100644 index 00000000..30e297ca --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/SOURCE_MANIFEST.md @@ -0,0 +1,108 @@ +# Source Manifest: WS-CON-001 Contribution Record And Compensation Boundary + +## Reference inputs + +| File | SHA-256 | Status | +|---|---|---| +| `docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.md` | `cddbe20f4fadf5307f68519347bdd9520ef49b23fb0b92cad24c31fc9b34c640` | Working transcription; not canonical | +| `docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification(2).pdf` | `ce65e208076769f0bafb09779d60ab6f5fc0c596514d4e8f4cc03690c6e6d457` | Revised archival input; not runtime authority | +| `docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.pdf` | `34c4337f27e42a5b0ed5e153fe8ccd492ecede202c2764506a930d109aef66c1` | Original archival input; pre-existing user deletion remains untouched | + +## Trusted baseline + +- `origin/main` / merged REV PR #128 at + `0302bcf854a565d429e232ad6b076a1931ea74e4`. +- PR #128 merges the reviewed WS-REV-001 plan after AUTH-09A, AUTH PR #140, and + WS-XINT PR #139. It is planning authority, not Review runtime implementation. +- Runtime AUTH is 74 PermissionIds, 65 ActionIds, nine active, 56 planned. + AUTH-09A contributes eight planned identity-administration actions; no CON or + task-claim ActionId exists. +- PR #140 remains the source for AUTH activation-custody, prepared-protocol, + revised chunk, + operations, and verification contracts. It changes no runtime CON behavior, + registers no CON action, and activates no feature action. + +## Human boundary amendment + +- On 2026-07-17 the human fixed the v0.1 shipping path as + `Review(accept) -> FinalAcceptance -> accepted_submission` and explicitly + excluded adjudication lifecycle/actions/readiness. +- Merged REV PR #128 now plans FinalAcceptance, exact + `accepted`/`needs_revision`/`rejected` effects, two ordered CON participant + operations, and REV-12A lifecycle-control hooks. WS-CON implementation still + waits for each exact runtime chunk and consumes no sibling-worktree behavior. +- The amendment's `submission_version_id` is normalized to canonical + `Submission.id` / `submission_id`; current runtime already stores each + immutable version as a Submission row. +- Merged REV-04 retains `policy_context_ref` as the foreign key to exact locked + `ReviewPolicy.id` and `recorded_by` as the reviewer ActorProfile field; CON + consumes those names and REV owns/proves the lineage. +- `docs/review_closure.md`, `docs/review_final_adversarial_review.md`, and + `docs/review_adversarial_quality_review.md` are historical internal-review + recommendations, not live lifecycle specifications. Their older “second + review” or “overturned” proposals cannot delay FinalAcceptance, add a second + decision, or gate CON readiness. PLAN2 updates active operations/templates + only and preserves those review records as historical evidence. + +## Normative repository sources + +- `AGENTS.md` +- `README.md` +- `docs/glossary.md` +- `docs/architecture_lockdown.md` +- `docs/architecture_data_model.md` +- `docs/architecture_lifecycle_state_machine.md` +- `docs/decision_0005_postgres_is_the_record_database.md` +- `docs/decision_0007_async_first_execution.md` +- `docs/decision_0009_review_decisions_are_canonical.md` +- `docs/decision_0010_revision_context_rebase.md` +- `docs/decision_0012_workstream_authorization_service.md` +- `docs/decision_0013_immutable_artifact_storage_boundary.md` +- `docs/decision_0014_external_service_adapter_convention.md` +- `docs/decision_0015_project_contributor_roles_are_independent.md` +- `docs/spec_authorization_service.md` +- `docs/spec_artifact_storage_service.md` +- `.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/ACTIVATION_CUSTODY.md` +- `.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-PREP-prepared-mutation-protocol.md` +- `.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-13-task-assignment-cutover.md` +- `.agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/chunks/WS-AUTH-001-16-evidence-live-proof.md` +- `.agent-loop/initiatives/WS-REV-001-review-revision-lifecycle/CON_INTEGRATION_REVIEW.md` +- `.agent-loop/initiatives/WS-REV-001-review-revision-lifecycle/DECISIONS.md` +- `.agent-loop/initiatives/WS-REV-001-review-revision-lifecycle/PLAN.md` +- `.agent-loop/initiatives/WS-REV-001-review-revision-lifecycle/chunks/WS-REV-001-08-immutable-decision-kernel.md` +- `.agent-loop/initiatives/WS-REV-001-review-revision-lifecycle/chunks/WS-REV-001-10-contribution-integration-hidden-composition.md` +- `.agent-loop/initiatives/WS-REV-001-review-revision-lifecycle/chunks/WS-REV-001-12A-joint-lifecycle-release-control.md` +- `.agent-loop/policies/*` + +## Normative WS-XINT handoffs + +- `WS-XINT-001/REV_CON_HANDOFF.md`: core contribution participant, frozen + ContributionPolicyVersion, no core ART dependency. +- `WS-XINT-001/AUTH_ROLE_SERVICE_HANDOFF.md`: independent project grants, + fixed-service static matrix, AUTH-09E admission. +- `WS-XINT-001/AUTH_REV_HANDOFF.md`: complete REV activation-custody and hidden + behavior choreography. +- `WS-XINT-001/AUTH_ART_HANDOFF.md`: complete 25-action ART custody transfer; + referenced only, not a core CON dependency. +- `WS-XINT-001/DECISIONS.md`: D1-D13 ownership and transaction rules. + +## Runtime observations + +- Current code still contains the retired guide-bound economic schema; CON-05A + and 05B own semantic then physical removal after a human migration decision. +- No ContributionPolicy, ContributionRecord, CompensationAward, fulfillment, or + WS-CON action runtime exists yet. +- No FinalAcceptance runtime exists yet; merged planning assigns it to REV-04 + and makes that exact schema a prerequisite for CON-03C/07. +- Existing `Submission` is the versioned identity; no new SubmissionVersion is + required. +- ART preparation from PR #129 is inactive foundation only and does not approve + optional contribution-evidence projection. +- Sibling worktrees remain discovery evidence only. Merged REV planning is + authoritative for sequencing but does not satisfy its own runtime gates. + +## Adoption note + +The reference inputs contain useful invariants but do not override merged +repository decisions. CON-01 writes the active specification after explicit +approval and leaves archival inputs unchanged. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/STATUS.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/STATUS.md new file mode 100644 index 00000000..6338a39d --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/STATUS.md @@ -0,0 +1,90 @@ +# Status: WS-CON-001 Contribution Record And Compensation Boundary + +## Current status + +`WS-CON-001-PLAN3` completed its pre-external-review exact-SHA review at +`e968430b0c3b5f1432899c9aa31ef209b774eae0` after current-main reconciliation +with merged REV PR #128 at `0302bcf`, which also contains AUTH-09A after AUTH PR +#140. The prior planning snapshot `09128ee1aed941682c7cb59ca04698de496de682` +remains historical and no longer controls publication. The reviewed refresh +corrects the AUTH catalogue baseline, replaces the obsolete omnibus nullable CON +decision input with two ordered operations, and adopts REV-12A's exact +obligation-writer/ordinal/cutoff hooks. PLAN2's human-approved v0.1 +`Review(accept) -> FinalAcceptance -> accepted_submission` boundary remains +intact. Runtime code is unchanged. +CodeRabbit then opened five consolidated contract-quality threads. PLAN3's +planning-only repair added executable verification gates, restored exact AUTH +prerequisite ownership, moved optional CON-09B to a deferred proposal, aligned +the PR trust bundle, and recorded the external response/review log. All required +tracks passed exact SHA `a69fad3a32ad47e3bd60a79cd75f5867eefc52b3`. +The prior plan is superseded where it used the older policy aggregate, made ART +evidence mandatory, described service action rows as persisted assignments, +allowed partial activation-custody transfer, or let outbox dispatch imply +feature-handler authority. + +## Corrected boundary + +- ContributionPolicyVersion and ContributionRule decide award eligibility. +- Core Review -> ContributionRecord/Award is one PostgreSQL transaction with no + ART call or evidence projection. +- REV creates FinalAcceptance only for accept. Reviewer contributions source + Review directly; submitter contributions source FinalAcceptance only. +- Shipping authority uses exact submitter and reviewer grants only; unrelated + grants do not substitute and WS-CON has no adjudication dependency. +- Fixed services require closed ServiceIdentity, exact static matrix membership, + provisioned ActorProfile/link, AUTH-09E admission, and active action. +- ActionOwner is AUTH activation custody. Complete ART/REV transfers are + referenced from WS-XINT and not partially restated by CON. +- Outbox dispatch owns outbox mechanics only. Protected handlers need exact + independent authority. +- CON-09A/09B are deferred optional successors and do not gate the core release. +- AUTH PR #140 registers no CON ActionId and activates no feature action. Its + exact custody and prepared-protocol contracts are now upstream gates. +- Current main has 74 PermissionIds and 65 ActionIds: nine active and 56 + planned. AUTH-09A added eight planned identity-administration actions; no CON + or task-claim ActionId exists. +- `task.claim` activation must follow, not precede, the CON-05A hidden + TaskAssignment contribution-policy freeze. +- Merged REV planning requires the CON reviewer operation before the decision + branch and the accept-only submitter operation afterward; it rejects one + nullable omnibus participant input. +- REV-12A requires every CON fulfillment-obligation writer to fence before + monotonic ordinal allocation and requires same-session maximum-ordinal/drain + observation for the immutable delivery cutoff. + +## Active chunk + +No implementation chunk is active or starts automatically. PLAN3 external +review repair is complete; it does not authorize merge or CON-01. + +| Chunk | Status | Notes | +|---|---|---| +| `WS-CON-001-PLAN` | Complete; superseded baseline | Based on PR #139 / `5d353b6`; reviewed content `c4242e0` | +| `WS-CON-001-PLAN2` | Complete; unpublished | FinalAcceptance is REV-owned; CON trigger changes only; all required internal tracks pass | +| `WS-CON-001-PLAN3` | Complete; externally repaired and internally reviewed | CodeRabbit gates/AUTH scope/09B/trust repairs pass at `a69fad3` | +| `WS-CON-001-01` through `08B`, `10A` through `11` | Proposed | Separate explicit start required after PLAN3 and upstream merge refresh | +| `WS-CON-001-09A/09B` | Deferred optional | Separate approval and fresh ART/AUTH review required | + +## Open gates + +| Gate | Owner | Required action | +|---|---|---| +| FinalAcceptance and decision integration | REV + CON | REV-04 runtime persistence -> CON-03C; REV-09B lineage + CON-07 two-operation participant -> REV-10 hidden single-commit composition -> AUTH activation | +| Active specification/archive handling | Human | Approve CON-01 repository-owned specification | +| Pre-production legacy rows | Human | Choose deterministic rebuild or explicit classified migration before 05A/05B | +| D11 AdminRole candidates | Human + AUTH | Fix award-detail, delivery-recovery, and audit candidates before registration | +| Core WS-CON action registration/activation | AUTH | Add reviewed registration and later activation chunks; CON remains hidden | +| Fixed service runtime | AUTH | Complete AUTH-09A through 09E before protected service calls | +| Feature handler authority | Human + AUTH + CON | Approve exact identities/actions/static rows; no dispatcher inheritance | +| AUTH prepared protocol | AUTH | Merge AUTH-PREP after AUTH-09E; all CON-sensitive mutations consume its exact opaque handle contract | +| task.claim | AUTH + task + CON | Only PermissionId exists; after AUTH-10/PREP and stable task seam, merge CON-05A freeze and task-owned composition; AUTH-13 enumerates/registers/evaluates/activates afterward | +| review.claim/review.decision | AUTH + REV + CON | Complete REV custody transfer and AUTH-PREP; merge hidden CON participants and REV composition; AUTH-REV-06/08 activate afterward | +| Shared outbox | CON-02A/B | Land generic persistence/dispatcher after approval | +| Joint release | REV + CON + AUTH | Consume exact hidden manifest; optional evidence and ART are not prerequisites | +| Fulfillment cutoff/drain | CON + REV-12A | CON-03D ordinal; all writer/dispatch/callback hooks; CON-10B observation; CON-11 manifest -> REV-12A shared fence/controller | + +## Stop condition + +Do not edit runtime code, start CON-01, or merge PR #142 without explicit human +direction. The reviewed PLAN3 repair may refresh the existing PR only; it does +not authorize its merge or any successor start. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-01-canonical-contract-adoption.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-01-canonical-contract-adoption.md new file mode 100644 index 00000000..d938811b --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-01-canonical-contract-adoption.md @@ -0,0 +1,103 @@ +# Chunk Contract: WS-CON-001-01 - Canonical Contract Adoption And Architecture Decision + +## Goal + +Publish one repository-owned active contribution/compensation specification and +Decision 0016 reconciled with WS-XINT, without editing or restoring archival +inputs. + +## Risk + +L0 direction executed as L1 specification work; SLA P1. + +## Allowed files + +```text +docs/spec_contribution_compensation.md +docs/decision_0016_contribution_compensation_boundary.md +README.md only active-spec link/precedence note +active docs/templates explicitly inventoried by the chunk before review +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-01.json +``` + +## Not allowed + +```text +reference-spec bytes, names, checksums, or restoration +backend runtime, migrations, tests, workflows, dependencies +AUTH/ART/REV owned specifications/catalogues or action activation +roadmap changes without synchronized local XLSX/CSV exports +``` + +## Acceptance criteria + +- [ ] Decision number is 0016; 0015 remains independent project contributor + roles. +- [ ] Active spec defines ContributionPolicy/version/rules/award definitions, + ProjectCompensationAdapterBinding, ContributionRecord, CompensationAward, + fulfillment receipts/status, and shared outbox ownership. +- [ ] Retired guide-bound schema removal is complete and split across 05A/05B; + no alias/fallback survives. Missing ContributionPolicy setup is not silently + unpaid. +- [ ] Existing versioned Submission is retained. CON copies stabilized + artifact_hash lineage and performs no core ART/evidence operation. +- [ ] Active spec defines REV-owned accept-only FinalAcceptance with canonical + `submission_id`, `policy_context_ref`, and `recorded_by`; + FinalAcceptance-sourced submitter + contribution; direct Review-sourced reviewer contribution; and one REV-owned + commit. It adds no SubmissionVersion alias or adjudication dependency. +- [ ] Active spec adopts merged REV PR #128's two ordered operation-specific CON + inputs: reviewer before branch, accept-only submitter after FinalAcceptance + and accepted task effects; no nullable omnibus input. +- [ ] Optional evidence is clearly deferred with separate ART/AUTH approval and + is absent from the core release path. +- [ ] AUTH boundary matches PR #140 (adopting PR #139): independent project grants, fixed-service + static matrix/AUTH-09E, prepared mutations, AUTH-only activation, complete + ART/REV custody references, and no service-row startup dependency. +- [ ] Active spec lists the proposed 22 core surface mappings as unregistered, + non-final identifiers using `contribution.policy.*`; optional evidence is separate; protected handler + execution actions remain explicit human/AUTH gates until approved. +- [ ] Dispatcher authority is limited to outbox mechanics; delivery, + reconciliation, rebuild, and callback cannot inherit it. +- [ ] Active spec adopts REV-12A's single shared lifecycle controller/fence, + immutable monotonic fulfillment-root ordinal, every-writer fence order, + maximum-ordinal drain observation, and same-generation pre-cutoff completion + rules without moving controller ownership into CON. +- [ ] Exact D11 outcome and legacy-row decision are recorded before dependent + implementation. +- [ ] Public prefix is `/api/v1`; provider refs/credentials and settlement + ledgers are excluded. +- [ ] Conformance matrix maps every normative rule to a chunk/test/final gate. +- [ ] Archival inputs remain byte-for-byte untouched, including the user's + pre-existing deletion state. + +## Verification + +Run from the repository root: + +```bash +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_authorization_docs.py +python3 scripts/check_stale_artifact_contracts.py +PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -m pytest -q scripts/test_agent_gates.py +test -f docs/spec_contribution_compensation.md +test -f docs/decision_0016_contribution_compensation_boundary.md +test "$(rg -c 'docs/spec_contribution_compensation\.md' README.md)" -eq 1 +git diff --quiet origin/main...HEAD -- docs/reference_specs +test "$(sha256sum 'docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.md' | cut -d ' ' -f1)" = cddbe20f4fadf5307f68519347bdd9520ef49b23fb0b92cad24c31fc9b34c640 +test "$(sha256sum 'docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification(2).pdf' | cut -d ' ' -f1)" = ce65e208076769f0bafb09779d60ab6f5fc0c596514d4e8f4cc03690c6e6d457 +git diff --check +``` + +Pass requires every command to exit zero, both active documents to exist, one +README canonical link, no reference-input delta, both present archival hashes +to match, and all repository gates to pass. Required reviewers: senior, QA, +security, product, architecture, docs, reuse, CI integrity, and test delta when +scanners/tests change. + +## Stop + +Stop after reviewed specification and merge memory. Do not start CON-02A +automatically. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02A-shared-outbox-persistence.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02A-shared-outbox-persistence.md new file mode 100644 index 00000000..a7ed8ce3 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02A-shared-outbox-persistence.md @@ -0,0 +1,55 @@ +# Chunk Contract: WS-CON-001-02A - Shared Transactional Outbox Persistence + +## Goal and risk + +Land feature-neutral PostgreSQL outbox truth and caller-transaction append only. +L1 infrastructure/audit/data risk. + +## Allowed files + +```text +backend/app/modules/outbox/{__init__,models,schemas,repository,service}.py +backend/app/db/models.py +backend/alembic/versions/_shared_transactional_outbox.py +backend/tests/{test_outbox,test_alembic}.py +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-02A.json +``` + +## Not allowed + +```text +Celery/dispatcher/handler/route changes +review, contribution, compensation, AUTH, ART, task or project behavior +new JSON canonicalizer, idempotency framework, dependency or CI weakening +``` + +## Acceptance criteria + +- [ ] Immutable event identity/type/version/project/correlation/causation, + canonical payload/digest, idempotency key and occurrence time are separate + from mutable delivery state. +- [ ] Reuse `app.core.hashing.canonical_json_hash` and the existing + reserve/lock/complete idempotency shape; no second canonicalizer/framework. +- [ ] Caller AsyncSession append flushes but never commits/publishes; changed + payload under one identity conflicts; PostgreSQL proves duplicate races. +- [ ] No Celery, handler, broker, review, or compensation behavior is added. + +## Verification and reviewers + +Execute the exact clean isolated CON-02A row in `../RUNTIME_VERIFICATION.md`, +replace its migration placeholder with the one new revision, then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_outbox.py tests/test_alembic.py -k 'outbox and (migration or append or idempotency or duplicate or race or rollback)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/outbox/*' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/outbox app/db/models.py tests/test_outbox.py tests/test_alembic.py) +``` + +Pass requires a non-empty selected test set, PostgreSQL upgrade and guarded +downgrade plus duplicate-race proof, stable exact replay, changed-payload +conflict, caller rollback with no commit/publish, repository coverage at least +78 percent in the same clean run, and focused outbox coverage at least 90 +percent. Baseline plus +architecture, security/auth, product/ops, docs, reuse/dedup, test-delta, and CI +integrity are required. Stop before dispatcher behavior. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02B-shared-outbox-dispatcher.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02B-shared-outbox-dispatcher.md new file mode 100644 index 00000000..c47234b6 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02B-shared-outbox-dispatcher.md @@ -0,0 +1,95 @@ +# Chunk Contract: WS-CON-001-02B - Shared Outbox Dispatcher And Recovery + +## Goal and risk + +Implement feature-neutral claim/invoke/finalize, retry, dead-letter, replay, +retention, typed handler registry, claim validation, and drain observation. L1 +background-execution/operations/auth risk. + +## Allowed files + +```text +backend/app/modules/outbox/** +backend/app/composition/outbox.py +backend/app/workers/outbox.py +backend/app/workers/celery_app.py only dispatcher task registration +backend/app/core/config.py only bounded outbox/Celery/Redis settings +backend/tests/test_outbox.py +backend/tests/test_config.py only exact new settings +backend/tests/test_authorization.py only exact boundary proof +docs/spec_shared_outbox.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-02B.json +``` + +## Not allowed + +```text +contribution, compensation, review, artifact, or provider semantics +protected feature-handler authority or provider I/O +AUTH implementation edits; dynamic registry/plugins; second outbox +test/coverage/CI weakening +``` + +## Approved AUTH prerequisites and handoff inputs + +- AUTH must first merge the planned `outbox.dispatch` ActionId/PermissionId, + AUTH custodian, closed `workstream.outbox.dispatcher` ServiceIdentity and + singleton static row, controlled ActorProfile/link provisioning, AUTH-09E + admission, typed context, and PR #140 prepared-mutation protocol. +- The handoff supplies AUTH-owned prepare/consume/evaluate ports and the exact + session/action/actor-reference/idempotency/request-digest binding. CON does + not register those identifiers, provision service authority, query grants, + or implement the AUTH evaluator. Matrix and availability remain code-owned + AUTH validations. The hidden dispatcher stays disabled until later AUTH + evaluator integration and activation. + +## Acceptance criteria + +- [ ] Using the approved AUTH handoff, dispatcher claim composition locks and + recomposes canonical claim facts between AUTH prepare and AUTH + consume/evaluate; no claim mutation occurs before the supplied authorization + succeeds. +- [ ] Dispatcher claims with lease/generation fencing, commits and releases all + locks before invoking a handler, and alone applies typed outcomes to retry/ + dead-letter/final state. +- [ ] Handler receives immutable event/payload/idempotency/claim generation and + validates it through OutboxClaimValidationPort. It cannot lock or mutate the + OutboxEvent. +- [ ] Dispatcher authority permits claim/invoke/finalize only. Tests deny every + contribution, compensation, ART, REV, callback, provider, reconciliation, or + projection action; a feature handler cannot borrow outbox.dispatch. +- [ ] Each protected handler must present its independently approved AUTH + service context/action. Registration rejects handlers lacking that manifest. +- [ ] Stable Celery task IDs, bounded leases, retry/dead-letter/replay, + deterministic backoff, cancellation, crash recovery, and retention are + covered with isolated PostgreSQL/Redis proof. +- [ ] Same-session drain observation counts pending/claimed/retryable/in-flight + work without repository leakage or false zero. +- [ ] Missing provisioned dispatcher rows deny dispatch/readiness but do not + fail app startup or administrative provisioning. +- [ ] Changed subsystem coverage is at least 90 percent; global floor 78. + +## Verification + +Execute the exact clean isolated CON-02B row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_outbox.py tests/test_authorization.py tests/test_config.py -k 'dispatcher and (claim or authorization or deny or lease or generation or retry or dead_letter or replay or recovery or drain)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/outbox/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/workers/outbox.py' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/outbox app/workers/outbox.py app/workers/celery_app.py app/core/config.py tests/test_outbox.py tests/test_authorization.py tests/test_config.py) +``` + +Pass requires a non-empty selected test set, real-kernel denial without the +approved AUTH handoff, claim-generation fencing, crash recovery, bounded +retry/dead-letter/replay, accurate drain counts, no handler authority +inheritance, repository coverage at least 78 percent in the same clean run, and +both focused coverage reports at least 90 percent. + +## Review and stop + +Required tracks include all baseline, architecture, security, product, docs, +reuse, CI integrity, and test-delta. Stop after hidden dispatcher; do not enable +feature execution. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02C-shared-lifecycle-audit-participant.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02C-shared-lifecycle-audit-participant.md new file mode 100644 index 00000000..816a992c --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02C-shared-lifecycle-audit-participant.md @@ -0,0 +1,54 @@ +# Chunk Contract: WS-CON-001-02C - Shared Lifecycle Audit Participant + +## Goal and risk + +Extend the existing shared AuditEvent repository/service with one typed +caller-transaction lifecycle participant required by REV and CON. L1 audit/ +cross-domain-transaction risk. + +## Allowed files + +```text +backend/app/modules/audit/{schemas,repository,service}.py +backend/tests/test_audit.py +docs/architecture_data_model.md only exact shared-audit ownership note +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-02C.json +``` + +## Not allowed + +```text +AuditEvent schema/migration rewrite +review, contribution, compensation, task, AUTH or outbox event semantics +commit ownership, route, background executor, dependency or CI weakening +``` + +## Acceptance criteria + +- [ ] Typed `LifecycleAuditParticipant` accepts caller AsyncSession and bounded + canonical event input, reuses AuditRepository, flushes, and never commits. +- [ ] It preserves append-only AuditEvent identity and rejects credentials, + tokens, provider refs, unbounded payloads and caller-supplied authority facts. +- [ ] Caller rollback removes audit with all other transaction effects; exact + replay/idempotency ownership is explicit and no second audit ledger appears. +- [ ] REV-04 and CON-07 may depend on the merged interface without importing + feature services; this chunk implements no feature-specific event. + +## Verification and reviewers + +Execute the exact clean isolated CON-02C row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_audit.py -k 'participant and (rollback or payload or boundary or idempotency or replay)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/audit/*' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/audit tests/test_audit.py) +``` + +Pass requires a non-empty selected test set, flush-only rollback, closed typed +payload enforcement, exact replay idempotency, changed-payload conflict, +repository coverage at least 78 percent in the same clean run, and focused +audit coverage at least 90 percent. Senior engineering, QA/test, security/auth, +product/ops, architecture, docs, reuse/dedup and test-delta are required. Stop +after the feature-neutral participant. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03A-adapter-binding-persistence.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03A-adapter-binding-persistence.md new file mode 100644 index 00000000..dc54e53f --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03A-adapter-binding-persistence.md @@ -0,0 +1,42 @@ +# Chunk Contract: WS-CON-001-03A - Project Compensation Adapter-Binding Persistence + +## Goal and risk + +Persist immutable `ProjectCompensationAdapterBinding` identity/lifecycle +without adapter behavior. L1 economic/auth/data risk. + +## Allowed files + +```text +backend/app/modules/compensation/{__init__,models,schemas,repository}.py +backend/app/db/models.py +backend/alembic/versions/_project_compensation_adapter_bindings.py +backend/tests/{test_compensation,test_alembic}.py +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-03A.json +``` + +## Not allowed + +```text +AUTH actor/grant/ServiceIdentity/static-matrix edits +adapter, route, background executor, policy, award, receipt or delivery behavior +credentials, secrets, raw provider refs, dependency or CI weakening +``` + +## Acceptance criteria + +- [ ] Binding stores project, instrument, typed capability, canonical service + actor ID, non-secret route identity, state/version, and immutable lifecycle + timestamps; credentials/provider refs are impossible. +- [ ] Composite constraints preserve project/instrument ownership and valid + active/suspended/retired transitions. +- [ ] Schema supports callback guards but creates no ActorProfile, identity + link, ServiceIdentity, static row, adapter, route, or delivery behavior. +- [ ] Upgrade/downgrade and duplicate/state races use isolated PostgreSQL. + +## Verification and reviewers + +Execute CON-03A in `../RUNTIME_VERIFICATION.md`; changed compensation code is +at least 90 percent. Required tracks: senior, QA, security, product, +architecture, docs, reuse, and test-delta. Stop after schema. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03B-contribution-policy-persistence.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03B-contribution-policy-persistence.md new file mode 100644 index 00000000..60395b8e --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03B-contribution-policy-persistence.md @@ -0,0 +1,47 @@ +# Chunk Contract: WS-CON-001-03B - Contribution Policy Persistence + +## Goal and risk + +Persist `ContributionPolicy`, immutable versions, exact rules, award +definitions, and one-active-policy-per-project without commands. L1 economic/ +data risk. + +## Allowed files + +```text +backend/app/modules/contributions/{models,schemas,repository}.py +backend/app/modules/projects/models.py only contribution-policy relationship +backend/app/db/models.py +backend/alembic/versions/_contribution_policy.py +backend/tests/{test_contributions,test_projects,test_alembic}.py +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-03B.json +``` + +## Not allowed + +```text +service, route, claim, award result, adapter execution, AUTH or ART behavior +legacy fallback, alias, automatic conversion, or historical-row rewrite +public API, background executor, dependency or CI weakening +``` + +## Acceptance criteria + +- [ ] One active ContributionPolicy per project points to one same-project + published immutable ContributionPolicyVersion. +- [ ] Every publishable version has exactly one accepted_submission and one + completed_review ContributionRule; each is unpaid or compensated. +- [ ] Unpaid rules have no definition. Compensated rules have at least one and + at most two ContributionAwardDefinitions: at most one money and at most one + project_points definition, each with exact positive decimal/unit/binding/ + provenance constraints. +- [ ] Published/retired content is immutable; missing policy has no fallback. +- [ ] Legacy classification follows D2/CON-05 and rewrites no history. +- [ ] Upgrade/downgrade and selector/version races use isolated PostgreSQL. + +## Verification and reviewers + +Execute CON-03B in `../RUNTIME_VERIFICATION.md`; changed subsystems are at least +90 percent. Required tracks: senior, QA, security, product, architecture, docs, +reuse, and test-delta. Stop after schema. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03C-contribution-award-persistence.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03C-contribution-award-persistence.md new file mode 100644 index 00000000..367e2b53 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03C-contribution-award-persistence.md @@ -0,0 +1,65 @@ +# Chunk Contract: WS-CON-001-03C - Contribution And Award Persistence + +## Goal and risk + +Persist immutable contribution/award truth against exact merged +FinalAcceptance, Review, ReviewLease, TaskAssignment, and Submission targets. +L1 history/economic risk. + +## Allowed files + +```text +backend/app/modules/contributions/{__init__,models,schemas,repository}.py +backend/app/modules/compensation/{models,schemas,repository}.py +backend/app/db/models.py +backend/alembic/versions/_contribution_award_truth.py +backend/tests/{test_contributions,test_compensation,test_alembic}.py +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-03C.json +``` + +## Not allowed + +```text +review model/service/composition edits +service, route, background executor, receipt, artifact, reputation or legacy accepted-work settlement row behavior +mutable/void/delete/adjust path, dependency or CI weakening +``` + +## Acceptance criteria + +- [ ] Existing Submission is the version identity. Project/task/submission/ + FinalAcceptance/Review/lease/assignment/contributor and stabilized + artifact_hash lineage are same-chain and non-null as applicable. No + SubmissionVersion entity or `submission_version_id` alias is added. +- [ ] Reviewer rows are completed_review and bind source Review + ReviewLease + + reviewer + reviewer-frozen policy, with FinalAcceptance/assignment sources + null. Submitter rows are accepted_submission and bind source FinalAcceptance + + TaskAssignment + submitter + submitter-frozen policy, with direct Review/ + lease sources null; they are impossible for needs_revision/reject. +- [ ] Partial uniqueness enforces one completed_review per source Review and one + accepted_submission per source FinalAcceptance. Contributor identity is a + validated lineage field, never part of either uniqueness key. Checks reject + mixed, incomplete, or wrong-type source shapes. +- [ ] `source_final_acceptance_id` references REV's immutable record; the exact + FinalAcceptance task/project/submission/submitter/source-Review chain matches + the contribution, but CON does not infer acceptance from that Review. +- [ ] Each award references the exact ContributionRecord, its frozen + ContributionPolicyVersion, matching rule/definition, same project/contributor/ + contribution type, and same-project/instrument adapter binding. +- [ ] Unique `(contribution_record_id, instrument_type)` enforces at most one + money and one project_points award; quantity is exact and positive. +- [ ] Database enforces immutability/at-most-one but does not require a + contribution child during staged Review persistence before CON-07 flushes. +- [ ] At-least-one per valid Review is deferred to CON-07 + REV-10 + preflight. +- [ ] At-least-one accepted_submission per FinalAcceptance is deferred to + CON-07 + REV hidden composition + preflight. +- [ ] No mutable/void/delete/adjust path or legacy accepted-work settlement row/reputation schema. + +## Verification and reviewers + +Execute CON-03C in `../RUNTIME_VERIFICATION.md`; changed subsystems are at least +90 percent. Senior engineering, QA/test, security/auth, product/ops, +architecture, docs, reuse/dedup and test-delta are required. Stop if exact +REV-04 runtime FinalAcceptance/Review/ReviewLease targets are not merged. Merged +REV PR #128 is planning authority only and does not satisfy that runtime gate. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03D-delivery-receipt-status-persistence.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03D-delivery-receipt-status-persistence.md new file mode 100644 index 00000000..0ed7cb0c --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03D-delivery-receipt-status-persistence.md @@ -0,0 +1,57 @@ +# Chunk Contract: WS-CON-001-03D - Delivery, Receipt, And Status Persistence + +## Goal and risk + +Persist outbound identity, acknowledgement, immutable fulfillment receipts and +rebuildable status separately. L1 payment/audit risk. + +## Allowed files + +```text +backend/app/modules/compensation/{models,schemas,repository}.py +backend/app/db/models.py +backend/alembic/versions/_compensation_delivery_receipts.py +backend/tests/{test_compensation,test_alembic}.py +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-03D.json +``` + +## Not allowed + +```text +background executor, callback, adapter, router or reconciliation behavior +provider request/attempt/balance, points ledger or settlement data +AUTH/ART edit, dependency or CI weakening +``` + +## Acceptance criteria + +- [ ] Immutable award/event/payload/binding/idempotency identities are retained; + acknowledgement is not fulfillment; receipts are append-only and terminal. +- [ ] Closed stored values are exact: receipt `reported_status` is `fulfilled` + or `failed`; delivery status is `pending_delivery` or + `acknowledged_by_adapter`; fulfillment status is `pending`, `failed`, or + `fulfilled`. No synonym or provider status is persisted. +- [ ] Delivery state durably represents fenced pre-I/O `in_flight` ownership, + the originating dispatcher claim generation, retryable recovery and callback + suppression without storing a provider payment attempt. Crash recovery cannot + erase or guess whether remote I/O may have started. +- [ ] Every fulfillment-obligation root has one immutable, database-allocated, + monotonically increasing `fulfillment_obligation_ordinal` and exact lifecycle + generation lineage. Requeue, successor, and repair rows retain their canonical + root identity; they do not allocate a second root ordinal. Uniqueness and + immutability constraints support REV-12A cutoff capture without making the + ordinal a caller-supplied or provider field. +- [ ] Status is rebuildable and cannot overwrite award/receipt truth. +- [ ] Callback-before-ack, duplicate exact receipt and changed receipt are + representable without provider-attempt/balance/ledger data. +- [ ] State constraints permit failed then fulfilled, prohibit any transition + away from fulfilled, prohibit partial fulfillment, and preserve every failed + receipt without allowing it to mutate award quantity or truth. +- [ ] Upgrade/downgrade and receipt/delivery races use isolated PostgreSQL. + +## Verification and reviewers + +Execute CON-03D in `../RUNTIME_VERIFICATION.md`; changed compensation code is at +least 90 percent. Senior engineering, QA/test, security/auth, product/ops, +architecture, docs, reuse/dedup and test-delta are required. Stop after schema. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-04A-hidden-adapter-binding-service.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-04A-hidden-adapter-binding-service.md new file mode 100644 index 00000000..6cb7039a --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-04A-hidden-adapter-binding-service.md @@ -0,0 +1,64 @@ +# Chunk Contract: WS-CON-001-04A - Hidden Adapter-Binding Service + +## Goal and risk + +Implement authorization-ready binding create/read/suspend/resume domain behavior +and canonical resource composition while production routes remain unregistered +and AUTH actions remain planned. Retirement stays planned until dependency rows +exist. L1 payment/auth risk. + +## Allowed files + +```text +backend/app/modules/compensation/{schemas,repository,service}.py +backend/app/composition/compensation.py +backend/tests/{test_compensation,test_authorization,test_api_contract_e2e}.py +docs/spec_contribution_compensation.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-04A.json +``` + +## Not allowed + +```text +production router registration, policy commands, delivery or callback +AUTH catalogue/grant/kernel/service-actor edits +concrete adapter, provider secret/ref, dependency or CI weakening +``` + +## Acceptance criteria + +- [ ] AUTH's registration checkpoint is merged: exact planned binding actions, + typed context contracts, applicable AdminRoleGrant definitions and prepared + `T` protocol, plus the planned `compensation.fulfillment.report` ActionId/new + PermissionId plus the human/AUTH-approved callback ServiceIdentity and exact + static action row, with controlled ActorProfile/link provisioning and + AUTH-09E admission. Both binding and callback actions remain planned and + fail-closed. This chunk changes no AUTH file and uses only an explicit + test decision/fake below the authorization boundary for domain-success tests. +- [ ] Create validates canonical active service ActorProfile/link, immutable + approved ServiceIdentity, exact static row, and non-secret route identity. +- [ ] Mutations follow PLAN locks and transaction-revalidate authority; own-state + concurrent suspend/resume is deterministic. AUTH prepares its exact bound + handle first; CON locks binding/project rows and recomposes final facts; AUTH + consumes the handle and evaluates once before CON mutates or flushes. +- [ ] The service accepts only an allowed decision whose complete resource- + context digest, matched AdminRoleGrant ID and covered project match the + locked binding facts; mismatched decision evidence is rejected. It flushes + and never commits. The later AUTH activation gate—not a CON role-aware + fake—proves Finance eligibility and every excluded/revoked/scope case. +- [ ] Retire remains registered/planned but non-executable; any attempt fails + closed with stable not-active behavior. CON-10B later implements its + dependency-aware resource behavior after assignment/lease/award/delivery rows + exist; the post-CON-10B AUTH gate alone activates the action. +- [ ] Claims/delivery/callback races remain owned by 05/06/08A/08B/REV-13. +- [ ] Production OpenAPI remains unchanged. +- [ ] A later AUTH-owned gate integrates the central evaluators against this + merged composer and alone changes availability. CON-04B cannot start until + that activation passes. + +## Verification and reviewers + +Execute CON-04A in `../RUNTIME_VERIFICATION.md`; changed code is at least 90 +percent. Senior engineering, QA/test, security/auth, product/ops, architecture, +docs, reuse/dedup and test-delta are required. Stop after hidden behavior. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-04B-hidden-contribution-policy-service.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-04B-hidden-contribution-policy-service.md new file mode 100644 index 00000000..190a3ae7 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-04B-hidden-contribution-policy-service.md @@ -0,0 +1,70 @@ +# Chunk Contract: WS-CON-001-04B - Hidden Contribution-Policy Service + +## Goal and risk + +Implement hidden read/draft/update/publish/retire ContributionPolicy behavior +and canonical resource composition while routes remain absent and AUTH actions +remain planned. L1 economic/auth risk. + +## Allowed files + +```text +backend/app/modules/contributions/{schemas,repository,service}.py +backend/app/modules/projects/repository.py only policy relationship locking +backend/app/composition/contributions.py +backend/tests/{test_contributions,test_projects,test_authorization,test_api_contract_e2e}.py +docs/spec_contribution_compensation.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-04B.json +``` + +## Not allowed + +```text +production router registration, task/review claim integration, award results +AUTH catalogue/grant/kernel/static-matrix edits, adapter/provider calls +legacy fallback, dependency or CI weakening +``` + +## Approved AUTH prerequisites and deferred activation gate + +- Before this chunk starts, AUTH must merge reviewed registration of the + planned `contribution.policy.*` actions, stable permission mapping, typed + contexts, ActionOwner custody, and PR #140 prepared-mutation ports. The + actions remain planned. CON does not edit the AUTH catalogue, grants, kernel, + ActionOwner custody, or static matrix. +- After this hidden feature manifest merges, AUTH alone integrates evaluators + and activates the actions. CON-05A waits for that activation. + +## Acceptance criteria + +- [ ] AUTH prepares its exact bound handle first. Publish then locks project, + active policy, version, rules, definitions, and bindings; recomposes final + facts; AUTH consumes the handle and evaluates once; only then may the caller + atomically update current_published_version_id with audit/outbox. +- [ ] Allowed decision evidence matches complete resource digest, grant ID, + project scope, request, and correlation. Service flushes and never commits. +- [ ] Explicit unpaid is valid. Missing/incomplete/contradictory setup is a + stable failure. No legacy authority executes. +- [ ] Concurrent draft/publish/retire/selector/binding changes are + deterministic. Production OpenAPI remains unchanged. +- [ ] The feature manifest is sufficient for later AUTH evaluator integration + and activation without transferring any AUTH-owned work to CON. + +## Verification and reviewers + +Execute the exact clean isolated CON-04B row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_contributions.py tests/test_projects.py tests/test_authorization.py tests/test_api_contract_e2e.py -k '(policy or publish or retire or binding) and (authorization or rollback or concurrency or idempotency or missing or invalid or openapi)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/contributions/*' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/contributions app/modules/projects/repository.py app/composition/contributions.py tests/test_contributions.py tests/test_projects.py tests/test_authorization.py tests/test_api_contract_e2e.py) +``` + +Pass requires a non-empty selected test set, supplied prepared-authorization +ordering, flush-only rollback, deterministic concurrent publication/binding +changes, missing-policy failure, hidden OpenAPI, repository coverage at least +78 percent in the same clean run, and focused contribution coverage at least 90 +percent. Required tracks: senior, QA, security, product, architecture, docs, +reuse, and test-delta. Stop after hidden behavior. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-05A-legacy-economic-terms-cutover-and-task-freeze.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-05A-legacy-economic-terms-cutover-and-task-freeze.md new file mode 100644 index 00000000..c5c836ca --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-05A-legacy-economic-terms-cutover-and-task-freeze.md @@ -0,0 +1,106 @@ +# Chunk Contract: WS-CON-001-05A - Legacy Economic Terms Cutover And Task Freeze + +## Goal + +Remove the retired guide-bound economic contract from every semantic consumer, +classify existing rows, and freeze the active published +ContributionPolicyVersion on each successful new TaskAssignment. Physical dead- +schema removal belongs to 05B. + +## Risk + +L1 economic/task lifecycle/authorization; SLA P1. + +## Allowed files + +```text +backend/app/modules/contributions/{ports,service}.py +backend/app/modules/projects/{schemas,repository,service}.py only legacy consumer removal +backend/app/modules/tasks/{models,schemas,repository,service}.py only cutover/freeze +backend/app/modules/checkers/{schemas,repository,service,runner}.py only legacy consumer removal +backend/alembic/versions/_task_assignment_contribution_policy_freeze.py +backend/app/db/models.py +backend/tests/{test_contributions,test_projects,test_tasks,test_checkers,test_authorization,test_alembic,test_api_contract_e2e}.py +docs/spec_contribution_compensation.md +docs/architecture_data_model.md only exact implemented reconciliation +docs/operations_payment_reputation.md only implemented operations +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-05A.json +``` + +## Not allowed + +```text +task-claim permission/grant/kernel implementation +ReviewLease or Review behavior; contribution/award creation +public policy routes; dead physical schema removal +fallback, alias, automatic conversion, or guessed historical rewrite +provider/artifact calls; unrelated checker behavior +``` + +## Acceptance criteria + +- [ ] Every new TaskAssignment has immutable non-null + `submitter_contribution_policy_version_id`. +- [ ] Exact merged Submission.task_assignment_id lineage is preserved; no + parallel submission identity is added. +- [ ] No runtime/API/setup/task/checker/review consumer treats retired guide- + bound terms as current economic authority. A zero-consumer scanner proves + remaining physical schema is unreachable until 05B. +- [ ] Stable PermissionId `task.claim` exists but no task-claim ActionId is + registered. AUTH-10 exact same-project submitter ProjectRoleGrant and + AUTH-PREP contracts are merged; no unrelated project/admin grant substitutes + and CON contains no role logic. +- [ ] AUTH prepares exact submitter authority first. Task-owned composition + locks canonical task/assignment facts, invokes the CON participant to lock + active ContributionPolicy, published version, exact rule/definition/binding + dependencies and return one same-project version, then recomposes final + facts. AUTH consumes the handle and evaluates once before TaskAssignment is + created with that immutable version. CON flushes only and never commits. +- [ ] CON-05A and task-owned claim composition merge while the task-claim + ActionId remains absent. `WS-AUTH-001-13` enumerates/registers the exact + action, integrates its evaluator, and activates only after the merged feature + manifest proves the freeze, canonical guards, rollback, and real-kernel + unavailable behavior before activation. +- [ ] Missing/invalid policy fails with no assignment/task/audit/outbox partial + state. Later publication never updates an assignment. +- [ ] Publish versus claim and binding-state versus claim pass both lock orders + without deadlock or mixed versions. +- [ ] Existing rows follow the approved deterministic classification and cannot + enter new Review decisions without a valid freeze. Migration fails on + ambiguity and downgrade refuses post-cutover data loss. +- [ ] Changed subsystems remain at least 90 percent; global floor remains 78. + +## Verification + +Execute the exact clean isolated CON-05A row in `../RUNTIME_VERIFICATION.md`, +replace its migration placeholder with the one new revision, then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_contributions.py tests/test_projects.py tests/test_tasks.py tests/test_checkers.py tests/test_authorization.py tests/test_alembic.py tests/test_api_contract_e2e.py -k '(policy or assignment or claim or migration or downgrade) and (freeze or rollback or race or lock or ambiguous or authorization or lineage)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/contributions/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/projects/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/tasks/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/checkers/*' --fail-under=90) +legacy_pattern='locked_''payment_''policy_version|payment_''policies|accepted_''payment_rule|revision_''payment_rule|rejection_''payment_rule' +if rg -n "$legacy_pattern" backend/app --glob '*.py' --glob '!**/models.py' --glob '!db/models.py'; then + exit 1 +else + rg_status=$? + test "$rg_status" -eq 1 +fi +``` + +Pass requires a non-empty selected test set, upgrade and guarded downgrade, +exact assignment freeze and Submission lineage, full rollback on missing or +ambiguous policy, both publication/claim and binding/claim race orders, +real-kernel denial before activation, no runtime legacy-policy consumer, +repository coverage at least 78 percent in the same clean run, and every +focused report at least 90 percent. + +## Review and stop + +Required tracks: senior, QA, security, product, architecture, docs, reuse, test- +delta, and CI integrity. Stop if exact task/Submission lineage, AUTH-PREP, +task-owned composition seam, or migration classification is not merged. Do not +wait for or perform `task.claim` activation inside this chunk. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-05B-legacy-economic-schema-removal.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-05B-legacy-economic-schema-removal.md new file mode 100644 index 00000000..068869a2 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-05B-legacy-economic-schema-removal.md @@ -0,0 +1,70 @@ +# Chunk Contract: WS-CON-001-05B - Legacy Economic Schema Removal + +## Goal and risk + +Delete the now-unreachable guide-bound economic model, tables, columns, +constraints, and compatibility code after 05A proves zero semantic consumers. +L1 migration/historical-data risk. + +## Allowed files + +```text +backend/app/modules/projects/{models,schemas,repository,service}.py only dead schema removal +backend/app/modules/tasks/{models,schemas,repository,service}.py only dead references +backend/app/modules/checkers/{models,schemas,repository,service,runner}.py only dead references +backend/app/db/models.py +backend/alembic/versions/_remove_legacy_project_economic_schema.py +backend/tests/{test_projects,test_tasks,test_checkers,test_alembic,test_api_contract_e2e}.py +docs/{architecture_data_model,operations_payment_reputation,spec_contribution_compensation}.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-05B.json +``` + +## Not allowed + +```text +new ContributionPolicy/award behavior or inferred backfill +ReviewLease/Review/contribution/award behavior +AUTH, ART, provider, frontend, dependency or CI changes +``` + +## Acceptance criteria + +- [ ] 05A zero-consumer proof still passes on current trusted main. +- [ ] Approved classification drains/rebuilds or explicitly maps every row; + ambiguous meaning fails migration and never guesses a policy version. +- [ ] Dead model/tables/columns/FKs/indexes and API/OpenAPI references are absent + after upgrade; ContributionPolicy and frozen references remain valid. +- [ ] Downgrade is data-loss aware, requires intake disabled, and never revives + the removed schema as executable authority. +- [ ] PostgreSQL upgrade/downgrade and fresh install pass; changed code remains + at least 90 percent and repository coverage at least 78 percent. + +## Verification + +Execute the exact clean isolated CON-05B row in `../RUNTIME_VERIFICATION.md`, +replace its migration placeholder with the one removal revision, then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_projects.py tests/test_tasks.py tests/test_checkers.py tests/test_alembic.py tests/test_api_contract_e2e.py -k '(upgrade or downgrade or fresh or migration or schema) and (legacy or economic or contribution_policy)') +legacy_pattern='Payment''Policy|payment_''policies|locked_''payment_''policy_version|accepted_''payment_rule|revision_''payment_rule|rejection_''payment_rule' +if rg -n "$legacy_pattern" backend/app docs/architecture_data_model.md docs/operations_payment_reputation.md docs/spec_contribution_compensation.md; then + exit 1 +else + rg_status=$? + test "$rg_status" -eq 1 +fi +(cd backend && .venv/bin/python -m coverage report --include='app/modules/projects/models.py' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/tasks/models.py' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/checkers/models.py' --fail-under=90) +``` + +Pass requires a non-empty selected test set, PostgreSQL upgrade, guarded +downgrade, fresh install, zero retired schema/API/OpenAPI references, preserved +ContributionPolicy freezes, repository coverage at least 78 percent in the same +clean run, and every focused model report at least 90 percent. + +## Review and stop + +Required tracks: senior, QA, security, product, architecture, docs, reuse, test- +delta, and CI integrity. Stop before CON-06. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-06-review-lease-contribution-policy-freeze.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-06-review-lease-contribution-policy-freeze.md new file mode 100644 index 00000000..44fe78a8 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-06-review-lease-contribution-policy-freeze.md @@ -0,0 +1,74 @@ +# Chunk Contract: WS-CON-001-06 - ReviewLease Contribution-Policy Freeze Participant + +## Goal + +Deliver the narrow CON policy lookup/freeze participant that REV invokes inside +the review-claim transaction. Reviewer award eligibility is frozen before +review work begins. + +## Risk + +L1 economic/review lifecycle/authorization; SLA P1. + +## Allowed files + +```text +backend/app/modules/contributions/{ports,service}.py +backend/tests/{test_contributions,test_authorization}.py +docs/spec_contribution_compensation.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-06.json +``` + +## Not allowed + +```text +review queue/lease policy, model, migration, service, route, or composition +AUTH catalogue/grant/kernel changes; review decision or award creation +task assignment changes; provider/artifact/adapter calls +``` + +## Acceptance criteria + +- [ ] Port accepts caller AsyncSession and canonical locked project/claim facts, + locks one active ContributionPolicy and published version plus referenced + definitions/bindings, returns the exact version ID, and never commits. +- [ ] Missing/inactive/invalid policy or binding returns stable failure with no + CON/audit/outbox partial state. +- [ ] REV-owned ReviewLease has immutable non-null + `reviewer_contribution_policy_version_id` and REV owns its write/wiring. +- [ ] review.claim uses exact active same-project reviewer ProjectRoleGrant; + unrelated project/admin grants do not substitute. No-self-review and REV + lifecycle guards remain REV-owned; no adjudication behavior or dependency is + introduced. +- [ ] AUTH-PREP locks reviewer authority and prepares its exact bound handle; + REV locks queue/lease/Submission facts; CON locks policy dependencies and + returns the version; REV recomposes final facts; AUTH consumes/evaluates once + before REV writes the lease freeze. CON flushes only and never commits. +- [ ] CON hidden port and REV hidden composition merge while review.claim + remains planned; AUTH later integrates the evaluator and alone activates. +- [ ] Policy publish and binding state versus claim pass both lock orders; + changed modules stay at least 90 percent and global floor stays 78. + +## Verification + +Execute the exact clean isolated CON-06 row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_contributions.py tests/test_authorization.py -k '(review or lease or claim or policy) and (freeze or lock or race or rollback or authorization or deny or no_self_review)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/contributions/*' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/contributions tests/test_contributions.py tests/test_authorization.py) +``` + +Pass requires a non-empty selected test set, caller-session flush-only freeze, +both publish/claim and binding/claim race orders, missing-policy rollback, +same-project reviewer authorization with unrelated-grant and self-review +denials, repository coverage at least 78 percent in the same clean run, and +focused contribution coverage at least 90 percent. + +## Review and stop + +Required tracks: senior, QA, security, product, architecture, docs, reuse, and +test-delta. Stop if REV lease schema/caller facts or review.claim authority are +not merged. CON owns no review composition. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-07-atomic-review-contribution-award-participant.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-07-atomic-review-contribution-award-participant.md new file mode 100644 index 00000000..750f544d --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-07-atomic-review-contribution-award-participant.md @@ -0,0 +1,127 @@ +# Chunk Contract: WS-CON-001-07 - Atomic Review Contribution And Award Participant + +## Goal + +Implement the mandatory flush-only participant that creates reviewer and +FinalAcceptance-sourced submitter contributions, evaluates frozen +ContributionRules, creates applicable awards, and returns typed audit/outbox +inputs in the caller-owned Review transaction. It performs no evidence +projection or ART work. + +## Risk + +L1 economic/canonical-judgment/cross-domain transaction; SLA P1. + +## Allowed files + +```text +backend/app/modules/contributions/{schemas,repository,service,ports}.py +backend/app/modules/compensation/{repository,service}.py +backend/tests/{test_contributions,test_compensation,test_authorization,test_outbox}.py +docs/spec_contribution_compensation.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-07.json +``` + +## Not allowed + +```text +Review policy/model/service/route/composition wiring or commit +public route registration; optional/no-op participant +AUTH catalogue/grant/kernel edits or materialize actions +ART capability/repository/provider call or evidence projection row/event +mutable/delete/void/adjust contribution/award path; reputation scoring +``` + +## Participant operations + +One mandatory typed participant uses the caller AsyncSession and exposes two +ordered operations rather than an omnibus nullable request. + +The reviewer operation receives exact locked Review, ReviewLease, versioned +Submission, project/task, reviewer ActorProfile, lease-frozen reviewer +ContributionPolicyVersion, originating `review.decision` +AuthorizationDecision, request/correlation references, and server-derived +stabilized `Submission.artifact_hash`. It never receives FinalAcceptance, +TaskAssignment contribution-source lineage, submitter, or submitter policy. + +The submitter operation exists only after REV creates FinalAcceptance and +applies accepted task/assignment effects. It receives exact locked +FinalAcceptance, TaskAssignment, versioned Submission, project/task, submitter +ActorProfile, assignment-frozen submitter ContributionPolicyVersion, the same +authorization/request/correlation lineage, and stabilized artifact hash. It +never uses direct Review/ReviewLease contribution-source fields. + +## Acceptance criteria + +- [ ] Every valid committed Review creates exactly one reviewer + `completed_review`. Accept requires exactly one same-chain FinalAcceptance and + creates one submitter `accepted_submission` from it; needs_revision/reject + require no FinalAcceptance and create no submitter record. +- [ ] REV calls the reviewer operation after appending Review/findings/ + resolutions, consuming the lease, and closing the queue but before any + decision branch. It therefore validates Review/ReviewLease lineage without + requiring branch effects. REV then applies the exact outcome. Accept creates + FinalAcceptance, sets Task `accepted`, and completes the Assignment before the + submitter operation. Needs revision keeps the Assignment active and reject + blocks only the same-task Assignment; neither invokes the submitter operation. + CON owns none of those lifecycle effects. +- [ ] Repeated idempotent decision returns the same rows; a later revision + Review creates a distinct reviewer contribution; automated outcomes create + none. +- [ ] Reviewer uses lease-frozen policy; submitter uses assignment-frozen + policy. Matching explicit unpaid rule creates no award; compensated rule + creates at most one money and one project-points award copied from immutable + definitions. +- [ ] CON copies the supplied stabilized digest exactly into + ContributionRecord.artifact_hash. It does not load/rederive it or call ART. +- [ ] Each operation validates only its exact source shape and frozen policy. + Both receive the allowed review.decision reference whose actor, action, + resource digest, matched reviewer grant/project, request, and correlation + match the locked transaction; CON does not re-evaluate it. +- [ ] Both operations use caller AsyncSession, stage contribution/award rows, + return canonical typed audit/outbox inputs, flush, and never commit. REV + collects results from the reviewer operation and, on accept, the later + submitter operation, then stages shared audit/outbox rows before the single + caller commit. CON creates no evidence projection or evidence-request event. +- [ ] CON never reads REV/AUTH repositories or evaluates review.decision. REV + owns canonical composition and the single route commit. +- [ ] AUTH registration -> CON participant -> REV hidden composition -> AUTH + evaluator/activation order is proven. Real kernel denies while planned. +- [ ] Fault injection after the reviewer operation, after every branch effect, + after FinalAcceptance, after the submitter operation, and at every later REV + audit/outbox step rolls back Review/FinalAcceptance/task/assignment/ + contribution/award/audit/outbox together. The reviewer operation never + commits independently and no post-commit repair path exists. +- [ ] No FinalAcceptance create action/API exists. Static/runtime proof finds no + adjudication policy, grant/action, queue/lease, state, decision, contribution, + conditional branch, readiness check, or initiative dependency. +- [ ] Static/runtime spies prove zero ART capability, repository, preparation, + provider, or evidence calls in every decision path. +- [ ] PostgreSQL uniqueness, replay, changed-fact conflict, and concurrency tests + pass; changed code is at least 90 percent and repository floor at least 78. + +## Verification + +Execute the exact clean isolated CON-07 row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_outbox.py -k '(review or final_acceptance or contribution or award) and (fault or rollback or replay or idempotency or uniqueness or conflict or concurrency or no_art)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/contributions/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/compensation/*' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/contributions app/modules/compensation tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_outbox.py) +``` + +Pass requires a non-empty selected test set, fault injection after every +reviewer/branch/FinalAcceptance/submitter/audit/outbox stage with total +rollback, exact replay idempotency, changed-fact conflict, database uniqueness +under concurrency, all three decision branches, zero ART/provider calls, +repository coverage at least 78 percent in the same clean run, and both focused +reports at least 90 percent. + +## Review and stop + +Required tracks: senior, QA, security, product, architecture, docs, reuse, and +test-delta. Stop after the participant. REV, not CON-07, owns integration and +production execution. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08A-outbound-compensation-delivery.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08A-outbound-compensation-delivery.md new file mode 100644 index 00000000..75793e22 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08A-outbound-compensation-delivery.md @@ -0,0 +1,104 @@ +# Chunk Contract: WS-CON-001-08A - Outbound Compensation Delivery Handler + +## Goal and risk + +Handle committed fulfillment-request events, persist durable pre-I/O delivery +state, call the typed external adapter after commit, and return a typed outbox +outcome. L1 economic/external-service/auth risk. + +## Prerequisites + +- CON-07 and shared outbox merged; +- exact outbound-delivery ServiceIdentity and ActionId/static row approved and + registered as planned by AUTH, or an explicitly approved closed + dual-principal design; +- provisioned service ActorProfile/link, AUTH-09E admission, typed context, and + prepared protocol; the action remains planned while this hidden behavior + merges; +- ADR 0014 typed adapter/factory composition and lifecycle fence port. + +## Allowed files + +```text +backend/app/modules/compensation/{schemas,repository,service,ports}.py +backend/app/interfaces/compensation.py +backend/app/adapters/compensation/** +backend/app/modules/outbox/handlers.py only explicit handler registration +backend/app/composition/compensation.py +backend/app/workers/compensation.py +backend/app/workers/celery_app.py only delivery task registration +backend/tests/{test_compensation,test_outbox,test_authorization,test_external_service_adapters}.py +docs/spec_contribution_compensation.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-08A.json +``` + +## Not allowed + +```text +outbox claim/finalization transitions; callback behavior +generic dispatcher identity executing delivery +AUTH implementation; provider SDK/concrete adapter import in domain service +database/fence lock held during external I/O +``` + +## Acceptance criteria + +- [ ] Handler validates committed claim generation but never locks/mutates the + OutboxEvent. Dispatcher later applies its typed outcome. +- [ ] Delivery authority is independent from `outbox.dispatch`. Dispatcher is + denied delivery; delivery identity is denied dispatch and every other + handler/action; humans are denied fixed-service execution. +- [ ] Prepared authorization locks service ActorProfile/link and validates exact + ServiceIdentity/static row/action as code-owned facts. AUTH prepares its exact + bound handle; CON locks award/binding/delivery rows and recomposes final + facts; AUTH consumes/evaluates once before durable delivery mutation. +- [ ] Durable in-flight generation and exact event/payload/binding/idempotency + identity commit before adapter I/O. The already-claimed command resolves its + immutable obligation root, ordinal, and lifecycle generation under the shared + `JointLifecycleMutationFence`. In `delivery_draining`, only a same-generation + root at or below the persisted cutoff may enter durable `in_flight`; no new + root, requeue, successor, or repair work is allowed. +- [ ] The pre-I/O transaction commits and releases every database transaction + and lifecycle fence before the adapter call. Finalization occurs in a new + fenced transaction for the same root. A lost pre-I/O race returns the same + event to retryable pending without changing award or delivery truth; only the + shared dispatcher mutates outbox claim/retry/dead-letter state. +- [ ] Adapter result cannot change award identity/quantity. Retry, ambiguous + completion, acknowledgement, callback-before-ack, cancellation, and replay + preserve monotonic delivery/receipt truth. +- [ ] Provider I/O is only through typed capability/factory at composition root. +- [ ] Coverage/concurrency/failure proof meets repository floors. +- [ ] Independent-session tests cover dispatch versus cutoff/disable in both + orders, same-generation pre-cutoff completion, post-cutoff/cross-generation + denial before provider I/O, and instrumentation proving no advisory fence or + database transaction is held during adapter I/O. +- [ ] The real kernel continues to deny the planned action. AUTH activation is + a later checkpoint after this hidden handler and its evaluator composition + merge. + +## Verification + +Execute the exact clean isolated CON-08A row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_compensation.py tests/test_outbox.py tests/test_authorization.py tests/test_external_service_adapters.py -k '(delivery or adapter or fulfillment) and (fence or cutoff or generation or retry or replay or concurrency or authorization or pre_io or transaction)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/compensation/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/workers/compensation.py' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/interfaces/compensation.py' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/adapters/compensation/*' --fail-under=90) +``` + +Pass requires a non-empty selected test set, pre-I/O durable fencing, no +transaction or lifecycle fence held during adapter I/O, both cutoff race +orders, same-generation pre-cutoff completion, post-cutoff/cross-generation +denial before provider calls, retry/replay and ambiguous-result safety, typed +adapter-factory use, repository coverage at least 78 percent in the same clean +run, and every focused report at least 90 percent. + +## Review and stop + +All baseline plus architecture, security, product, docs, reuse, CI integrity, +and test-delta. Stop after hidden handler; do not activate the action or +register public routes. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08B-inbound-fulfillment-callback.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08B-inbound-fulfillment-callback.md new file mode 100644 index 00000000..1cb47f88 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08B-inbound-fulfillment-callback.md @@ -0,0 +1,83 @@ +# Chunk Contract: WS-CON-001-08B - Inbound Fulfillment Callback + +## Goal and risk + +Accept authenticated bound-service fulfillment results and create immutable +receipts/status updates. L1 auth/economic/replay risk. + +## Allowed files + +```text +backend/app/modules/compensation/{schemas,repository,service,ports}.py +backend/app/api/internal_compensation.py +backend/app/composition/compensation.py +backend/tests/{test_compensation,test_authorization,test_api_controls,test_api_rate_controls,test_api_contract_e2e}.py +docs/spec_contribution_compensation.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-08B.json +``` + +## Not allowed + +```text +AUTH catalogue/grant/ServiceIdentity/static-matrix implementation edits +human role fallback; dynamic service grant; provider credentials +outbox transition ownership; production route registration +``` + +## Acceptance criteria + +- [ ] Human/AUTH approves exact callback ServiceIdentity and static + `compensation.fulfillment.report` row (or an explicitly closed set of + identities), provisions ActorProfile/link, admits through AUTH-09E, and keeps + the action planned until hidden callback behavior merges. +- [ ] Prepared callback locks profile/link and validates immutable + ServiceIdentity, matrix membership and active action as code-owned facts. + AUTH prepares its exact bound handle; CON locks binding/award/delivery/ + receipt rows and recomposes final facts; AUTH consumes/evaluates once before + callback mutation. +- [ ] Exact route identity, project, instrument, award, frozen binding, external + event, quantity/status, and idempotency must match. Actor/link/binding state + loss denies. +- [ ] After CON-owned signature verification plus AUTH/idempotency locking, the + callback acquires the shared `JointLifecycleMutationFence`, resolves the + canonical obligation root, immutable ordinal, and generation, and holds the + fence through receipt commit. In `delivery_draining`, only same-generation + roots at or below the persisted cutoff may finalize; `disabled`, post-cutoff, + crossed-generation, or missing lineage denies before provider/follow-on I/O. +- [ ] Callback finalization cannot create a successor event, retry root, + delivery obligation, repair, award, or other follow-on work while draining. + Callback-versus-disable tests prove the exclusive transition cannot cross an + in-flight receipt transaction. +- [ ] Duplicate exact receipt is idempotent; changed replay conflicts; fulfilled + receipt is immutable and at most one exists per award. +- [ ] Suspended binding accepts only valid already-issued obligations; retired + binding accepts only exact replay of a receipt accepted before retirement. +- [ ] Callback-before-local-ack creates terminal truth and suppresses later + delivery without regression. Both lock orders and rate limits per actor plus + binding are covered. +- [ ] Missing provisioned callback rows deny callback/readiness but do not fail + startup/provisioning. AUTH later activates after hidden behavior proof. + +## Verification + +Execute the exact clean isolated CON-08B row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_compensation.py tests/test_authorization.py tests/test_api_controls.py tests/test_api_rate_controls.py tests/test_api_contract_e2e.py -k '(callback or receipt or fulfillment) and (replay or conflict or fence or cutoff or generation or rate or authorization or signature or concurrency or openapi)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/compensation/*' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/compensation app/api/internal_compensation.py app/composition/compensation.py tests/test_compensation.py tests/test_authorization.py tests/test_api_controls.py tests/test_api_rate_controls.py tests/test_api_contract_e2e.py) +``` + +Pass requires a non-empty selected test set, exact callback replay and changed +replay conflict, signature and authorization negatives, actor-plus-binding rate +isolation, both fence race orders, same-generation at-or-below-cutoff +finalization only, no follow-on obligation while draining, repository coverage +at least 78 percent in the same clean run, and focused compensation coverage at +least 90 percent. + +## Review and stop + +All baseline plus architecture, security, product, docs, reuse, test-delta, and +CI integrity. Stop before public registration. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08R-bound-service-rate-control.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08R-bound-service-rate-control.md new file mode 100644 index 00000000..bd2afa95 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08R-bound-service-rate-control.md @@ -0,0 +1,57 @@ +# Chunk Contract: WS-CON-001-08R - Bound-Service Callback Rate Control + +## Goal and risk + +Extend the shared closed API-control service with one durable actor+binding +callback scope before the external fulfillment route exists. L1 abuse-control/ +availability/data risk. + +## Allowed files + +```text +backend/app/modules/api_controls/{models,repository,service}.py +backend/app/api/deps/api_controls.py +backend/app/core/config.py +backend/alembic/versions/_compensation_callback_rate_scope.py +backend/tests/{test_api_rate_controls,test_config,test_alembic}.py +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-08R.json +``` + +## Not allowed + +```text +AUTH catalogue/grant/kernel/service-actor edits +callback route/receipt/award/binding behavior +in-memory/shared-IP-only limiter, new rate-control framework, dependency/CI weakening +``` + +## Acceptance criteria + +- [ ] Closed scope adds only `compensation_fulfillment_report`; key digest is + derived from canonical service actor + binding and stores neither raw secret + nor provider credential/reference. +- [ ] Bounded configuration, PostgreSQL atomic window accounting, fail-closed + storage errors and deterministic retry-after behavior reuse RateControlService. +- [ ] Actor A cannot exhaust actor B; binding A cannot bypass binding B; exact + boundary/concurrency/upgrade/downgrade behavior is tested. +- [ ] No callback or authorization decision is implemented in this chunk. + +## Verification and reviewers + +Execute the exact clean isolated CON-08R row in `../RUNTIME_VERIFICATION.md`, +replace its migration placeholder with the one new revision, then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_api_rate_controls.py tests/test_config.py tests/test_alembic.py -k '(compensation_fulfillment_report or rate) and (atomic or window or concurrent or isolation or upgrade or downgrade or fail_closed or retry_after)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/api_controls/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/api/deps/api_controls.py' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/core/config.py' --fail-under=90) +``` + +Pass requires a non-empty selected test set, atomic PostgreSQL window races, +actor and binding isolation, upgrade/downgrade proof, bounded configuration, +fail-closed storage errors, deterministic retry-after, repository coverage at +least 78 percent in the same clean run, and every focused report at least 90 +percent. Senior engineering, QA/test, security/auth, product/ops, architecture, +docs, reuse/dedup and test-delta are required. Stop before callback. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-09A-contribution-evidence-write.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-09A-contribution-evidence-write.md new file mode 100644 index 00000000..24c63e57 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-09A-contribution-evidence-write.md @@ -0,0 +1,40 @@ +# Chunk Contract: WS-CON-001-09A - Optional Contribution Evidence Projection Write + +## Status + +Deferred optional successor. This contract is a placeholder and does not +authorize implementation. + +## Goal if separately approved + +Create a deterministic post-commit evidence export through a named ART +capability with independent projection status and failure semantics. + +## Mandatory refresh gate + +Before implementation, a new review must bind the then-current: + +- ART store/admission/verification/recovery and typed write capability; +- document schema, media type, retention, disclosure, and replay rules; +- optional `artifact.contribution_evidence.binding.create` ActionId mapped to + stable `artifact.binding.create`; +- exact extension of `workstream.artifact.binding` static service row, + controlled provisioning, AUTH-09E admission, prepared protocol, and AUTH + activation after hidden behavior; +- scratch/preparation ownership, provider ambiguity, cancellation, cleanup, + commitment drift, binding/receipt validation, and cross-project negatives. + +## Non-negotiable acceptance criteria + +- [ ] CON-07 creates no projection row/event and never calls this capability. +- [ ] Failure cannot mutate Review, ContributionRecord, CompensationAward, + fulfillment receipt, or status projection truth. +- [ ] CON receives no ArtifactStore, ART repository, scratch/preparation type, + provider reference, path, or credential. +- [ ] Optional work is absent from CON-10A/B, CON-11, and joint release gates. +- [ ] PR #129 alone is insufficient proof. + +## Stop + +Do not start without separate human approval and a refreshed internally reviewed +chunk contract. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10A-contribution-award-product-reads.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10A-contribution-award-product-reads.md new file mode 100644 index 00000000..79735c5b --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10A-contribution-award-product-reads.md @@ -0,0 +1,74 @@ +# Chunk Contract: WS-CON-001-10A - Contribution And Award Product Reads + +## Goal and risk + +Implement hidden authorized self/project reads directly from canonical +PostgreSQL ContributionRecord and CompensationAward truth. L1 auth/privacy risk. + +## Allowed files + +```text +backend/app/modules/contributions/{schemas,repository,service}.py +backend/app/modules/compensation/{schemas,repository,service}.py +backend/app/api/internal_{contributions,compensation}.py +backend/app/composition/{contributions,compensation}.py +backend/tests/{test_contributions,test_compensation,test_authorization,test_api_contract_e2e}.py +docs/spec_contribution_compensation.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-10A.json +``` + +## Not allowed + +```text +ART/evidence read or provider reference +operations mutation/rebuild/reconciliation; AUTH edit +balance/ledger; production route registration; CI weakening +``` + +## Approved AUTH prerequisites and handoff inputs + +- AUTH must first merge the approved contribution/award self/project + ActionIds, typed contexts, ActionOwner custody, and real-kernel decision + ports. CON neither registers nor activates them. +- The actions remain planned until CON's hidden read composition and negative + proof merge; AUTH alone performs later evaluator integration and activation. + +## Acceptance criteria + +- [ ] CON composes canonical PostgreSQL resource facts for the supplied AUTH + decision ports while the real kernel continues to deny planned actions. +- [ ] D11 exact award-detail candidate set is approved before implementation. + CON contains no role logic and never infers access from broad PermissionId. +- [ ] Self reads require exact contributor/beneficiary. Project reads use exact + eligible AdminRole, covered project, pre-filtered stable pagination, and + cross-project concealment. Reviewer has no project-wide access by review role. +- [ ] Allowed decisions bind complete resource digest, matched grant/project, + request, and correlation. Stale/mismatched evidence denies. +- [ ] Contribution, money, points, delivery acknowledgement, and fulfillment + are distinct. No provider/balance/ledger/evidence artifact data appears. +- [ ] CON-09A/09B absence or failure has no effect. OpenAPI remains hidden; + coverage stays at required floors. + +## Verification + +Execute the exact clean isolated CON-10A row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_api_contract_e2e.py -k '(contribution or award) and (read or list or pagination or conceal or cross_project or unauthorized or stale or openapi)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/contributions/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/compensation/*' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/contributions app/modules/compensation app/api/internal_contributions.py app/api/internal_compensation.py app/composition/contributions.py app/composition/compensation.py tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_api_contract_e2e.py) +``` + +Pass requires a non-empty selected test set, stable pre-filtered pagination, +self/project authorization negatives, cross-project concealment, stale-decision +denial, hidden OpenAPI routes, no evidence/provider disclosure, repository +coverage at least 78 percent in the same clean run, and both focused reports at +least 90 percent. + +## Review and stop + +Required tracks: senior, QA, security, product, architecture, docs, reuse, and +test-delta. Stop before operations/public registration. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10B-operations-reconciliation-rebuild.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10B-operations-reconciliation-rebuild.md new file mode 100644 index 00000000..93dc0401 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10B-operations-reconciliation-rebuild.md @@ -0,0 +1,87 @@ +# Chunk Contract: WS-CON-001-10B - Operations Requests, Reads, And Drain Observation + +## Goal and risk + +Implement hidden bounded status/audit reads, binding retirement, durable +reconciliation/rebuild request creation, and fulfillment drain observation. +Execution belongs to 10C. L1 operations/auth/data risk. + +## Allowed files + +```text +backend/app/modules/contributions/{schemas,repository,service}.py +backend/app/modules/compensation/{schemas,repository,service,ports}.py +backend/app/modules/audit/{schemas,repository,service}.py only bounded WS-CON projection +backend/app/api/internal_operations.py +backend/app/composition/{contributions,compensation}.py +backend/tests/{test_contributions,test_compensation,test_authorization,test_outbox,test_audit}.py +docs/operations_payment_reputation.md only implemented WS-CON operations +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-10B.json +``` + +## Not allowed + +```text +async reconciliation/rebuild execution or provider I/O +outbox dispatcher/transition implementation; immutable truth repair +AUTH implementation; production router registration; CI weakening +``` + +## Approved AUTH prerequisites and handoff inputs + +- D11 must be final and AUTH must first merge the approved binding-retire, + delivery-reconcile, status, reconcile-request, rebuild-request, and audit + ActionIds with exact candidates, typed contexts, prepared protocol, and AUTH + custodians. CON neither registers nor activates them. +- The handoff supplies AUTH-owned prepare/consume/evaluate ports. AUTH prepares + authority first and consumes/evaluates the recomposed facts; the route owns + the single commit. + +## Acceptance criteria + +- [ ] Every mutation uses the supplied PR #140 handoff: CON locks and + recomposes final product facts between AUTH prepare and AUTH + consume/evaluate, and stages no request/retirement mutation beforehand. +- [ ] Human operations create bounded durable idempotent requests only; they do + not execute reconciliation/rebuild under human or dispatcher authority. +- [ ] Binding retirement locks policy/assignment/lease/award/delivery/receipt + dependencies and denies active/unfinished/unfulfilled references in both race + orders. Exact prior receipt replay remains the only post-retirement path. +- [ ] Audit read/export enforces purpose/scope/range/redaction with no provider + or sensitive failure leakage. +- [ ] `FulfillmentLifecycleDrainObservationPort` reports pending/claimed/ + retryable outbox work, durable in-flight delivery, and nonterminal callback + obligations through typed outbox capability, plus the current maximum + immutable `fulfillment_obligation_ordinal`; zero is valid only when no root + exists. It never imports an outbox or lifecycle-control repository. +- [ ] Observation uses the caller AsyncSession, is bounded/read-only, never + commits or calls a provider, and never returns false zero while remote I/O or + terminal receipt remains possible. Caller-supplied timestamps, ordinals, + generation, or event IDs cannot substitute. +- [ ] AUTH later activates after hidden behavior; 10C waits for approved + executor identities/actions/static rows. + +## Verification + +Execute the exact clean isolated CON-10B row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_outbox.py tests/test_audit.py -k '(operation or retirement or reconcile or rebuild or audit or drain) and (race or lock or authorization or idempotency or ordinal or false_zero or provider)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/contributions/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/compensation/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/audit/*' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/contributions app/modules/compensation app/modules/audit app/api/internal_operations.py app/composition/contributions.py app/composition/compensation.py tests/test_contributions.py tests/test_compensation.py tests/test_authorization.py tests/test_outbox.py tests/test_audit.py) +``` + +Pass requires a non-empty selected test set, both retirement race orders, +prepared-authorization negatives, idempotent bounded requests, exact drain +counts and maximum ordinal without false zero, zero provider calls, repository +coverage at least 78 percent in the same clean run, and every focused report at +least 90 percent. + +## Review and stop + +Required tracks: senior, QA, security, product, architecture, docs, reuse, and +test-delta. Stop before executor work. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10C-operations-executors.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10C-operations-executors.md new file mode 100644 index 00000000..659c21ba --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10C-operations-executors.md @@ -0,0 +1,91 @@ +# Chunk Contract: WS-CON-001-10C - Reconciliation And Projection Executors + +## Goal and risk + +Execute committed bounded compensation-reconciliation and contribution- +projection-rebuild requests under independent exact fixed-service authority. +L1 background-execution/auth/economic-data risk. + +## Prerequisites + +- 10B durable request and drain contracts merged; +- exact ServiceIdentity/ActionId/static-row design approved for compensation + reconciliation and contribution projection rebuild, or explicitly approved + closed dual-principal evaluators; +- controlled service ActorProfile/link provisioning, AUTH-09E admission, + typed context, and prepared protocol; both actions remain planned while this + hidden behavior merges; +- shared outbox claim validation and handler registry. + +## Allowed files + +```text +backend/app/modules/contributions/{repository,service}.py +backend/app/modules/compensation/{repository,service}.py +backend/app/modules/outbox/handlers.py only explicit registration +backend/app/workers/{contributions,compensation}.py +backend/app/composition/{contributions,compensation}.py +backend/tests/{test_contributions,test_compensation,test_outbox,test_authorization}.py +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-10C.json +``` + +## Not allowed + +```text +generic dispatcher identity executing feature work +human request authority reused without approved dual-principal evaluator +canonical contribution/award/receipt mutation; provider settlement +outbox claim/finalization transitions; AUTH implementation +``` + +## Acceptance criteria + +- [ ] Dispatcher can invoke but is denied both executor actions. Each executor + is denied dispatch, the other executor's action, delivery/callback/ART/REV + actions, and every human action outside its exact row. +- [ ] Handler validates committed claim generation; AUTH locks fixed-service + authority and prepares its exact bound handle; CON locks bounded request/ + product rows and recomposes final facts; AUTH consumes/evaluates once; CON + then stages result/audit/projection state and returns a typed outcome. +- [ ] Compensation reconciliation compares immutable award/delivery/receipt + truth and creates durable findings/actions allowed by the approved contract; + it never changes award amount/eligibility or fabricates receipt truth. +- [ ] Any reconciliation path that creates, requeues, succeeds, or repairs a + fulfillment obligation is classified as an obligation writer, acquires the + shared lifecycle fence before allocating/locking its immutable root ordinal, + and is denied from `commands_draining` onward. Completion-only observation or + same-root finalization cannot be used to smuggle new work into the drain. +- [ ] Contribution rebuild changes rebuildable projections only and never + mutates ContributionRecord or CompensationAward. +- [ ] Retry/replay/idempotency and crash fencing preserve request identity. + Missing service provisioning denies runtime/readiness without failing startup. +- [ ] Coverage, concurrency, and cross-service negative proof meet floors. +- [ ] The real kernel continues to deny both planned executor actions. AUTH + activation is a later checkpoint after hidden behavior and exact evaluator + composition merge. + +## Verification + +Execute the exact clean isolated CON-10C row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_contributions.py tests/test_compensation.py tests/test_outbox.py tests/test_authorization.py -k '(executor or reconcile or rebuild) and (fence or ordinal or retry or replay or crash or concurrency or unauthorized or deny)') +(cd backend && .venv/bin/python -m coverage report --include='app/modules/contributions/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/modules/compensation/*' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/workers/contributions.py' --fail-under=90) +(cd backend && .venv/bin/python -m coverage report --include='app/workers/compensation.py' --fail-under=90) +(cd backend && .venv/bin/ruff check app/modules/contributions app/modules/compensation app/modules/outbox/handlers.py app/workers/contributions.py app/workers/compensation.py app/composition/contributions.py app/composition/compensation.py tests/test_contributions.py tests/test_compensation.py tests/test_outbox.py tests/test_authorization.py) +``` + +Pass requires a non-empty selected test set, exact executor isolation, +claim-generation validation, shared-fence-before-ordinal ordering, retry/replay +and crash idempotency, concurrent drain denial of new obligation work, +repository coverage at least 78 percent in the same clean run, and every +focused report at least 90 percent. + +## Review and stop + +All baseline plus architecture, security, product, docs, reuse, CI integrity, +and test-delta. Stop before AUTH activation and CON-11. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-11-hidden-release-readiness.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-11-hidden-release-readiness.md new file mode 100644 index 00000000..576ac16c --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-11-hidden-release-readiness.md @@ -0,0 +1,116 @@ +# Chunk Contract: WS-CON-001-11 - Hidden Release Readiness And Dependency Manifest + +## Goal and risk + +Prove the core WS-CON subsystem coherent while hidden and publish an exact +merged-SHA/schema/action/service/handler/fence/drain/test manifest for the +reviewed REV release owner. L1 release/auth/economic risk. + +## Allowed files + +```text +backend/app/composition/{contributions,compensation,outbox}.py +backend/tests/{test_api_contract_e2e,test_authorization,test_contributions,test_compensation,test_outbox}.py +docs/spec_contribution_compensation.md +docs/internal_reviews/WS-CON-001-hidden-release-readiness.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +.agent-loop/merge-intents/WS-CON-001-11.json +``` + +## Not allowed + +```text +production route registration or noncanonical prefix alias +REV lifecycle-control persistence/policy; AUTH/ART implementation +optional evidence projection/read or ART readiness gate +archival input edits +``` + +## Acceptance criteria + +- [ ] Startup parity covers closed ActionId/PermissionId/ActionOwner, typed + contexts/evaluators, ServiceIdentity/static rows, and active-feature behavior. + Active-without-evaluator/behavior or extra/missing matrix membership fails. +- [ ] Missing provisioned service ActorProfile/link rows do not fail app startup + or Access Administrator provisioning. Protected runtime calls deny and + release readiness stays false until exact rows exist. +- [ ] AUTH manifest binds trusted baseline, complete REV custody transfer, + proposed core CON mappings plus separately approved executor actions, D11 + role sets, exact grants/static rows, AUTH-09E admission, prepared protocol, + decision digests/matched authority, and activation evidence. +- [ ] Prepared-protocol proof binds handles exactly to session, ActionId, + actor-reference kind/reference, idempotency key, and request digest; proves + same-session/action cross-actor/request substitution does not mutate state or + consume a valid handle; and proves ServiceIdentity/matrix/availability are not + database lock targets. +- [ ] No partial ART/REV transfer is restated. Complete mappings are referenced + from merged WS-XINT handoffs. ART and optional CON-09A/09B are absent from + core prerequisites. +- [ ] Hidden integration proves production OpenAPI routes remain absent and no + direct construction path bypasses AUTH, fixed-service admission, outbox + handler isolation, or mandatory REV/CON participant composition. +- [ ] Manifest names exact migrations, schemas, event/task IDs, registry rows, + service identities/actions/static rows, handler execution boundaries, and + retained test metadata. Dispatcher cannot execute protected handlers. +- [ ] Manifest names mandatory CON obligation-writer, dispatch, callback, and + same-session `FulfillmentLifecycleDrainObservationPort` hooks plus + `OutboxClaimValidationPort`, injection seams, phase mappings, denial states, + and fail-closed construction. REV-12A injects the one shared + `JointLifecycleMutationFence`; CON defines no second controller or optional/ + no-op fence. +- [ ] The manifest enumerates every fulfillment-obligation root creation, + requeue, successor, and repair writer and proves each acquires the shared + fence before allocating its immutable monotonic ordinal or locking obligation + rows. Missing, extra, ambiguous, differently ordered, or completion-only- + misclassified writers fail composition and preflight. +- [ ] Drain observation returns pending/claimed/retryable outbox events, durable + in-flight dispatch, nonterminal delivery/callback obligations, and the current + maximum root ordinal in the caller session. Independent-session proof races + every writer against cutoff capture and proves it either commits under an + included ordinal or observes `commands_draining` without allocation/mutation. +- [ ] Dispatch and callback readiness proves `delivery_draining` permits only + same-generation, at-or-below-cutoff completion and denies new roots, requeue, + successor, repair, post-cutoff, and crossed-generation work before provider + I/O. Disable waits for zero dispatchable/retryable/claimed/in-flight work and + zero nonterminal delivery/callback obligations. +- [ ] Core conformance matrix has executable evidence; same-run repository + coverage is at least 78 and changed subsystems at least 90. +- [ ] Joint drill contract covers all core families. Accept proves Task + `accepted`, Assignment `completed`, one FinalAcceptance and one submitter + contribution. Needs_revision proves Task `needs_revision`, Assignment still + `active`, and neither acceptance fact nor submitter contribution. Reject + proves Task `rejected` with bounded human reason, only the same-task + Assignment blocked with its source Review, and neither acceptance fact nor + submitter contribution. Every Review proves one reviewer contribution. It + explicitly + asserts zero ART calls and no adjudication model/action/state/queue/readiness + dependency. It is not marked executed here. + +## Verification + +Execute the exact clean isolated CON-11 row in `../RUNTIME_VERIFICATION.md`, +then run: + +```bash +(cd backend && .venv/bin/python -m pytest -q tests/test_api_contract_e2e.py tests/test_authorization.py tests/test_contributions.py tests/test_compensation.py tests/test_outbox.py tests/test_audit.py -k '(manifest or readiness or openapi or isolation or fence or cutoff or generation or drain or provider)') +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_authorization_docs.py +python3 scripts/check_stale_artifact_contracts.py +python3 scripts/check_loop_memory_state.py +python3 scripts/check_internal_review_evidence.py +git diff --check +``` + +Pass requires a non-empty selected test set, a complete exact AUTH/REV/CON +manifest, no public OpenAPI registration, service/action isolation, every +writer/dispatch/callback fence race in both orders, same-generation +at-or-below-cutoff completion only, provider I/O outside transaction/fence, +repository coverage at least 78 percent and each CON-11 focused subsystem at +least 90 percent in the same clean run, plus every repository gate above. + +## Review and stop + +All internal tracks including CI integrity and test-delta. Stop after hidden +manifest. Do not register routes, implement REV release control, run production +activation, or start optional evidence work. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN-contribution-compensation-planning.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN-contribution-compensation-planning.md new file mode 100644 index 00000000..96843a5e --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN-contribution-compensation-planning.md @@ -0,0 +1,98 @@ +# Chunk Contract: WS-CON-001-PLAN - Contribution And Compensation Planning + +## Goal + +Reconcile WS-CON planning to merged PR #139 / WS-XINT-001 without implementing +runtime behavior, and repair only the exact active-contract scanner +classification/proof required by that reconciliation. + +## Risk + +L0 architecture/economic/authorization planning plus CI-sensitive scanner +metadata; P1. + +## Allowed files + +```text +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +scripts/check_stale_workstream_wording.py only exact archival/current-runtime contract rules +scripts/check_stale_authorization_docs.py only exact archival classification +scripts/check_stale_artifact_contracts.py only exact archival classification parity +scripts/check_internal_review_evidence.py only deleted-contract provenance during chunk renames +scripts/test_agent_gates.py only fail-closed gate regressions for these rules +docs/current_system_data_flow.html only remove premature target-runtime type claim +``` + +## Not allowed + +```text +backend application, migrations, runtime tests, workflows, dependencies +AUTH/ART/REV initiative edits +reference-spec byte edits, restoration, rename, or archival replacement +active product documentation adoption +scanner threshold weakening, directory-wide archive exemption, or broad waiver +``` + +## Acceptance criteria + +- [ ] Trusted baseline is `5d353b6`; runtime AUTH remains 74 PermissionIds, 57 + ActionIds, nine active, and 48 planned. +- [ ] Canonical eligibility model is ContributionPolicy/version/rule/award + definition; CompensationAward remains the evaluated result. +- [ ] Core Review-to-contribution transaction creates no evidence projection, + makes zero ART calls, and copies stabilized Submission artifact_hash lineage. +- [ ] Project grants are independent submitter/reviewer/adjudicator; fixed + services use ServiceIdentity/static matrix/AUTH-09E, never persisted action + rows. +- [ ] ActionOwner is AUTH activation custody; complete ART/REV transfers are + referenced from WS-XINT rather than partially restated. +- [ ] Shared outbox dispatch cannot authorize protected feature handlers; + delivery/reconciliation/rebuild/callback identity/action decisions are open + exact gates. +- [ ] Proposed policy ActionIds use `contribution.policy.*` mapped to stable + `compensation.policy.manage`. The 22 core surface actions are tested + separately from optional evidence and unapproved executor candidates. +- [ ] CON-09A/09B are deferred optional and absent from core 10A/B/10C/11 and + joint release gates. +- [ ] Current chunk map includes independently authorized 10C executors. +- [ ] The pre-existing user deletion of the original PDF remains untouched and + unstaged. +- [ ] Exact WS-CON reference Markdown is classified historical consistently in + all three scanners; near misses and new docs remain scanned. +- [ ] Current-runtime scanner recognizes canonical unimplemented contribution/ + award types and fails on premature runtime walkthrough claims. +- [ ] Internal-review evidence discovery recovers a deleted contract heading + from the index, HEAD, or review base and retains its chunk ID alongside each + replacement; missing, empty, malformed, unreadable, dangling-symlink, and + non-file contracts fail closed. +- [ ] Required internal reviewers pass the exact final snapshot and no sessions + remain open. +- [ ] The repository loop-memory check is run and its only failure is the + unchanged AUTH status inherited from trusted `main`; this bounded CON chunk + does not edit another initiative to conceal the upstream failure. + +## Verification + +```bash +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_authorization_docs.py +python3 scripts/check_stale_artifact_contracts.py +# Expected inherited failure until AUTH/main repairs its own status: +python3 scripts/check_loop_memory_state.py +git diff --exit-code origin/main -- \ + .agent-loop/initiatives/WS-AUTH-001-workstream-authorization-service/STATUS.md +PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -m pytest -q scripts/test_agent_gates.py +git diff --check +test "$(git rev-parse origin/main)" = 5d353b6d3f8a36b9b9ffdc1959487a150ac25fd1 +``` + +## Reviewers + +Senior engineering, QA/test, security/auth, product/ops, architecture, docs, +reuse/dedup, CI integrity, and test-delta. + +## Stop + +Stop after reviewed planning reconciliation. Do not start CON-01, runtime work, +optional evidence, push, or PR publication without explicit human direction. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN2-final-acceptance-reconciliation.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN2-final-acceptance-reconciliation.md new file mode 100644 index 00000000..2a80c6a2 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN2-final-acceptance-reconciliation.md @@ -0,0 +1,107 @@ +# Chunk Contract: WS-CON-001-PLAN2 - Final Acceptance Reconciliation + +## Goal + +Adopt the human-approved v0.1 `Review(accept) -> FinalAcceptance -> +accepted_submission` boundary in WS-CON planning and shared product wording, +without implementing runtime behavior or introducing adjudication. + +## Risk + +L0 architecture/economic/lifecycle specification; P1. + +## Allowed files + +```text +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/** +README.md only exact review/final-acceptance/contribution wording +docs/architecture_brief/workstream_architecture_brief.md only contribution principle wording +docs/architecture_data_model.md only FinalAcceptance/contribution lineage and non-mutating reviewer-quality event tokens +docs/architecture_lifecycle_state_machine.md only accepted transition facts and no-adjudication invariant +docs/architecture_lockdown.md only v0.1 acceptance/contribution invariants +docs/architecture_system_architecture.md only replace second-review flags with non-mutating post-decision quality-audit observations +docs/glossary.md only FinalAcceptance/ContributionRecord definitions and exact no-adjudication clarification +docs/operations_reviewer_workflow.md only exact decision effects and non-mutating quality audit +docs/operations_operator_workflow.md only acceptance sequence +docs/operations_payment_reputation.md only contribution/award trigger wording and non-mutating reviewer-quality event tokens +docs/operations_queue_policy.md only accepted-lane required facts +docs/product_first_user_flows.md only reviewer decision effects +docs/risk_register.md only reviewer-quality mitigation wording that could imply a second lifecycle decision +docs/template_project_guide.md only replace mandatory second-review gating with non-mutating quality-audit sampling +docs/template_review_packet.md only replace second-review gating fields with non-mutating quality-audit fields +``` + +## Not allowed + +```text +backend application, migrations, runtime tests, workflows, dependencies +REV/AUTH/ART initiative or runtime edits +reference-spec/PDF byte edits, restoration, rename, or replacement +SubmissionVersion entity or submission_version_id compatibility alias +adjudicator grant/action implementation; adjudication policy, queue, lease, +state, decision, contribution type, branch, readiness gate, or initiative dependency +new authorization action for FinalAcceptance creation +manual/public FinalAcceptance creation API +rewriting historical docs/review_* internal-review evidence +``` + +## Acceptance criteria + +- [x] REV owns immutable `FinalAcceptance`, creates it only as an internal + consequence of an authorized `Review(accept)`, and exposes no independent + create action or API. +- [x] Existing immutable `Submission` remains the version identity. The + external `submission_version_id` shorthand maps to canonical `submission_id`; + no duplicate entity or alias is introduced. +- [x] FinalAcceptance has exact task/project/submission/Review/submitter/ + reviewer/time/policy-context lineage and unique task, Review, and Submission + constraints. REV must type the policy-context reference against its canonical + immutable review-policy fact before its persistence chunk starts. +- [x] `completed_review` remains directly sourced from every valid human Review + and ReviewLease. `accepted_submission` is sourced only from FinalAcceptance + plus TaskAssignment and never inferred directly from Review.decision. +- [x] One completed_review exists per Review and one accepted_submission per + FinalAcceptance; needs_revision/reject create no FinalAcceptance or submitter + contribution. +- [x] Outcome effects match REV's canonical lifecycle exactly: accept sets Task + `accepted` and Assignment `completed`; needs_revision sets Task + `needs_revision` and keeps Assignment `active`; reject sets Task `rejected` + with a bounded human reason and blocks only the same-task Assignment with its + source Review. No `closed/review_rejected` token, grant mutation, or unrelated + task effect is introduced. +- [x] The REV request owns one transaction. REV creates Review and optional + FinalAcceptance, invokes CON flush-only contribution/award behavior, stages + shared audit/outbox records, and commits once. +- [x] Any CON failure rolls back Review, FinalAcceptance, task/assignment + effects, contributions, awards, audit, and outbox together. External + fulfillment starts only after commit. +- [x] Core contribution creation copies stabilized Submission artifact-hash + lineage and makes zero ART/provider calls. +- [x] WS-CON has no adjudication lifecycle, action, state, queue, contribution, + authorization, or release dependency. Existing unrelated AUTH role catalogue + state is neither expanded nor implemented here. +- [x] Required internal reviewers pass the exact final snapshot; no sub-agent + session remains open. + +## Verification + +```bash +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_authorization_docs.py +python3 scripts/check_stale_artifact_contracts.py +PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -m pytest -q scripts/test_agent_gates.py +git diff --check +test -z "$(git diff --name-only -- backend)" +``` + +## Reviewers + +Senior engineering, QA/test, security/auth, product/ops, architecture, docs, +reuse/dedup, and test-delta. CI integrity is N/A only if no script, workflow, +dependency, test, threshold, or runner changes. + +## Stop + +Stop after reviewed specification reconciliation. Do not implement +FinalAcceptance, start CON-01/03C/07, push, or open a PR automatically. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN3-auth-pr140-reconciliation.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN3-auth-pr140-reconciliation.md new file mode 100644 index 00000000..7dcad013 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN3-auth-pr140-reconciliation.md @@ -0,0 +1,144 @@ +# Chunk Contract: WS-CON-001-PLAN3 - AUTH And REV Current-Main Reconciliation + +## Goal + +Reconcile WS-CON planning with trusted `main` after merged AUTH PR #140 and the +later merged AUTH-09A/REV PR #128 boundary without implementing runtime +behavior, changing AUTH/REV-owned files, or weakening the +review/FinalAcceptance/contribution transaction. + +## Risk + +L0/L1 authorization, transaction, and release specification; P1. + +## Allowed files + +```text +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/AUTHORIZATION_HANDOFF.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/CHUNK_MAP.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/CONFORMANCE_MATRIX.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/DECISIONS.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/DISCOVERY.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/INTENT.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/JOINT_RELEASE_HANDOFF.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/PLAN.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/RISKS.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/RUNTIME_VERIFICATION.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/SOURCE_MANIFEST.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/STATUS.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-01-canonical-contract-adoption.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02A-shared-outbox-persistence.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02B-shared-outbox-dispatcher.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-02C-shared-lifecycle-audit-participant.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03C-contribution-award-persistence.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-03D-delivery-receipt-status-persistence.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-04A-hidden-adapter-binding-service.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-04B-hidden-contribution-policy-service.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-05A-legacy-economic-terms-cutover-and-task-freeze.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-05B-legacy-economic-schema-removal.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-06-review-lease-contribution-policy-freeze.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-07-atomic-review-contribution-award-participant.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08A-outbound-compensation-delivery.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08B-inbound-fulfillment-callback.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-08R-bound-service-rate-control.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-09B-authorized-contribution-evidence-read.md (deletion only; moved to deferred/) +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/deferred/WS-CON-001-09B-authorized-contribution-evidence-read.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10A-contribution-award-product-reads.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10B-operations-reconciliation-rebuild.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-10C-operations-executors.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-11-hidden-release-readiness.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN-internal-review-evidence.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN2-internal-review-evidence.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-internal-review-evidence.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-external-review-response.md +.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-pr-trust-bundle.md +.agent-loop/REVIEW_LOG.md +.agent-loop/merge-intents/WS-CON-001-PLAN3.json +``` + +## Not allowed + +```text +backend application, migrations, tests, workflows, dependencies, or runtime catalogue edits +AUTH/REV/ART/XINT initiative or implementation edits +active product-document changes without a newly discovered canonical mismatch +new PermissionId, ActionId, ServiceIdentity, grant, or action activation +feature-owned authorization evaluator, grant query, or availability writer +FinalAcceptance API/action or adjudication lifecycle/dependency +reference specification/PDF edits, restoration, rename, or replacement +``` + +## Acceptance criteria + +- [x] Trusted baseline is merged REV PR #128 at `0302bcf`, containing AUTH-09A + after PR #140. The runtime catalogue has 74 PermissionIds, 65 ActionIds, nine + active and 56 planned, with no registered CON-specific or task-claim ActionId. +- [x] CON consumes AUTH's exact prepared mutation protocol: AUTH locks current + authority first and creates an opaque single-use handle bound to session, + ActionId, actor-reference kind/reference, idempotency key, and canonical + request digest; feature rows lock afterward; final facts are recomposed; AUTH + evaluates once and stages evidence; the route/command commits once. +- [x] CON never describes ServiceIdentity, static matrix membership, or action + availability as database lock targets and never imports AUTH persistence or + evaluates grants locally. +- [x] Only the stable `task.claim` PermissionId exists today; no task-claim + ActionId is registered. After AUTH-10/PREP, CON-05A and task-owned freeze + composition merge first; AUTH-13 then enumerates/registers the exact action, + integrates its evaluator, and activates only after merged proof. Existing + `review.claim` and `review.decision` ActionIds remain planned and require the + exact reviewer grant plus REV guards before activation. +- [x] `review.decision` activation requires the merged mandatory CON flush-only + participant with two ordered operation-specific inputs and rollback-safe + REV+CON single transaction. The reviewer operation precedes the branch; the + accept-only submitter operation follows FinalAcceptance and accepted task + effects. FinalAcceptance remains an internal REV consequence with no action/API. +- [x] All 19 REV actions are referenced through the complete AUTH custody + transfer. CON names only its `review.claim` and `review.decision` + dependencies and never owns or partially transfers ActionOwner metadata. +- [x] The existing 22 CON surface mappings and service-execution identifiers + remain explicitly non-final proposals. Each requires a later exact + feature-owned manifest, reviewed AUTH registration, hidden behavior, and + AUTH-only activation; dispatcher authority is never inherited by handlers. +- [x] No adjudication dependency, retired compensation-policy compatibility + path, ART call in + core contribution creation, or independent CON commit is introduced. +- [x] Required internal reviewers pass the exact final snapshot, deterministic + gates pass, the PR trust bundle is complete, and exactly one PLAN3 merge + intent is present in the branch delta. Older PLAN/PLAN2 evidence receives a + provenance-only rebind when the PR-level gate requires every evidence file + added by the cumulative branch to match the final reviewed revision. +- [x] Merged REV PR #128 release-control dependencies are reflected exactly: + every fulfillment-obligation writer uses the shared lifecycle fence before + allocating a monotonic root ordinal; the same-session drain port returns the + maximum ordinal; and delivery-draining dispatch/callback paths are limited to + same-generation roots at or below the persisted cutoff. +- [x] Every unresolved CodeRabbit thread is dispositioned: active chunks name + deterministic runnable verification commands and pass criteria; AUTH-owned + registration, context, custody, and activation remain prerequisites rather + than CON-owned acceptance work; optional CON-09B is explicitly a deferred + proposal pending a fresh contract; and the PR description carries the full + trust bundle. + +## Verification + +```bash +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_authorization_docs.py +python3 scripts/check_stale_artifact_contracts.py +PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -m pytest -q scripts/test_agent_gates.py +git diff --check +git diff --quiet origin/main -- backend +``` + +## Required reviewers + +Senior engineering, QA/test, security/auth, product/ops, architecture, docs, +reuse/dedup, and test-delta. CI integrity is required if any script, workflow, +test, dependency, threshold, or runner changes. + +## Stop + +Stop after reviewed planning reconciliation, PR trust bundle, and merge-intent +preparation. Do not implement CON-01 or any runtime chunk, push, open, or merge +a PR without the user's explicit next instruction and merge approval. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/deferred/WS-CON-001-09B-authorized-contribution-evidence-read.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/deferred/WS-CON-001-09B-authorized-contribution-evidence-read.md new file mode 100644 index 00000000..1c5bff8a --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/deferred/WS-CON-001-09B-authorized-contribution-evidence-read.md @@ -0,0 +1,97 @@ +# Deferred Proposal: WS-CON-001-09B - Optional Authorized Contribution Evidence Read + +## Status + +Deferred optional successor after separately approved and merged CON-09A. It is +not a prerequisite for core contribution/award reads. This file is deliberately +not an implementation contract and authorizes no file changes. + +## Prospective risk + +L1 disclosure, authorization, artifact-retention, and cross-subsystem read +boundary. Risk and scope must be reclassified against then-current ART/AUTH +contracts before promotion. + +## Goal if separately approved + +Expose a bounded evidence-export read through a separately proven ART read +capability and exact AUTH disclosure contract. + +## Allowed files now + +None. A separately human-approved, internally reviewed replacement chunk +contract must name exact allowed files before implementation. + +## Prohibited changes + +```text +runtime, route, schema, migration, dependency, workflow, AUTH, ART, or activation changes +CON-10A contribution/award truth or availability dependencies +public evidence route or provider/credential disclosure +reuse of the CON-09A write capability as an implicit read capability +``` + +## Promotion acceptance criteria + +- [ ] CON-09A is separately approved, merged, and refreshed against trusted + main; its absence or failure still cannot affect CON-10A. +- [ ] The replacement contract names exact ART read capability, projection + schema/binding/retention, AUTH disclosure ActionIds/contexts/candidates, and + self/project concealment rules without reviewer-private/provider/credential + disclosure. +- [ ] Exact allowed files, prohibited changes, runtime tests, migration impact, + coverage targets, reviewers, and stop conditions are approved before any + implementation. +- [ ] Routes stay hidden until their own merged AUTH evaluator/activation and + optional release gate pass. + +## Mandatory refresh gate + +- Re-review the then-current projection schema/binding/retention state and ART + read port independently from the write port. +- Define exact self/project candidates, pre-filtering, concealment, media/schema + validation, and no reviewer-private/provider/credential disclosure. +- Prove evidence absence/failure leaves PostgreSQL contribution/award truth and + CON-10A reads unaffected. +- Keep routes hidden until its own AUTH evaluator/activation and optional release + gate pass. + +## Verification before promotion + +Run from the repository root against the proposed replacement contract: + +```bash +test -f docs/spec_artifact_storage_service.md +test -f docs/spec_authorization_service.md +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_authorization_docs.py +python3 scripts/check_stale_artifact_contracts.py +git diff --check +if ! changed_files="$(git diff --name-only origin/main...HEAD)"; then + exit 1 +fi +allowed_paths='^\.agent-loop/REVIEW_LOG\.md$|^\.agent-loop/merge-intents/WS-CON-001-09B\.json$|^\.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/(CHUNK_MAP\.md|STATUS\.md|(chunks|deferred)/WS-CON-001-09B-authorized-contribution-evidence-read\.md|reviews/WS-CON-001-09B-[^/]+\.md)$' +if unexpected="$(printf '%s\n' "$changed_files" | rg -v "$allowed_paths")"; then + printf '%s\n' "$unexpected" + exit 1 +else + rg_status=$? + test "$rg_status" -eq 1 +fi +``` + +Pass only proves that a planning-only replacement contract is eligible for +internal review: every command exits zero, no runtime/workflow delta exists, +and the contract closes every promotion criterion above. It does not authorize +implementation. + +## Required reviewers before promotion + +Senior engineering, QA/test, security/auth, product/ops, architecture, docs, +reuse/dedup, ART boundary, AUTH boundary, CI integrity, and test delta. + +## Stop + +Do not start without separate human approval and a replacement internally +reviewed chunk contract. CON-10A proceeds independently. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN-internal-review-evidence.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN-internal-review-evidence.md new file mode 100644 index 00000000..4f72b8c1 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN-internal-review-evidence.md @@ -0,0 +1,628 @@ +# Internal Review Evidence: WS-CON-001-PLAN + +## 2026-07-17 AUTH And REV Current-Main Provenance Rebind + +Reviewed code SHA: a69fad3a32ad47e3bd60a79cd75f5867eefc52b3 +Reviewed at: 2026-07-17T18:14:54Z +Reviewer run IDs: auth08_arch_review/final-a69fad3, auth08_qa_product_review/final-a69fad3, auth08_security_review/final-a69fad3 + +This provenance-only addendum binds the earlier substantive PLAN review chain to +the final reviewed cumulative planning snapshot. PLAN3 authorizes this evidence +rebind because the PR-level gate validates every evidence file added by the +branch. It changes no historical finding or product conclusion. The exact-SHA +re-review confirmed that the merged AUTH runtime and REV plan, exact +FinalAcceptance/CON participant boundary, joint release-control contract, +CodeRabbit contract repairs, and evidence-schema update introduce no remaining +blocker. + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS AFTER FIXES | None | The cumulative specification remains coherent after current-main and external-review repairs. | +| qa/test | PASS | None | Exact two-operation ordering, branch effects, rollback coverage, and deterministic gates pass. | +| security/auth | PASS | None | Current AUTH catalogue facts, prepared semantics, and AUTH-only identifier/evaluator/activation ownership pass. | +| product/ops | PASS | None | Review outcomes, FinalAcceptance lineage, contribution atomicity, release cutoff, and no-adjudication boundary pass. | +| architecture | PASS AFTER FIXES | None | Ownership, executable chunk gates, transaction, rollout, joint release control, and successor boundaries remain coherent. | +| ci integrity | PASS | None | The rebind changes evidence only; no CI, runtime, test, script, workflow, dependency, or threshold changes. | +| docs | PASS AFTER FIXES | None | Runtime-versus-planned identifiers, merged REV dependencies, CodeRabbit dispositions, and cumulative evidence provenance are explicit. | +| reuse/dedup | PASS | None | No duplicate service, evaluator, registry, or transaction abstraction is introduced. | +| test delta | PASS | None | No test delta; all 80 agent-gate tests pass. | + +Valid findings addressed: yes + +Open sub-agent sessions: none + +## 2026-07-17 WS-XINT-001 Boundary Reconciliation + +This addendum is the current authoritative review state and supersedes the +older policy-model, mandatory-evidence, service-assignment, partial-custody, +trusted-main, and chunk-order statements below. Trusted `main` +`5d353b6d3f8a36b9b9ffdc1959487a150ac25fd1` merges WS-XINT-001 PR #139. + +Reviewed code SHA: `c4242e0b7c3441c23ce8b3a3facc45ae00de848a` + +Reviewed non-review planning-tree SHA-256: +`586658fb55eadcc36f8095051ed7ff3281a714672456221de7d7041c6f040465` + +The digest excludes `reviews/**` and is reproduced from the repository root: + +```bash +find .agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary \ + -type f -name '*.md' ! -path '*/reviews/*' -print0 \ + | sort -z | xargs -0 sha256sum | sha256sum +``` + +Reviewed at: 2026-07-17T05:16:47Z + +Reviewer run IDs: senior/architecture/reuse=`/root/auth08_arch_review`; +QA/test/product/ops/docs/test-delta=`/root/auth08_qa_product_review`; +security/auth/CI-integrity=`/root/auth08_security_review` + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS AFTER FIXES | None | Operation-specific lifecycle-before-policy locking, chunk gates, and hidden-before-activation sequencing are executable. | +| QA/test | PASS AFTER FIXES | None | Contribution/award cardinality, exact uniqueness/enums, chunk file scopes, and deleted-contract evidence regressions are explicit. | +| security/auth | PASS AFTER FIXES | None | Human grants, fixed-service static authority, AUTH-only activation custody, callback isolation, and optional evidence separation are fail closed. | +| product/ops | PASS AFTER FIXES | None | Every valid human Review recognizes reviewer work; accept alone recognizes submitter work; policy, award, fulfillment, and legacy cutover boundaries are coherent. | +| architecture | PASS AFTER FIXES | None | ContributionPolicy is the eligibility aggregate, ART is absent from the core transaction, and dispatcher authority cannot leak to feature handlers. | +| CI integrity | PASS AFTER FIXES | None | Scanner changes are exact; deleted contract provenance is recovered index to HEAD to base; regular-file enforcement prevents path/symlink bypass. | +| docs | PASS AFTER FIXES | None | PR #139 precedence, optional evidence, complete ART/REV custody references, open AUTH decisions, and inherited loop-memory failure are truthful. | +| reuse/dedup | PASS AFTER FIXES | None | Existing AUTH kernel, static matrix, outbox, lifecycle, audit, adapter-factory, and PostgreSQL truth boundaries are reused. | +| test delta | PASS AFTER FIXES | None | Added regressions preserve failure for missing, malformed, unreadable, non-file, dangling/resolvable-symlink, pure-deletion, and replacement contracts. | + +Open sub-agent sessions: none + +Valid findings addressed: yes + +- Replaced the obsolete policy model with `ContributionPolicy`, immutable + `ContributionPolicyVersion`, exact `ContributionRule`, and + `ContributionAwardDefinition`; `CompensationAward` is only the evaluated + downstream result. PaymentPolicy has no compatibility path. +- Removed ART and evidence projection from the atomic Review-to-contribution + transaction. CON copies the stabilized versioned `Submission.artifact_hash`; + it does not introduce SubmissionVersion or make an ART/provider call. +- Fixed product cardinality: every valid committed human Review creates one + reviewer `completed_review`; only `accept` additionally creates submitter + `accepted_submission`; automated outcomes create neither. +- Replaced combined role semantics with independent exact `submitter`, + `reviewer`, and `adjudicator` grants. +- Reconciled 22 core proposed ActionIds to existing stable PermissionIds where + present. Policy actions use `contribution.policy.*` while retaining + `compensation.policy.manage`; optional evidence and unapproved executor + candidates are outside the core count. +- Fixed service authorization now requires provisioned ActorProfile/link, + immutable closed ServiceIdentity, exact static matrix row, AUTH-09E, typed + context, prepared mutation protocol, and later AUTH activation. There is no + persisted service grant/action-assignment row. +- Kept complete 25-action ART and 19-action REV activation-custody transfer in + WS-XINT/AUTH ownership. WS-CON references those complete handoffs and does not + restate partial subsets. +- Split human operations requests/reads/drain observation in CON-10B from + independently authorized async executors in new CON-10C. Outbox dispatch owns + mechanics only and never grants delivery, callback, reconciliation, or + rebuild authority. +- Deferred CON-09A/09B as optional successors. Neither ART nor evidence + projection gates core reads, readiness, or joint REV/CON release. +- Repaired the internal-review evidence gate for renamed/deleted contracts: + deleted headings are recovered from index, HEAD, then review base and retain + their chunk ID; missing provenance, invalid content, non-regular files, and + symlinks fail closed. + +Deterministic evidence passed: Markdown links for 44 changed Markdown files; +stale Workstream wording; stale authorization documentation; stale artifact +contracts; `git diff --check`; Python compilation for all five changed gate +files; 80/80 agent-gate tests; trusted-main ancestry; no backend diff; exact +74 PermissionId / 57 ActionId / nine active / 48 planned runtime catalogue; +and the 22-action proposal audit. The repository-wide loop-memory check has one +inherited failure: merged `origin/main` leaves the unchanged WS-AUTH status at +the human merge checkpoint. WS-CON does not edit that externally owned file to +conceal the failure. + +Application/runtime code changed: no. The original PDF deletion remains the +pre-existing unstaged user-worktree change and is excluded from both commits. + +## 2026-07-16 ART-02A2 PR #129 And Exact Custody Reconciliation + +This addendum is the current authoritative review state and supersedes older +trusted-main, ART readiness, REV worktree and ActionOwner statements below. +Trusted `main` `9a04434e2f23c5dec8939dadb943bba4d85110c0` merges ART-02A2 PR #129 and +includes AUTH-08 merge `aa0fdcd6912e66609e39a2fbd7b65f67be6c62f3`. + +Reviewed code SHA: `5538e94a66718b867280f806c9beac97ac212972` + +Reviewed non-review planning-tree SHA-256: +`b44c0685e842c57694ba0e3b4af34cbcdcaa6a423f965af3cd8d71f9fad9ea92` + +The digest excludes `reviews/**` and is reproduced from the repository root: + +```bash +find .agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary \ + -type f -name '*.md' ! -path '*/reviews/*' -print0 \ + | sort -z | xargs -0 sha256sum | sha256sum +``` + +Reviewed at: 2026-07-16T11:00:58Z + +Reviewer run IDs: architecture/senior/reuse=`/root/auth08_arch_review`; +QA/test/product/ops/docs=`/root/auth08_qa_product_review`; +security/auth/privacy=`/root/auth08_security_review` + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS | None | Pre-lock preparation, bounded Transaction A, explicit caller commit and ART-owned post-commit execution form one executable protocol. | +| QA/test | PASS | None | Exact ART write/read/recovery/media/receipt gates and concurrent-sibling discovery rules are testable. | +| security/auth | PASS | None | All eleven ART-02D actions retain exact mappings and move to closed AUTH custody without dual availability writers. | +| product/ops | PASS | None | Contribution truth remains PostgreSQL-canonical and complete PaymentPolicy removal remains unchanged. | +| architecture | PASS | None | ART owns preparation/storage; AUTH owns registration/evaluators/availability; CON owns deterministic evidence facts only. | +| docs | PASS | None | PR #129 is described as inactive preparation only and later gates are named exactly. | +| reuse/dedup | PASS | None | Canonical ART scratch/preparation, AUTH D10, shared outbox, sessions and recovery paths are reused. | +| CI integrity | N/A - with approved reason | None | Planning Markdown only; no workflow, dependency, test, threshold or runner changed. | +| test delta | N/A - with approved reason | None | No runtime test file changed; focused merged-code tests are dependency evidence only. | + +Open sub-agent sessions: none + +Valid findings addressed: yes + +- Classified merged ART-02A2 final head `32aab89262a3944f305e9e5dc4c65a2d31e2e144` + correctly: inactive `ArtifactPreparationService`, canonical bounded scratch and + sealed one-shot source only. ArtifactStore v1, providers, schema, admission, + verification, binding, contribution behavior and authorization are unchanged. +- Replaced the unsafe long-lock draft with ART-owned pre-transaction + `prepare_source`; locked AUTH -> CON -> ART staging and commitment + revalidation; caller-owned commit; a fresh committed-attempt claim; and + one-shot provider I/O outside every database transaction. Rollback, + cancellation, process loss, stale cleanup, acknowledgement loss and + deterministic replay serialize no scratch handle and retain cleanup custody + fail closed when release cannot complete. +- Made the dependency chain exact: AUTH-09 fixed identities/assignments; ART + 02A2 -> 02A3 -> 02B1 -> 02C1 -> 02C2 -> 02C3 -> hidden 02D behavior; + AUTH-owned Operator/internal evaluator activation; then the separately + approved `WS-ART-001-CON-EVIDENCE` write/read ports. CON-09A, 09B and 11 gate + the exact owning symbols separately. +- Froze media type + `application/vnd.workstream.contribution-evidence+json;version=1`, zero-I/O + rejection for invalid media or digest/size mismatch, and exact returned + binding/receipt digest, size, media, owner, project, role, schema and + idempotency validation before projection success. +- Extended D12 without changing canonical identifiers. All eight current + Operator-facing `ART_02D` ActionIds retain their existing PermissionIds under + proposed `AUTH_ART_02D_OPERATOR`; all three internal ActionIds retain theirs + under `AUTH_ART_02D_INTERNAL`. In the recommended model, AUTH atomically + removes now-unused `ART_02D` and `REV_08`, retains `REV_06`, and preserves + `{definition.owner} == set(ActionOwner)` across typed/SQL/audit parity. The + global alternative must keep feature owners and add a separate exact closed + activation-custody catalogue; mixed models and dual writers are forbidden. +- Preserved AUTH ownership. ART-02D supplies hidden feature/resource behavior + only; AUTH-09 owns service identities/assignments and later AUTH chunks alone + integrate evaluators and change availability. The three internal actions do + not imply Operator `artifact.verification_job.retry`, and the later + contribution binding action cannot substitute for either authority family. +- Inspected REV evidence-bound baseline `6faccc0`, then observed its owner begin + later external-review repairs. The live sibling is discovery only and is not + pinned by WS-CON verification; only a reviewed merge on trusted `main` may be + consumed. + +Deterministic evidence passed: `git diff --check`; Markdown links for 38 changed +Markdown files; stale Workstream wording; artifact-contract and loop-memory +state; 71 agent-gate tests; seven focused ART commitment/single-stream/ +cancellation/cleanup tests; exact trusted-main ancestry; no backend diff; +direct proof of all eleven current `ART_02D` ActionId -> PermissionId mappings; +and exact proposed owner/removal/parity assertions. The authorization stale-doc +scanner continues to flag exactly ten `HUMAN_WORKER_VOCABULARY` occurrences in +the explicitly non-canonical generation-2 working transcription. CON-01 owns +its byte-preserving archive classification and active-spec reconciliation; no +active documentation waiver was added. + +Application/runtime code changed: no. The original PDF deletion remains the +pre-existing unstaged user-worktree change and is excluded from the reviewed +content/evidence commits. + +## 2026-07-16 AUTH-08 And Parallel-REV Reconciliation + +This addendum is the current authoritative review state and supersedes older +AUTH counts, trusted-main SHAs, ActionOwner assumptions, role-candidate outcomes +and REV freshness statements below. Trusted `main` +`aa0fdcd6912e66609e39a2fbd7b65f67be6c62f3` includes AUTH-08 through PR #131. + +Reviewed code SHA: 9df6eace4921755cdd39759cece8e49c9a885382 + +Reviewed planning-tree SHA-256: +`7c49d006f505fe923e0194e1331e6e9ab7fb7da36ff506c8785f3c955ec2e372` + +The tree digest excludes this evidence file and is reproduced from the +initiative directory with: + +```bash +find . -type f ! -path './reviews/WS-CON-001-PLAN-internal-review-evidence.md' -print0 | sort -z | xargs -0 sha256sum | sha256sum +``` + +Reviewed at: 2026-07-16T09:17:13Z + +Reviewer run IDs: architecture/senior/reuse=`/root/auth08_arch_review`; +QA/test/product/ops/docs=`/root/auth08_qa_product_review`; +security/auth/privacy=`/root/auth08_security_review` + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS | None | Chunk gates, conditional human decisions, exact ownership and operational commit boundaries are coherent. | +| QA/test | PASS | None | AUTH/source/REV freshness assertions, conditional role outcomes, chunk-local evidence and release proof are executable. | +| security/auth | PASS | None | D10, D11, D12, exact matched evidence, service separation and no-CON-auth boundaries are fail-closed. | +| product/ops | PASS | None | PaymentPolicy removal remains complete; delivery/award/audit role conflicts remain explicit human decisions rather than silent policy. | +| architecture | PASS | None | All 23 actions map once to proposed activation custody; feature ownership, AUTH activation, route commits, ART and outbox boundaries do not cross. | +| CI integrity | N/A - with approved reason | None | Planning Markdown only; no workflow, dependency, runner, threshold, test or coverage configuration changed. | +| docs | PASS | None | Main, source hashes, clean REV head, planning-versus-runtime language and blockers are truthful. | +| reuse/dedup | PASS | None | One prepared D10 protocol and existing AUTH grant, outbox, ART, session, fence and composition abstractions are reused. | +| test delta | N/A - with approved reason | None | No runtime test file changed; every later runtime chunk retains test-delta review and isolated evidence gates. | + +Open sub-agent sessions: none + +Valid findings addressed: yes + +- Rebased the branch onto merged AUTH-08. Canonical main now has 74 + PermissionIds, 57 ActionIds, nine active self/admin actions, 48 planned + actions, eight resource-context variants and actor-self/AdminRoleGrant matched + authorities. All 23 proposed WS-CON actions, both proposed service permissions + and the upstream `task.claim` ActionId remain absent. +- Reused AUTH-08's resource-context digest, matched grant/project evidence, + rollback-only dependency teardown and typed retryable evidence-failure path. + Hidden domain services flush without committing; every actual route owns its + complete decision/business transaction. The service callback commits its + decision, receipt and idempotency state atomically inside its fence. +- Kept D10 AUTH-owned and single-use: authority locks first, final product facts + are evaluated once, AUTH stages one decision and never commits, and CON never + queries AUTH state or supplies role policy. +- Added D11 as an unresolved human cross-spec decision. Merged AUTH gives + Finance—but not Operator—delivery-reconcile candidacy and gives Project + Manager the broad award-read candidate; audit candidates also differ. Later + gates support either human outcome and require only the AUTH amendments or + CON-01 active-matrix changes that outcome selects. +- Added D12 because canonical ActionOwner means the chunk allowed to activate. + The recommended model proposes eight exact AUTH activation owners mapping all + 23 WS-CON actions once plus two AUTH review-action custodians. The globally + reviewed alternative must add a separate closed activation-custody type. + Missing, dual or feature-side activation custody is forbidden. +- Moved role-selection and negative grant tests to AUTH activation. CON chunks + validate typed decision causation against canonical product facts and do not + grow role-aware fakes or a second policy engine. +- Refreshed the parallel REV dependency to clean committed head + `a13bf352147cbb2c65742802e7c74a9478e5013b`. Its AUTH-08 dependency review is + accurate, but it remains non-consumable pending ART/final evidence plus + review choreography, D12 custody and handler-claims-OutboxEvent repair. +- Preserved the human-approved complete PaymentPolicy semantic cutover in + CON-05A and physical removal in CON-05B. Only legacy-row treatment remains a + separate human decision. + +Deterministic evidence passed: `git diff --check`; Markdown links for 38 changed +Markdown files; stale Workstream wording; artifact-contract and loop-memory +state; 71 agent-gate tests; two focused synchronous AUTH catalogue/role-policy +tests; exact trusted-main ancestry; all three WS-CON source hashes including the +tracked original through `git show`; clean REV head assertion; direct AUTH +catalogue/runtime/role assertions; and exact D12 23/23 unique owner coverage. +The two focused AUTH tests emitted only expected environment warnings because +the local system interpreter lacks the async pytest plugin; no async test was +claimed. The authorization stale-doc scan continues to flag exactly ten +`HUMAN_WORKER_VOCABULARY` occurrences in the explicitly non-canonical working +transcription. CON-01 owns its byte-preserving archive classification and +active-spec reconciliation; this is not a waiver for active documentation. + +Application/runtime code changed: no. The original PDF deletion remains the +pre-existing unstaged user-worktree change and is excluded from the reviewed +content/evidence commits. + +## 2026-07-15 AUTH-07B Executable-Boundary Reconciliation + +This addendum is the current authoritative review state. It supersedes the +older trusted-main SHA, AUTH runtime assumptions, activation choreography and +parallel-REV freshness statements below. The reviewed plan is based on trusted +`main` `90eca12f6398f2ef168e634244d912765572c3e5` (merged AUTH-07B). + +Reviewed code SHA: 31f7350be4a964faed4f3f0487a53de65c3f6840 + +Reviewed planning-tree SHA-256: +`07f8ed891ff15302b7b1a8e223cc122d98298d99ab0dd35660699866fff63cac` + +The tree digest excludes this evidence file and includes the final initiative +status. It is reproduced from the initiative directory with: + +```bash +find . -type f ! -path './reviews/WS-CON-001-PLAN-internal-review-evidence.md' -print0 | sort -z | xargs -0 sha256sum | sha256sum +``` + +Reviewed at: 2026-07-15T20:22:23Z + +Reviewer run IDs: architecture/senior/reuse=`/root/plan_arch_senior`; +QA/test/product/ops/docs=`/root/plan_qa_product_docs`; +security/auth/privacy=`/root/plan_security_auth` + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS | None | Activation waves, prepared mutation seams, transaction ownership and chunk boundaries are executable. | +| QA/test | PASS | None | Local gates, failure cases, races, real-kernel denial and post-activation proof are explicit. | +| security/auth | PASS | None | Canonical identifiers, grants, fixed service identities, one-decision semantics and AUTH-only activation are coherent. | +| product/ops | PASS | None | Complete PaymentPolicy removal, legacy-row human gate, callback/delivery behavior and release dependencies remain explicit. | +| architecture | PASS | None | Review choreography is non-circular; outbox, ART, REV, AUTH and CON ownership boundaries do not cross. | +| CI integrity | N/A - with approved reason | None | This delta changes planning Markdown only and does not modify CI, dependencies, tests or coverage gates. | +| docs | PASS | None | Trusted-main facts, sibling freshness, source provenance, blockers and ownership language are truthful. | +| reuse/dedup | PASS | None | The plan reuses the central prepared protocol, shared dispatcher, ART capability, `workstream.artifact.binding` and existing grants/permissions. | +| test delta | N/A - with approved reason | None | No runtime test file changed; every later runtime chunk still requires test-delta review and retained evidence. | + +Open sub-agent sessions: none + +Valid findings addressed: yes + +- Recorded the exact merged AUTH-07B state: 74 PermissionIds, 50 ActionIds, + two active and 48 planned actions. All 23 proposed WS-CON ActionIds remain + absent. The two proposed service-only PermissionIds remain absent. +- Kept authorization implementation entirely AUTH-owned: catalogue/owner/audit + parity, closed typed contexts, evaluator dispatch, matched authority, grant + loading/revalidation, service actors/assignments, composition dependencies and + availability changes. +- Added an AUTH-owned D10 prepared-mutation protocol for every `T` operation: + authority rows lock first, an opaque caller-session-bound handle is finalized + once against locked product facts, one decision is staged, and AUTH never + commits. Missing, reused, mismatched and cross-session/action handles deny. +- Repaired activation into registration -> hidden fail-closed feature behavior + -> AUTH evaluator/activation waves. Review actions add the required REV-owned + composition stage: AUTH registration -> CON capability/participant -> REV + hidden composition while planned -> AUTH activation -> later readiness/public + activation. +- Added the missing upstream dependency that `task.claim` has an existing + PermissionId but no ActionId. AUTH-13 or a reviewed AUTH successor must order + registration/typed-prepared contract, task resource behavior and evaluator/ + activation before CON-05A. +- Required the callback ActionId/new PermissionId and active binding-specific + service actor/link/exact assignment before CON-04A so binding creation is + executable while the callback action remains planned. Binding retirement + remains planned until its CON-10B dependency guards exist and a later AUTH + gate activates it. +- Put the D10 call site in CON-02B before OutboxEvent claim and made the active + `outbox.dispatch` evaluator/assignment proof a local CON-08A gate. +- Repaired evidence ownership: CON prepares authority and locks only CON facts; + ART locks/composes admission facts and performs the one final evaluation in + durable Transaction A without commit/provider I/O. Provider continuation is + post-commit under ART authority. The exact action reuses the existing fixed + `workstream.artifact.binding` principal and existing + `artifact.binding.create` PermissionId. +- Recorded sibling REV head `e59e2bbe823bc0ee2b0e59ff35f8352349618b2e` + as non-consumable until its AUTH-07B choreography, outbox claim wording, + source SHA and commit-bound evidence are refreshed and reviewed. +- Preserved the approved complete PaymentPolicy semantic cutover and physical + removal. Only the legacy-row rebuild-versus-classified-backfill choice remains + a human decision. + +Deterministic evidence passed: `git diff --check`; Markdown links for 38 changed +Markdown files; stale Workstream wording; artifact-contract state; loop-memory +state; 71 agent-gate tests; and direct AUTH catalogue/runtime assertions for the +counts, availability, absent WS-CON IDs, absent service permissions, +`task.claim`, resource variants and matched-authority state. The authorization +stale-doc scan continues to flag exactly ten `HUMAN_WORKER_VOCABULARY` +occurrences in the explicitly non-canonical working transcription; CON-01 owns +its exact byte-preserving archival rename/classification and active-spec +reconciliation. This is not a waiver for an active document. + +The focused async AUTH test environment was unavailable at final rerun because +this worktree's `backend/.venv` lacked an interpreter/plugin installation. That +does not weaken the planning proof: runtime files are byte-unchanged from +trusted main, the catalogue assertion passed with the available interpreter, +and no runtime completion is claimed. + +Application/runtime code changed: no. The original PDF deletion remains an +unstaged user-worktree change and is excluded from both reviewed commits. + +## 2026-07-15 Final Trusted-Main And Parallel-Dependency Review + +This addendum is the current authoritative review state and supersedes older +statements below about D2, AUTH-07A merge status, REV joint-release adoption, or +an uncommitted planning candidate. D2 is approved: +`CompensationPolicyVersion` completely supersedes `PaymentPolicy`; only the +legacy-row reset-versus-classified-backfill rule remains a human gate. + +Reviewed code SHA: ebdd21d231207845d44832a502de9dc56f237fd9 + +Reviewed planning-tree SHA-256: +`c3a82c1d5db19038709ff844a3bbde6cc77b21d525f408f2768d71c34883181d` + +The tree digest excludes this evidence file and is reproduced from the +initiative directory with: + +```bash +find . -type f ! -path './reviews/WS-CON-001-PLAN-internal-review-evidence.md' -print0 | sort -z | xargs -0 sha256sum | sha256sum +``` + +Reviewed at: 2026-07-15T17:08:45Z + +Reviewer run IDs: architecture/senior/reuse=`/root/plan_arch_senior`; +QA/test/product/ops/docs=`/root/plan_qa_product_docs`; +security/auth/privacy=`/root/plan_security_auth` + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS | None | The chunk map, ownership seams, stop conditions, and long-term boundaries are coherent. | +| QA/test | PASS | None | Gates, races, failure cases, evidence retention, and the exact scanner regression contract are executable. | +| security/auth | PASS | None | Merged AUTH has 74 PermissionIds/50 ActionIds; 23 WS-CON actions and two service permissions remain absent/proposed; all 12 reused permissions exist. | +| product/ops | PASS | None | Complete PaymentPolicy removal, legacy-row gate, fulfillment lifecycle, drain, and joint release behavior are explicit. | +| architecture | PASS | None | CON-02B solely owns outbox transitions; CON owns narrow ports; REV supplies only hidden release-control composition. | +| CI integrity | N/A - with approved reason | None | This reviewed delta changes planning Markdown only; CON-01 itself requires CI-integrity review when its script/test files change. | +| docs | PASS | None | Source provenance, active/archive precedence, current REV status, and PaymentPolicy removal are truthful. | +| reuse/dedup | PASS | None | Claim validation, drain observation, and lifecycle fences reuse sole owners through narrow ports without repository duplication. | +| test delta | N/A - with approved reason | None | No test file changes in this planning delta; CON-01 requires test-delta review for its planned gate regression. | + +Open sub-agent sessions: none + +Valid findings addressed: yes + +- Rebased onto trusted `main` `e9d72a1`, including merged ADR 0014 and AUTH-07A + catalogue/audit foundations, and validated exact AUTH counts/mappings. +- Preserved complete PaymentPolicy removal in split semantic-cutover and physical + removal chunks; no advisory, compatibility, or execution fallback survives. +- Made merged REV-02 exact `Submission.task_assignment_id` lineage a hard + CON-05A prerequisite. +- Preserved CON-02B as the sole OutboxEvent claim/retry/finalization owner. A + feature handler only validates immutable claim generation through + `OutboxClaimValidationPort`, never locks or mutates OutboxEvent, and returns a + typed outcome after CON work. +- Added canonical lifecycle-fence lock ordering, durable pre-I/O state, and the + prohibition on provider I/O under a database transaction, lifecycle fence, + or OutboxEvent lock. +- Assigned `FulfillmentDispatchFence`, `FulfillmentCallbackFence`, and + `FulfillmentLifecycleDrainObservationPort` to CON-owned chunks while limiting + REV-12A to hidden composition and REV-13 to sole activation/live drill. +- Recorded the content-reviewed but dirty REV snapshot atop `3e09e99` as + non-consumable. Its stale handler-claim wording must be repaired, committed, + commit-freshness reviewed, refreshed, and merged before use. +- Made CON-01 own the exact authorization-scanner history entry created by its + hash-proven archival rename plus fail-closed tests. The cross-scanner equality + assertion subtracts only that named auth-only path and separately proves the + unchanged artifact scanner already excludes reference specs by prefix. +- Preserved AUTH ownership: WS-CON proposes identifiers and supplies resource + facts/guards only; it does not implement the authorization service. + +Deterministic evidence passed: Markdown links for 38 changed Markdown files, +general stale wording, artifact-contract state, loop-memory state, 71 agent-gate +tests, reference hashes, and `git diff --check`. The authorization stale-doc +scan continues to flag ten human-worker vocabulary occurrences only in the +explicitly non-canonical working transcription. CON-01 now owns its exact +byte-preserving archive rename/classification and the reconciled active spec; +this is not a waiver for an active document. + +Application/runtime code changed: no. The original PDF deletion remains an +unstaged user-worktree change and was excluded from both reviewed commits. + +## 2026-07-15 End-to-End Reference Reconciliation Addendum + +The supplied generation-2 Markdown was audited against AUTH head `3ab25cf`, +canonical ART/REV decisions, ADR 0014, the shared-outbox plan, and current +PaymentPolicy consumers. Final internal delta reviews passed: + +| Track | Result | Closed findings | +|---|---|---| +| security/auth + senior engineering | PASS | Exact ActionId/PermissionId handoff, request-scoped AUTH boundary, service-only callback/outbox authority, human/request versus dispatcher execution, bounded callback data, split award routes | +| product/ops + QA/test | PASS | 05A/05B executable removal scope, contribution/evidence disclosure, delivery retry and callback transitions, conformance traceability | +| architecture + docs | PASS | ART typed capabilities/recovery/provider matrix, centralized adapter factory, shared outbox ownership, source provenance/hash, stale-prefix and Markdown-link checks | + +The reconciled Markdown remains a non-normative working transcription. CON-01 +still owns creation and review of the active specification/ADR; no runtime chunk +is activated by this addendum. + +## Chunk + +`WS-CON-001-PLAN` - Contribution And Compensation Planning + +open sub-agent sessions: none + +valid findings addressed: yes + +## Reviewed Revision + +Reviewed code SHA: f5995518a0d1723be5600d4bb306d99d3ba077a7 + +Reviewed planning-tree SHA-256: `367a43d2913276b1b700f9d55ae30ff812d8478c520bf338035c3b8671048f43` + +Reviewed at: 2026-07-15T14:24:59Z + +Reviewer run IDs: senior-engineering/architecture/reuse=`/root/plan_arch_senior`; +QA/test/product/ops/docs=`/root/plan_qa_product_docs`; +security/auth/privacy=`/root/plan_security_auth` + +The planning-tree digest excludes this post-review evidence file. After the +reviewed digest, only this evidence and initiative status/chunk-status fields +changed. + +## Reviewer Results + +| Reviewer | Result | Blocking findings | Notes | +|---|---:|---|---| +| senior engineering | PASS AFTER FIXES | None | Cross-initiative ownership, PR sizing, reusable infrastructure, and executable contracts repaired. | +| QA/test | PASS AFTER FIXES | None | Traceability, isolated PostgreSQL evidence, separate subsystem coverage, retained attempts, and release handoff repaired. | +| security/auth | PASS AFTER FIXES | None | Proposed action/resource contracts, service actor, binding states, rate controls, retirement and privacy repaired. | +| product/ops | PASS AFTER FIXES | None | Current re-review confirms complete PaymentPolicy removal, the open legacy-row gate, REV-02 ordering, fence ownership, and joint activation operations. | +| architecture | PASS AFTER FIXES | None | REV ownership, sole activation, outbox/audit/factory boundaries and ART/AUTH ownership are coherent. | +| CI integrity | N/A - with approved reason | None | Planning Markdown only; no workflow, script, dependency, test, or coverage gate changed. | +| docs | PASS AFTER FIXES | None | Archive provenance, active-doc inventory and generated-companion release ownership are explicit. | +| reuse/dedup | PASS AFTER FIXES | None | Shared hashing, idempotency, workers, rate control, audit, outbox, typed factory and existing Submission are reused. | +| test delta | N/A - with approved reason | None | No runtime test file changed; runtime contracts prohibit weakening and require same-run evidence. | + +## Valid Findings Addressed + +- Removed all REV-owned ReviewLease schema/claim/composition work from WS-CON; + REV-03/06/10 retain their exact ownership. +- Made REV-13 the sole joint production activation/live-drill owner and added an + exact evidence-driven release handoff without editing the sibling worktree. +- Split shared outbox truth from its dispatcher, added a shared lifecycle-audit + participant owner, and kept feature handlers separate. +- At the original pre-merge review point, reconciled trusted-main 73 + PermissionIds versus AUTH-07A's 74/50 candidate state. The current addendum + records AUTH-07A merged through `e9d72a1`; every WS-CON ActionId remains + proposed with exact target/principal/facts/ + guard/revalidation/registry/resource/activation ownership. +- Added canonical service ActorProfile binding, exact callback assignment, + actor/link/binding state distinctions, per actor+binding rate control, and + dependency-safe deferred retirement. +- Extended the accepted REV lock order and assigned every cross-feature race to + a chunk where both sides exist. +- Superseded the advisory PaymentPolicy direction with complete semantic and + physical removal plus TaskAssignment compensation freeze + one atomic cutover with drain/rebuild/downgrade rules. +- Split persistence, services, delivery, callback, evidence, reads, operations, + and release readiness into explicit contracts with exact allowed/not-allowed + paths and reviewer requirements. +- Added deterministic ADR-0014 compensation adapter/factory composition and + prohibited provider-specific/fallback/service-locator construction. +- Added exact versioned event names and a conformance matrix for retained source + invariants, role/privacy cases, races, failures, replays and live evidence. +- Added a normative runtime proof that erases stale coverage, retains immutable + attempt-specific isolated-PostgreSQL metadata, preserves the 78-percent global + floor, and runs a separate 90-percent report for every changed subsystem. + +## Commands Run + +```bash +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_artifact_contracts.py +python3 scripts/check_loop_memory_state.py +python3 scripts/test_agent_gates.py +python3 scripts/check_internal_review_evidence.py +git diff --check +sha256sum +git show HEAD: | sha256sum +python3 scripts/check_stale_authorization_docs.py +``` + +Results: + +- Markdown links passed for 35 changed Markdown files. +- General stale wording, artifact-contract and loop-memory checks passed. +- Agent gate regression suite passed: 71 tests. +- The internal-evidence gate correctly remains red in this uncommitted planning + worktree because its reviewed-SHA protocol accepts only a committed candidate, + not the supplementary planning-tree digest. Before any PR, commit the approved + planning candidate, rerun exact-head reviewers/evidence, and require this gate + to pass; this local evidence is not PR-ready proof. +- `git diff --check` passed. +- Superseded after the 2026-07-15 end-to-end reconciliation: the Markdown is + now an editable working transcription with a new truthful hash in + `SOURCE_MANIFEST.md`; the generation-2 PDF hash remains unchanged. +- Authorization stale-contract scan intentionally rejects the unadopted raw + candidate Markdown for `/v1` and legacy human-worker vocabulary. This is the + evidence requiring archival treatment and a reconciled active spec in CON-01, + not a gate waiver for an active document. + +## Remaining Risks + +- D1/D7/D8 and the callback/outbox service PermissionIds require explicit human + approval. D2 removal is approved; only legacy-row handling remains open. +- Original PDF disposition remains a pre-existing user-worktree concern; + generation-2 PDF preservation and working-Markdown provenance remain CON-01 + gates. +- AUTH, ART and REV prerequisites are unmerged. The active REV working delta + incorporates `JOINT_RELEASE_HANDOFF.md` but must become a branch-reachable + reviewed commit, rebase, and merge before either public surface can activate. +- Exact migration numbers, merged symbols, production adapter/provider and live + values must be refreshed at each approved implementation chunk. +- This uncommitted reviewed plan still requires a committed exact-head review + cycle before it can be published or treated as PR evidence. + +## Stop Condition + +Planning is internally reviewed. No implementation/specification chunk is +active. Await explicit human approval; do not start WS-CON-001-01 automatically. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN2-internal-review-evidence.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN2-internal-review-evidence.md new file mode 100644 index 00000000..4a873134 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN2-internal-review-evidence.md @@ -0,0 +1,116 @@ +# WS-CON-001-PLAN2 Internal Review Evidence + +## AUTH And REV current-main provenance rebind + +Reviewed code SHA: a69fad3a32ad47e3bd60a79cd75f5867eefc52b3 +Reviewed at: 2026-07-17T18:14:54Z +Reviewer run IDs: auth08_arch_review/final-a69fad3, auth08_qa_product_review/final-a69fad3, auth08_security_review/final-a69fad3 + +This provenance-only addendum binds the reviewed FinalAcceptance reconciliation +to the final cumulative planning snapshot. It changes no PLAN2 lifecycle fact. +The exact-SHA re-review confirms that PLAN3 preserves REV-owned +FinalAcceptance, CON flush-only participation, all three review outcomes, and +the no-adjudication boundary while adopting merged REV's exact two-operation +ordering and joint release-control contract. The external-review repair changes +only future chunk executability, AUTH prerequisite placement, and deferred +proposal classification; it does not alter PLAN2 lifecycle facts. + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS AFTER FIXES | None | FinalAcceptance and contribution responsibilities retain single owners and one commit after contract metadata repair. | +| qa/test | PASS | None | Accept, needs-revision, reject, lineage, rollback, and evidence completeness pass. | +| security/auth | PASS | None | No FinalAcceptance action/API, adjudication path, authorization bypass, or CON evaluator is introduced. | +| product/ops | PASS | None | Reviewer and submitter contribution triggers remain Review and FinalAcceptance respectively. | +| architecture | PASS AFTER FIXES | None | REV persistence, two CON operations, REV composition, joint release control, and later AUTH activation remain correctly ordered. | +| ci integrity | PASS | None | The rebind changes evidence only and weakens no gate. | +| docs | PASS AFTER FIXES | None | Historical PLAN2 conclusions, merged REV refinements, and final provenance are explicit. | +| reuse/dedup | PASS | None | Existing REV/AUTH contracts are referenced without a parallel path. | +| test delta | PASS | None | No test delta; all 80 agent-gate tests pass. | + +Valid findings addressed: yes + +Open sub-agent sessions: none + +Date: 2026-07-17 + +## Reviewed boundary + +The reviewed specification snapshot establishes: + +- `Review(accept) -> FinalAcceptance -> accepted_submission`; +- one reviewer `completed_review` for every valid human Review; +- REV-owned Review/FinalAcceptance/task/assignment/audit/outbox orchestration + and one commit; +- CON-owned flush-only contribution/award participation with no ART or provider + call; +- canonical `Submission.id` version identity and exact immutable + `ReviewPolicy.id` lineage; +- exact `accepted`, `needs_revision`, and `rejected` effects; and +- no v0.1 adjudication action, policy, queue, lease, state, decision, + contribution, branch, readiness dependency, manual FinalAcceptance API, or + independent FinalAcceptance authorization action. + +The pre-existing deletion of the archival WS-CON PDF was excluded from this +chunk and remains user-owned. + +## Internal reviews + +### Architecture + +Final result: PASS. + +Resolved findings: + +- removed the REV/CON cycle by ordering REV persistence and locked lineage, + then CON-03C/07, then REV hidden composition, then AUTH activation; +- resolved `policy_context_ref` to canonical immutable `ReviewPolicy.id`; +- reverted an out-of-scope global AUTH role-catalogue wording change; +- bounded active reviewer-quality wording changes explicitly in PLAN2; and +- consolidated duplicate second-review/template language into non-mutating + post-decision quality-audit sampling. + +### QA, product/ops, docs, and test delta + +Final result: PASS. + +Resolved findings: + +- made non-accept effects exact: needs revision keeps the Assignment active; + reject uses canonical Task `rejected`, blocks only the same-task Assignment + with its source Review, and changes no grant or unrelated task; +- rejected the archival `closed/review_rejected` token using current REV plan, + discovery, and conformance evidence; +- classified historical `docs/review_*` recommendations as non-normative; and +- removed active mutating “overturned”/second-review wording in favor of + non-mutating reviewer-quality audit observations. + +### Security and authorization + +Final result: PASS. + +The reviewer confirmed no FinalAcceptance ActionId/API, adjudication path, +catalogue/runtime/backend change, grant mutation, cross-task reject effect, or +authorization bypass. CON remains flush-only and REV remains the sole commit +owner. + +## Deterministic evidence + +Passed on the final reviewed snapshot: + +```text +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_authorization_docs.py +python3 scripts/check_stale_artifact_contracts.py +PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -m pytest -q scripts/test_agent_gates.py +git diff --check +test -z "$(git diff --name-only -- backend)" +``` + +Result: 80 agent-gate tests passed; markdown links and all stale-contract scans +passed; no backend delta exists. + +## Stop + +PLAN2 is complete but unpublished. No runtime chunk, push, or PR begins without +explicit human direction. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-external-review-response.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-external-review-response.md new file mode 100644 index 00000000..8fcaeb2c --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-external-review-response.md @@ -0,0 +1,74 @@ +# WS-CON-001-PLAN3 External Review Response + +## Review source + +CodeRabbit review of PR #142, run +`26a5debe-60e5-445a-840c-f7155725fd90`, against `0302bcf...adf5cc1`. +Five unresolved consolidated threads and one PR-description warning were +triaged on 2026-07-17. + +## Comments addressed + +1. `PRRT_kwDOSwL_U86R1pF_`: added deterministic runnable verification commands, + coverage targets, and explicit pass criteria to CON-01, 02A, 02B, 02C, 10A, + 10B, 10C, and 11. +2. `PRRT_kwDOSwL_U86R1pGB`: moved AUTH registration, ServiceIdentity/static + authority, typed-context, custodian, and prepared-protocol ownership into + approved prerequisites/handoff inputs for CON-02B, 10A, and 10B. Acceptance + criteria now cover only CON-owned composition and behavior. +3. `PRRT_kwDOSwL_U86R1pGD`: moved contribution-policy action registration out + of CON-04B. The hidden feature may consume reviewed AUTH ports, but AUTH + alone owns later registration, evaluator integration, and activation. +4. `PRRT_kwDOSwL_U86R1pGE`: added deterministic runnable verification commands, + coverage targets, and explicit pass criteria to CON-04B, 05A, 05B, 06, 07, + 08A, 08B, and 08R. +5. `PRRT_kwDOSwL_U86R1pGI`: moved CON-09B out of executable `chunks/` and + corrected it from an incomplete “Chunk Contract” to a non-executable + “Deferred Proposal.” It now has prospective risk, zero current allowed + files, explicit prohibitions, exact-whitelist promotion checks, required + reviewers, and a mandatory fresh replacement contract after separate + human/ART/AUTH approval. +6. CodeRabbit description warning: the PR body is replaced with the complete + PLAN3 trust-bundle structure after the reviewed repair is pushed. + +## Comments deferred + +None. CON-09B implementation remains intentionally deferred by product scope, +but the review concern about presenting an incomplete actionable contract is +addressed now. + +## Human decisions needed + +None for this repair. The human directed that all CodeRabbit findings be fixed. +Existing separate approval gates for CON-01, optional CON-09A/09B, and PR merge +remain unchanged. + +## Commands rerun + +```text +Markdown links: PASS (61 changed Markdown files before evidence refresh) +Stale Workstream wording: PASS +Stale authorization docs: PASS +Stale artifact contracts: PASS at foundation phase +Loop-memory state: PASS +Agent gates: PASS (80 tests) +Merge-intent validation: PASS +Bash syntax for every new verification block: PASS +Diff integrity: PASS +Repair backend/.github/scripts delta: none +Required exact-SHA internal tracks: PASS at a69fad3a32ad47e3bd60a79cd75f5867eefc52b3 +``` + +The internal-review evidence gate is run in a clean worktree after this +provenance-only rebind commit; it must pass before push. + +## Remaining risks + +- Future implementation filenames and migrations must replace each contract's + explicit placeholder without broadening its allowed scope. +- Focused pytest selectors are required to select at least one test; a zero-test + selection is a failure, not a pass. +- CON-09B remains non-executable until a fresh replacement contract is + separately approved and reviewed against then-current ART/AUTH boundaries. +- GitHub threads remain open until the reviewed repair is pushed; they are + resolved only after the remote diff contains these fixes. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-internal-review-evidence.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-internal-review-evidence.md new file mode 100644 index 00000000..5082aaf0 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-internal-review-evidence.md @@ -0,0 +1,175 @@ +# WS-CON-001-PLAN3 Internal Review Evidence + +Reviewed code SHA: a69fad3a32ad47e3bd60a79cd75f5867eefc52b3 +Reviewed at: 2026-07-17T18:14:54Z +Reviewer run IDs: auth08_arch_review/final-a69fad3, auth08_qa_product_review/final-a69fad3, auth08_security_review/final-a69fad3 + +## Reviewed boundary + +The exact reviewed snapshot reconciles CON planning with merged AUTH PR #140, +AUTH-09A runtime, and REV PR #128 at trusted `main` `0302bcf`. It authorizes the +provenance-only rebind of the older PLAN/PLAN2 evidence required by the +cumulative PR gate. After that reconciliation, the CodeRabbit repair changes 24 +planning-path entries with 713 insertions and 120 deletions relative to +`adf5cc1`. It changes no backend, migration, runtime catalogue, test, script, +workflow, dependency, or merge-intent content. + +The reviewed boundary establishes: + +- 74 runtime PermissionIds and 65 ActionIds, with nine active and 56 planned; +- no registered CON-specific ActionId and no task-claim ActionId; +- stable PermissionId `task.claim` followed by the safe order AUTH-10/PREP and + task seam, CON-05A hidden freeze and task composition, then AUTH-13 action + enumeration/registration/evaluator integration/activation; +- planned `review.claim` and `review.decision` actions gated on the merged + mandatory CON participant, REV-owned composition, and later AUTH activation; +- exact AUTH-PREP authority-first lock, opaque-handle binding, feature-lock, + recomposition, single AUTH evaluation, flush-only participant, and + caller-owned commit semantics; +- 22 explicitly unregistered, non-final CON surface mappings and no speculative + `AUTH_CON_*` ActionOwner candidates; +- a mandatory CON flush-only participant with a reviewer operation after + immutable Review/findings/resolutions and lease/queue closure but before the + decision branch, plus an accept-only submitter operation after exact + FinalAcceptance and accepted task/assignment effects; +- exact REV-owned FinalAcceptance fields `submission_id`, `recorded_by`, and + `policy_context_ref`, with submitter contribution sourced only from that fact; +- REV-12A as the sole joint release controller/fence, with every CON + obligation writer fenced before monotonic root ordinal allocation and + same-generation at-or-below-cutoff completion during delivery drain; +- `Review(accept) -> FinalAcceptance -> accepted_submission`, with REV as the + transaction owner, no separate FinalAcceptance action/API, no adjudication + dependency, and no independent CON commit; and +- one schema-v2 merge intent naming `WS-CON-001-01` as an explicit-start + same-initiative successor; +- executable, fail-closed verification commands and pass criteria for 16 active + future chunks, with 78 percent repository and 90 percent focused coverage; +- AUTH registration/context/custody/prepared-port inputs as merged upstream + prerequisites, never CON-owned acceptance work; and +- optional CON-09B outside `chunks/` as a zero-file deferred proposal requiring + separate ART/AUTH/human approval and a fresh reviewed replacement contract. + +## Reviewer results + +| Reviewer | Result | Blocking findings | Notes | +|---|---|---|---| +| senior engineering | PASS AFTER FIXES | None | The 24-path external repair is cohesive, bounded, executable, and planning-only after all review findings. | +| qa/test | PASS AFTER FIXES | None | Focused selectors, migrations, rollback/race proof, coverage, 08B scope, and deferred 09B semantics pass. | +| security/auth | PASS AFTER FIXES | None | AUTH prerequisites, registration order, fail-closed commands, 09B whitelist, and template CI controls pass. | +| product/ops | PASS AFTER FIXES | None | FinalAcceptance, contribution, compensation, fulfillment cutoff, and no-adjudication behavior remain unchanged. | +| architecture | PASS AFTER FIXES | None | Two-operation sequencing, upstream AUTH ownership, executable gates, 09B deferral, and release control pass. | +| ci integrity | PASS AFTER FIXES | None | No CI/workflow/test/runtime delta or bypass; repository 78 and focused 90 percent floors remain mandatory. | +| docs | PASS AFTER FIXES | None | PR-template structure, external response, review log, allowed scope, canonical names, and provenance are explicit. | +| reuse/dedup | PASS | None | No duplicate runtime abstraction or alternative authorization path is introduced; common AUTH/REV contracts are referenced. | +| test delta | PASS | None | No tests changed; 80 existing agent-gate tests and all static gates pass. | + +## Findings and repairs + +### Resolved substantive finding + +Initial QA and security reviews found that the draft treated `task.claim` as an +existing ActionId. Runtime inspection proved it exists only as a PermissionId. +The plan, discovery, handoff, decisions, status, chunk map, PLAN3 contract, and +CON-05A contract now state that the ActionId remains absent until the hidden +freeze and task composition merge. AUTH-13 alone owns the later enumeration, +registration, evaluator integration, and activation. + +### Resolved process finding + +The exact-SHA QA re-review found that the PLAN3 contract's evidence criterion +could not be complete until this evidence file and the PR trust bundle existed. +Both were added after review through paths explicitly allowed by the repository +evidence gate; no reviewed planning or implementation file changed afterward. +The final exact-SHA rebind then added the two older evidence paths to PLAN3's +allowed scope so every evidence file added by the cumulative branch can carry +current, parser-complete provenance without rewriting historical conclusions. + +### Resolved current-main architecture finding + +The first current-main architecture review found that the PLAN3 title still +named only AUTH PR #140 and that its allowed-file list repeated CON-07. The +contract title now matches the AUTH-and-REV current-main merge intent and the +duplicate row is removed. All required reviewers re-ran against exact SHA +`e968430b0c3b5f1432899c9aa31ef209b774eae0`. + +### Resolved external-review findings + +CodeRabbit's five consolidated threads and description warning were valid at +the contract/process level. The repair: + +- adds exact focused commands, non-empty selection, coverage floors, and pass + criteria to all 16 affected active chunks; +- moves AUTH registration/context/custody/prepared-port requirements to + upstream prerequisites while retaining registration -> hidden behavior -> + evaluator/activation ordering; +- moves CON-09B from `chunks/` to `deferred/`, gives it no current allowed + implementation files, and fail-closes promotion to an exact planning-path + whitelist; +- aligns CON-08B allowed tests, runtime-verification row, selector, and Ruff + targets; +- replaces fail-open Git/Ripgrep absence checks with status-sensitive checks; + and +- mirrors the repository PR template and records the repair in the external + response and root review log. + +Initial internal re-review found and repaired the remaining 04B ordering, +09B whitelist/location, 08B scope, review-log, allowlist, shell-failure, and +trust-template defects. All required tracks then passed exact SHA +`a69fad3a32ad47e3bd60a79cd75f5867eefc52b3`. + +### Confirmed non-findings + +- A failed same-session/action substitution does not consume an otherwise valid + prepared handle. +- ServiceIdentity, static-matrix membership, and action availability are + code-owned validations rather than database lock targets. +- CON imports no AUTH persistence, grant query, evaluator, registration, + ActionOwner, or availability writer. +- FinalAcceptance has no public API or independent authorization action. +- FinalAcceptance uses REV's canonical `submission_id`, `recorded_by`, and + `policy_context_ref` names; CON does not redefine the entity. +- REV owns the sole joint release controller/fence; CON adds no parallel + controller or lifecycle state. +- No adjudication lifecycle or dependency was introduced. +- The archival PDF deletion is user-owned, unstaged, and excluded from every + reviewed commit. + +## Deterministic evidence + +```text +python3 scripts/check_markdown_links.py + PASS - 61 changed Markdown files before evidence refresh +python3 scripts/check_stale_workstream_wording.py + PASS +python3 scripts/check_stale_authorization_docs.py + PASS +python3 scripts/check_stale_artifact_contracts.py + PASS - foundation phase +python3 scripts/check_loop_memory_state.py + PASS +PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -m pytest -q scripts/test_agent_gates.py + PASS - 80 tests +git diff --check adf5cc1..a69fad3 + PASS +git diff --check + PASS +external-review repair backend/.github/scripts delta + none +python3 scripts/update_post_merge_memory.py validate-merge-intent --base-ref origin/main + PASS - WS-CON-001-PLAN3 +``` + +The circuit-breaker passed with a documentation-only size exception. The full +branch is large because it contains the original reference transcription and +durable planning/review history, but the external repair is one bounded 24-path +planning correction, has no runtime boundary, and required no split. + +Valid findings addressed: yes + +Open sub-agent sessions: none + +## Stop + +PLAN3 is reviewed for PR #142 refresh. This evidence authorizes no merge +or CON-01 start. The user retains the human checkpoint and must explicitly +approve PR #142 before merge. diff --git a/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-pr-trust-bundle.md b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-pr-trust-bundle.md new file mode 100644 index 00000000..f222ede8 --- /dev/null +++ b/.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-pr-trust-bundle.md @@ -0,0 +1,307 @@ +# Workstream PR Trust Bundle: WS-CON-001-PLAN3 + +## Chunk + +`WS-CON-001-PLAN3` - AUTH And REV Current-Main Reconciliation. + +Merge intent: `.agent-loop/merge-intents/WS-CON-001-PLAN3.json` + +## Goal + +Reconcile the contribution and compensation plan with trusted `main` at merged +REV PR #128 (`0302bcf`), which contains AUTH-09A after AUTH PR #140, before any +CON runtime implementation begins. + +## Human-Approved Intent + +- Intent: `.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/INTENT.md` +- Chunk contract: `.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/chunks/WS-CON-001-PLAN3-auth-pr140-reconciliation.md` + +- The current compensation-policy model completely supersedes the retired + policy model; no compatibility path returns. +- The v0.1 accept path is `Review(accept) -> FinalAcceptance -> + accepted_submission` with no adjudication lifecycle. +- REV owns Review and FinalAcceptance orchestration and the single transaction; + CON is a mandatory flush-only contribution/award participant. +- AUTH owns identifiers, grants, evaluator integration, ActionOwner custody, + evidence, and activation. CON must validate upstream planning rather than + copy speculative identifiers. +- Pull and reconcile merged AUTH work before publishing this plan; do not start + CON runtime work automatically. +- Consume merged REV's exact FinalAcceptance shape, two-operation CON + participant, initiative interleaving, and sole joint release-control contract. + +## What Changed + +- Rebased CON authorization assumptions on AUTH PR #140 and AUTH-09A's current + runtime catalogue while preserving PR #139 as the underlying boundary. +- Replaced the older prepared-authorization description with the exact opaque, + single-use handle binding and authority-first lock protocol. +- Corrected `task.claim`: only its stable PermissionId exists; no task-claim + ActionId is registered. +- Ordered task work as AUTH-10/PREP and the task seam, then CON-05A hidden + policy freeze plus task composition, then AUTH-13 enumeration, registration, + evaluator integration, and activation. +- Preserved planned `review.claim` and `review.decision` actions and their + dependency on hidden CON participants, REV composition, and later AUTH + activation. +- Replaced the obsolete nullable omnibus review participant with reviewer and + accept-only submitter operations at REV's exact lifecycle points. +- Adopted REV's canonical FinalAcceptance field names and exact REV/CON chunk + interleaving. +- Made REV-12A the sole joint release controller/fence and specified CON's + root-ordinal, maximum-ordinal, drain, dispatch, callback, and writer hooks. +- Removed speculative `AUTH_CON_*` ActionOwner candidates. The 22 CON surface + mappings remain unregistered, non-final proposals. +- Added the reviewed PLAN3 contract and one schema-v2 merge intent naming + `WS-CON-001-01` as the same-initiative successor with an explicit start gate. + +## Why It Changed + +Treating a PermissionId as an existing ActionId would invert the safe rollout: +AUTH could activate task claim before the assignment captured its immutable +contribution-policy version. The corrected order keeps the feature unavailable +until hidden behavior and rollback proof are merged. + +## Design Chosen + +AUTH locks current actor/link/exact-grant authority first and prepares one +opaque handle bound to session, ActionId, actor-reference kind/reference, +idempotency key, and canonical request digest. The feature then locks product +rows and recomposes final facts. AUTH consumes the handle, evaluates once, and +stages evidence. Participants flush only and the owning request/command commits +once. A failed substitution attempt does not consume an otherwise valid handle. + +ServiceIdentity, static-matrix membership, and action availability are +code-owned validations, not database lock targets. No AUTH persistence, grant +query, evaluator, identifier registration, or availability writer moves into +CON. + +FinalAcceptance remains an internal REV-derived fact with canonical +`submission_id`, `recorded_by`, and `policy_context_ref`, no public API, and no +separate authorization action. The mandatory CON participant receives a +reviewer operation before the branch and, only for accept, a submitter operation +after FinalAcceptance and accepted Task/Assignment effects. No adjudication +policy, state, action, queue, lease, contribution, or release dependency is +added. + +REV owns the sole `JointLifecycleReleaseControl` and +`JointLifecycleMutationFence`. CON fences every fulfillment-obligation root +creation/requeue/successor/repair writer before immutable monotonic ordinal +allocation. Delivery-draining completion is limited to same-generation roots +at or below the persisted cutoff; provider I/O occurs outside the transaction +and fence. + +## Alternatives Rejected + +- Activating task claim before CON-05A: rejected because assignment policy + lineage would not be guaranteed. +- Treating `task.claim` as an existing ActionId: rejected by runtime catalogue + evidence. +- Retaining `AUTH_CON_*` planning labels: rejected because PR #140 approves no + such ActionOwner values. +- Giving CON an authorization evaluator or commit: rejected because those + responsibilities remain AUTH- and request-owned. +- Adding a FinalAcceptance action or adjudication branch: rejected by the + approved v0.1 lifecycle. + +## Scope Control + +### Allowed Files Changed + +- Sixteen active WS-CON future chunk contracts. +- CON-09B moved from `chunks/` to `deferred/` as one non-executable proposal. +- PLAN3 contract, STATUS, RUNTIME_VERIFICATION, trust bundle, and external + response under the WS-CON initiative. +- Root `.agent-loop/REVIEW_LOG.md` for the required durable external-review + record. +- No merge-intent content changed; the cumulative PR still contains exactly one + existing PLAN3 schema-v2 merge intent. + +### Files Outside Contract + +- None. The user-owned archival PDF deletion is unstaged and excluded. + +The current-main reconciliation changes 22 planning/merge-intent files with 429 +insertions and 178 deletions. It changes no backend, migration, test, workflow, +script, dependency, runtime catalogue, or active product document. Before the +final evidence rebind, the full planning branch is 69 files with 8,874 +insertions and 90 deletions against `origin/main`; most of that delta is the original reference +transcription and durable planning/review record. + +The circuit-breaker passed with a documentation-only size exception: the branch +is one coherent specification initiative, its runtime boundary is empty, and +the earlier planning snapshots retain their own review evidence. The user-owned +deletion of the archival CON PDF is unstaged and excluded. + +The PR #142 external-review repair has 24 changed-path entries relative to the +pre-review head: 16 active chunk contracts; the old/new paths for one CON-09B +move; PLAN3, STATUS, RUNTIME_VERIFICATION, trust bundle, external-response log, +and root REVIEW_LOG. It adds no runtime, AUTH/REV/ART-owned, workflow, +dependency, migration, test, or merge-intent content change. The repair makes +verification executable and preserves upstream AUTH ownership rather than +changing product behavior. + +## Product Behavior + +- [x] No Workstream product behavior changed. +- [ ] Product behavior changed and is explained here. + +This PR changes planning, lifecycle wording, future chunk contracts, and review +evidence only. It adds no runtime route, model, migration, action, permission, +grant, worker, provider call, or activation. + +## Evidence + +### Commands Run + +```bash +python3 scripts/check_markdown_links.py +python3 scripts/check_stale_workstream_wording.py +python3 scripts/check_stale_authorization_docs.py +python3 scripts/check_stale_artifact_contracts.py +python3 scripts/check_loop_memory_state.py +PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -m pytest -q scripts/test_agent_gates.py +python3 scripts/update_post_merge_memory.py validate-merge-intent --base-ref origin/main +git diff --check +``` + +### Result Summary + +```text +Markdown link check: PASS (60 changed Markdown files before final evidence refresh) +Stale Workstream wording: PASS +Stale authorization documentation: PASS +Stale artifact contracts: PASS at foundation phase +Loop-memory state: PASS +Agent gates: PASS (80 tests) +External-review repair diff check: PASS +Working-tree diff check: PASS +External-review repair backend/.github/scripts delta: none +Merge-intent schema-v2 validation: PASS +Local roadmap workbook: not present, so no sheet-export check applies +``` + +## Acceptance Criteria Proof + +- Runtime catalogue verified at 74 PermissionIds and 65 ActionIds: nine active, + 56 planned, no CON-specific ActionId, and no task-claim ActionId. +- Prepared-handle wording matches merged AUTH PR #140. +- The task and review activation sequences explicitly require hidden feature + behavior before AUTH-only activation. +- Reviewer and submitter contribution lineage remains Review and + FinalAcceptance respectively, inside the REV-owned transaction. +- FinalAcceptance names and CON operation ordering match merged REV PR #128. +- One shared release controller/fence, monotonic root ordinal, cutoff capture, + and same-generation at-or-below-cutoff completion match REV-12A. +- The 22 CON mappings are explicitly unregistered/non-final; only the two + proposed service PermissionIds remain identified as proposals. +- Merge-intent validation passes for successor `WS-CON-001-01`. +- Every CodeRabbit contract finding is dispositioned without moving AUTH-owned + registration, evaluation, or activation into CON. +- Sixteen active future chunks name runnable focused commands, non-empty test + selection, repository coverage 78, focused coverage 90, and explicit pass + criteria. +- Optional CON-09B is a zero-file deferred proposal until a separately approved + replacement contract closes then-current ART/AUTH disclosure scope. + +## Test Delta + +### Tests Added + +- None; this planning repair defines mandatory commands for future chunks. + +### Tests Modified + +- None. + +### Tests Removed Or Skipped + +- None. + +## Internal Reviewer Results + +Reviewed code SHA: a69fad3a32ad47e3bd60a79cd75f5867eefc52b3 + +Reviewed at: 2026-07-17T18:14:54Z + +Reviewer run IDs: auth08_arch_review/final-a69fad3, auth08_qa_product_review/final-a69fad3, auth08_security_review/final-a69fad3 + +| Reviewer | Result | Blocking Findings | Notes | +|---|---:|---|---| +| Senior engineering | PASS AFTER FIXES | None | Scope, executable gates, deferred proposal, and durable review record pass. | +| QA/test | PASS AFTER FIXES | None | Selectors, migrations, rollback/races, 08B scope, and coverage criteria pass. | +| Security/auth | PASS AFTER FIXES | None | AUTH ownership/order, fail-closed checks, 09B whitelist, and trust controls pass. | +| Product/ops | PASS AFTER FIXES | None | No contribution, compensation, review, or release behavior changed. | +| Architecture | PASS AFTER FIXES | None | Boundaries and future chunk ordering remain coherent. | +| CI integrity | PASS AFTER FIXES | None | No CI/test/runtime delta or threshold/bypass weakening. | +| Docs | PASS AFTER FIXES | None | PR template, external response, scope, review log, and provenance pass. | +| Reuse/dedup | PASS | None | Existing runtime-verification and AUTH/REV contracts are reused. | +| Test delta | PASS | None | No tests changed; 80 agent-gate tests pass. | + +The final repair results are rebound in +`WS-CON-001-PLAN3-internal-review-evidence.md` without changing reviewed +planning content after exact-SHA review. + +## External Review + +External review response file: + +- `.agent-loop/initiatives/WS-CON-001-contribution-compensation-boundary/reviews/WS-CON-001-PLAN3-external-review-response.md` + +| Source | Status | Notes | +|---|---:|---| +| CodeRabbit | Addressed locally; push pending | Five consolidated threads and the description warning are repaired. | +| GitHub checks | Pending rerun | Agent Gates and Backend passed before this repair. | + +## CI And Gate Integrity + +- [x] No workflow weakening. +- [x] No lint/test/docstring gate weakening. +- [x] No coverage threshold weakening. +- [x] No package script weakening. +- [x] No unpinned new GitHub Action. +- [x] Checkout credential persistence remains unchanged; no workflow changed. + +### Integrity Detail + +PLAN3 changes no test or CI file, removes no assertion, skips no test, changes +no threshold, and adds no bypass. Existing agent-gate coverage remains intact. + +## Remaining Risks + +- Future test selectors must select at least one test and future migration + placeholders must be replaced by exact reviewed filenames. +- Optional CON-09B could drift unless its fresh contract repeats the separate + ART/AUTH/human approval gate. + +## Follow-Up Work + +- AUTH-13 must be refreshed to consume the merged CON-05A/task-composition + manifest before task-claim registration or activation. +- Future CON actions need complete feature manifests and exact AUTH-owned + registration/activation contracts; the proposed table is not a registry. +- `review.claim` and `review.decision` remain unavailable until their complete + REV/CON composition and AUTH gates merge. +- CON-01 remains a separate explicit human start after this planning PR. + +## Human Review Focus + +Confirm the corrected task-claim ordering, exact prepared-handle contract, +two-operation Review/FinalAcceptance/contribution transaction, canonical +FinalAcceptance names, sole REV-12A release controller/fence, executable future +chunk gates, and upstream-only AUTH registration/activation ownership. Also +confirm that optional CON-09B remains non-executable until fresh approval and +that the cumulative planning PR is acceptable as one coherent specification +record. + +## Human Merge Ownership + +This bundle authorizes refreshing PR #142, not merging it. The user must +explicitly approve PR #142 for merge. No successor chunk starts automatically. + +- [ ] I can explain what changed. +- [ ] I can explain why it changed. +- [ ] I know what could break. +- [ ] I accept the remaining risks. +- [ ] The user explicitly approved this specific PR for merge. diff --git a/.agent-loop/merge-intents/WS-CON-001-PLAN3.json b/.agent-loop/merge-intents/WS-CON-001-PLAN3.json new file mode 100644 index 00000000..926058d8 --- /dev/null +++ b/.agent-loop/merge-intents/WS-CON-001-PLAN3.json @@ -0,0 +1,9 @@ +{ + "chunk_id": "WS-CON-001-PLAN3", + "chunk_title": "AUTH And REV Current-Main Reconciliation", + "initiative_id": "WS-CON-001", + "next_chunk_id": "WS-CON-001-01", + "next_chunk_title": "Canonical Contract Adoption And Architecture Decision", + "next_requires_explicit_start": true, + "schema_version": 2 +} diff --git a/README.md b/README.md index ce633c0b..5b7d1004 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Project Guide -> Platform Checkers -> Human Review -> Needs Revision / Accepted / Rejected +-> Final Acceptance on Accepted -> Contribution Record -> Compensation Award / Fulfillment when payable -> Reputation Update @@ -51,7 +52,8 @@ Different projects speak different domain languages, but serious task evaluation - every review creates a decision - every revision must close prior feedback - every valid human review creates a reviewer contribution -- every accepted task additionally creates a submitter contribution +- every accepted Review creates one immutable FinalAcceptance +- every submitter accepted_submission contribution consumes FinalAcceptance - every payable contribution updates compensation fulfillment; all contributions can update reputation @@ -252,7 +254,7 @@ Run checks Review packet Record review decision: accept, needs_revision, or reject Create reviewer contribution for every valid human review -Create submitter contribution only for accepted work +On accept, create FinalAcceptance then create the submitter contribution only from it Record compensation status only for payable contribution awards Update reputation from review outcome Review lessons learned @@ -287,7 +289,8 @@ Artifacts, evidence, and auditing: Contribution and compensation: - every valid human review creates a reviewer contribution from locked evidence -- accepted work additionally creates a submitter contribution +- accepted work creates an immutable FinalAcceptance, which is the sole source + for the submitter contribution - only payable contributions create immutable awards and fulfillment tracking; explicit unpaid rules create none - compensation fulfillment is recorded separately from task acceptance diff --git a/docs/architecture_brief/workstream_architecture_brief.md b/docs/architecture_brief/workstream_architecture_brief.md index adfb4f73..187a548f 100644 --- a/docs/architecture_brief/workstream_architecture_brief.md +++ b/docs/architecture_brief/workstream_architecture_brief.md @@ -44,7 +44,7 @@ Current v0.1 is backend-first and internal-loop-first. External source adapters, | Postgres record database | Local, CI, and production-like development use Postgres as the record database. | | Object-storage abstraction | Local filesystem storage is allowed only behind the provider-neutral `ArtifactStore`; AWS S3 is the v0.1 hosted provider and MinIO is the local/CI protocol proof. | | Async-first execution | Long-running checker work does not block request/response paths. | -| Contribution before compensation | Every valid human review creates a reviewer contribution; accepted work additionally creates a submitter contribution. Compensation and reputation attach afterward. | +| Contribution before compensation | Every valid human Review creates a reviewer contribution; accepted work creates REV-owned FinalAcceptance, which alone sources the submitter contribution. Compensation and reputation attach afterward. |
diff --git a/docs/architecture_data_model.md b/docs/architecture_data_model.md index e4bcfe4d..2eb4b47a 100644 --- a/docs/architecture_data_model.md +++ b/docs/architecture_data_model.md @@ -44,6 +44,7 @@ Task ReadinessCertificate (later optional) Review ReviewFinding + FinalAcceptance (accept only) RevisionReplay RevisionContextPreparation ContributionRecord @@ -1452,6 +1453,36 @@ new ReviewLease independently freezes the then-current The contributor and reviewer packets must show the prior version, next version, rebase reason, and change summary when `context_rebased = true`. +## FinalAcceptance + +Fields: + +- `id` +- `project_id` +- `task_id` +- `submission_id` +- `source_review_id` +- `accepted_submitter_id` +- `accepted_at` +- `recorded_by_reviewer_id` +- `review_policy_id` + +Purpose: + +This immutable REV-owned internal fact is created only inside the authorized +`Review(accept)` transaction. Existing `Submission` is already the version +identity, so the stored FK is `submission_id`; no SubmissionVersion entity or +`submission_version_id` alias is introduced. `review_policy_id` is the exact +locked ReviewPolicy context for the accepted Review. + +PostgreSQL enforces `UNIQUE(task_id)`, `UNIQUE(source_review_id)`, and +`UNIQUE(submission_id)` plus same-project/task/Submission/Review/submitter/ +reviewer/policy lineage. There is no public/manual create API and no separate +authorization action. `needs_revision` and `reject` create none. Accept/reject +are terminal in v0.1; no adjudication or replacement-acceptance path exists. +Reviewer-quality sampling is a non-mutating audit and never delays or changes +this record. + ## ContributionRecord Fields: @@ -1464,6 +1495,7 @@ Fields: - `contributor_id` - `source_review_id` - `source_review_lease_id` +- `source_final_acceptance_id` - `source_task_assignment_id` - `artifact_hash` - `contribution_policy_version_id` @@ -1472,11 +1504,20 @@ Fields: Purpose: The record is immutable. Every valid recorded human Review creates one reviewer -`completed_review` contribution. `accept` additionally creates one submitter -`accepted_submission`; `needs_revision` and `reject` do not. The record carries -the exact Review, submission, assignment or lease, frozen contribution policy, -and stabilized artifact-hash lineage. Compensation awards and reputation events -may reference it, but do not replace it. +`completed_review` contribution with direct Review and ReviewLease lineage. +`Review(accept)` creates FinalAcceptance; exactly one submitter +`accepted_submission` consumes that fact plus the exact TaskAssignment. +`needs_revision` and `reject` create no FinalAcceptance or submitter record. + +Reviewer rows require `source_review_id` and `source_review_lease_id` and have +null FinalAcceptance/assignment sources. Submitter rows require +`source_final_acceptance_id` and `source_task_assignment_id` and have null +direct Review/lease sources. Partial unique constraints enforce one +`completed_review` per Review and one `accepted_submission` per +FinalAcceptance; database checks reject mixed or incomplete source shapes. The +record carries the exact Submission, actor, frozen contribution policy, and +stabilized artifact-hash lineage. Compensation awards and reputation events may +reference it, but do not replace it. ## CompensationAward @@ -1563,8 +1604,12 @@ Event types: - revision_closed - contribution_recorded - compensation_fulfilled -- review_overturned -- review_confirmed +- review_quality_audit_completed +- review_quality_issue_flagged + +Reviewer-quality events are non-mutating observations. They cannot reopen or +replace Review, FinalAcceptance, task, contribution, or award truth and are not +adjudication decisions. ## AuditEvent @@ -1618,12 +1663,18 @@ open an independent session. registered scoped permission and cannot bypass missing task policy context - a submission must belong to a task - a review must belong to a submission -- an accepted task must have at least one accepted submission +- an accepted task must have exactly one immutable FinalAcceptance bound to its + accepted Submission and source Review - every valid recorded human review must create one reviewer `completed_review` contribution -- an accepted task must additionally create one submitter - `accepted_submission` contribution -- `needs_revision` and `reject` must not create a submitter contribution +- every FinalAcceptance must create one submitter `accepted_submission` + contribution in the same transaction +- `needs_revision` and `reject` must not create FinalAcceptance or a submitter + contribution +- FinalAcceptance is unique per task, source Review, and Submission and has no + independent creation API/action +- v0.1 has no adjudication state/action/queue/lease/decision/contribution or + readiness dependency - no compensation award exists without its contribution record - a fulfilled award must have an immutable fulfillment receipt with the exact authorized quantity and external reference diff --git a/docs/architecture_lifecycle_state_machine.md b/docs/architecture_lifecycle_state_machine.md index 07748011..9d25491f 100644 --- a/docs/architecture_lifecycle_state_machine.md +++ b/docs/architecture_lifecycle_state_machine.md @@ -156,6 +156,8 @@ Required before entering: - from `REVIEW_PENDING`: review decision id, at least one structured review finding, reviewer `completed_review` contribution, and any applicable reviewer award +- from `REVIEW_PENDING`: the same TaskAssignment remains `active`, with no + FinalAcceptance or submitter contribution Before the contributor resumes, Workstream prepares the next revision context. That preparation checks whether the active project guide or policy context changed since the prior submission was locked. Revision policy decides whether the next attempt keeps the prior context, rebases to the current active context, or is blocked for project-manager repair. @@ -168,6 +170,9 @@ The submission is accepted. Required before entering: - accepted review decision +- one immutable FinalAcceptance bound to the accepted Review, existing + versioned Submission, task, submitter, recording reviewer, and locked + ReviewPolicy - no unresolved blocking checker failure under the locked post-submit checker policy - evidence present - reviewer cited evidence supporting acceptance @@ -178,8 +183,9 @@ Required before entering: Required side effects: - reviewer `completed_review` contribution created with the Review -- submitter `accepted_submission` contribution created from the accepted - submission, accepting Review, frozen policy lineage, and artifact hash +- submitter `accepted_submission` contribution created from FinalAcceptance, + the exact TaskAssignment, frozen policy lineage, and artifact hash; it is not + inferred directly from Review.decision - applicable awards created independently from the reviewer and submitter contribution records - reputation events reference the applicable contribution record @@ -191,9 +197,15 @@ The task or submission is rejected. Required before entering: - rejection review decision -- rejection reason +- bounded human rejection reason - reviewer `completed_review` contribution and any applicable reviewer award +Required side effects: + +- same-task TaskAssignment is `blocked` and bound to the source reject Review +- no other task, assignment, or actor grant changes +- no FinalAcceptance or submitter `accepted_submission` exists + ### CANCELLED The task is cancelled before acceptance. @@ -228,6 +240,7 @@ No administrative or recovery grant authorizes these transitions: - `SUBMITTED -> REVIEW_PENDING` without checker run - `REVIEW_PENDING -> ACCEPTED` without review decision +- `REVIEW_PENDING -> ACCEPTED` without exactly one FinalAcceptance - `REVIEW_PENDING -> ACCEPTED` without contribution record creation - `NEEDS_REVISION -> ACCEPTED` without new submission or explicit finding closure - `SUBMITTED -> ACCEPTED` directly @@ -236,6 +249,7 @@ No administrative or recovery grant authorizes these transitions: - compensation projection `pending -> fulfilled` without an immutable payable award and fulfillment receipt - compensation exposure without a contribution record and frozen policy +- adjudication, appeal, acceptance replacement, or reopen transition in v0.1 - fulfillment without an external reference ## Submission Versioning diff --git a/docs/architecture_lockdown.md b/docs/architecture_lockdown.md index ebe0a384..d1e7bfd2 100644 --- a/docs/architecture_lockdown.md +++ b/docs/architecture_lockdown.md @@ -59,6 +59,10 @@ local ActorProfile/ActorIdentityLink records, administrative grants, exact-project submitter/reviewer/adjudicator grants, registered permissions, resource and lifecycle guards, revocation, and append-only authority evidence. +The global role catalogue does not define the v0.1 review lifecycle. Shipping +uses submitter and reviewer authority only; no adjudication policy, action, +queue, lease, state, decision, contribution, or readiness dependency exists. + Token roles and typed workflow profiles are not product authority. All public routes remain under `/api/v1`. ADR 0012 and the canonical authorization service specification control authorization wording in this lockdown. @@ -181,15 +185,23 @@ separate deferred adapter initiatives and are not v0.1 runtime dependencies. Every valid recorded human Review creates an immutable reviewer `completed_review` contribution record, regardless of whether the decision is -`accept`, `needs_revision`, or `reject`. An `accept` decision additionally -creates one submitter `accepted_submission` contribution record. Automated -checker outcomes create neither type. +`accept`, `needs_revision`, or `reject`. REV creates one immutable +FinalAcceptance only for `accept`; that fact, not direct inspection of +`Review.decision`, sources one submitter `accepted_submission` contribution +record. `needs_revision`, `reject`, and automated checker outcomes create no +FinalAcceptance or submitter contribution. Contribution records are separate from compensation status. Each record freezes its exact review, submission, actor, policy, and artifact-hash lineage. Compensation awards and reputation events may attach to a contribution record, but do not replace it. +FinalAcceptance is internal and REV-owned. It has no independent API/action, +uses canonical `Submission.id` because each Submission row is already a +version, and is unique per task, source Review, and Submission. V0.1 contains +no adjudication policy, action, queue, lease, state, decision, contribution +type, branch, readiness check, or adjudication-initiative dependency. + ## Deferred These ideas remain architecture-compatible, but they are not part of the first build: diff --git a/docs/architecture_system_architecture.md b/docs/architecture_system_architecture.md index 9000c393..8c5140f2 100644 --- a/docs/architecture_system_architecture.md +++ b/docs/architecture_system_architecture.md @@ -184,7 +184,7 @@ Owns: - review queue - findings - review decisions -- second-review flags +- non-mutating post-decision reviewer-quality audit selections and observations - reviewer audit history ### Revision Service diff --git a/docs/current_system_data_flow.html b/docs/current_system_data_flow.html index c7553659..31aebca6 100644 --- a/docs/current_system_data_flow.html +++ b/docs/current_system_data_flow.html @@ -483,7 +483,7 @@

Project guide and policy are prepared

3

Guide activation locks contract

-

Activation validates a passing or acknowledged sufficiency report, immutable guide source snapshot, approved submission artifact policy, effective project submission artifact policy hash, project pre-submit checker compiled bundle hash, approved generated project post-submit checker policy with matching guide, source snapshot, effective project policy, and pre-submit checker provenance, review policy allowed decisions, and revision states. Task readiness later validates that the task locks the applicable guide snapshot, effective project submission artifact policy hash, pre-submit checker bundle hash, and approved provenance-matched project post-submit checker policy reference. Publication of a ContributionPolicyVersion is independent of guide activation.

+

Activation validates a passing or acknowledged sufficiency report, immutable guide source snapshot, approved submission artifact policy, effective project submission artifact policy hash, project pre-submit checker compiled bundle hash, approved generated project post-submit checker policy with matching guide, source snapshot, effective project policy, and pre-submit checker provenance, review policy allowed decisions, and revision states. Task readiness later validates that the task locks the applicable guide snapshot, effective project submission artifact policy hash, pre-submit checker bundle hash, and approved provenance-matched project post-submit checker policy reference. Contribution-policy publication is outside this current-backend walkthrough and remains independent of guide activation.

status=active one active guide diff --git a/docs/glossary.md b/docs/glossary.md index bba3c7db..28d0625e 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -144,9 +144,9 @@ through separate active grants. The umbrella human product term for a person participating in Workstream. A contributor may have exact-project `submitter`, `reviewer`, and `adjudicator` grants as independent records. The adjudicator grant creates no adjudication -capability until WS-REV defines the lifecycle and AUTH activates exact -adjudication actions. Celery, checker, setup, and background workers are -internal services, not human product roles. +capability in v0.1 and creates no review-lifecycle or release dependency. +Celery, checker, setup, and background workers are internal services, not +human product roles. ## Source @@ -312,10 +312,22 @@ The outcome-based record of contributor and reviewer performance. The immutable, evidence-backed record of one completed contribution under locked project context. `completed_review` is created for every valid recorded human -Review; `accepted_submission` is created for the submitter only on `accept`. +Review and binds directly to that Review and ReviewLease. +`accepted_submission` is created only from FinalAcceptance and the exact +TaskAssignment; it is never inferred directly from `Review.decision`. Compensation and reputation records may attach to either contribution type, but do not replace the contribution record. +## Final Acceptance + +The immutable REV-owned internal fact created only as a lifecycle consequence +of `Review(accept)`. It binds one project, task, existing versioned Submission, +source Review, accepted submitter, recording reviewer, acceptance time, and +locked ReviewPolicy. There is no public/manual create API or separate +authorization action. `needs_revision` and `reject` create none. In v0.1 it is +unique per task, source Review, and Submission and is the sole source of an +`accepted_submission` ContributionRecord. + ## Human Owner The person accountable for a submitted packet, even when agents or external tools helped produce the work. diff --git a/docs/operations_operator_workflow.md b/docs/operations_operator_workflow.md index 854efb57..2ab5f263 100644 --- a/docs/operations_operator_workflow.md +++ b/docs/operations_operator_workflow.md @@ -93,23 +93,36 @@ Reads authorized immutable and operational evidence without mutation. ## Acceptance Workflow 1. Reviewer accepts submission. -2. Task moves to ACCEPTED. -3. Workstream records reviewer `completed_review` and submitter - `accepted_submission` contributions. -4. Frozen contribution policies create awards only for payable contributions; +2. REV records the immutable Review and one internal FinalAcceptance for the + exact task, Submission, submitter, reviewer, and locked ReviewPolicy. +3. Task moves to ACCEPTED and the TaskAssignment completes. +4. Workstream records reviewer `completed_review` directly from Review and + submitter `accepted_submission` only from FinalAcceptance. +5. Frozen contribution policies create awards only for payable contributions; explicit unpaid rules create none. -5. Reputation events are recorded from contribution facts. -6. Finance Authority follows delivery and fulfillment only for created awards. +6. Reputation events are recorded from contribution facts. +7. Finance Authority follows delivery and fulfillment only for created awards. + +The Review request owns one commit for Review, FinalAcceptance, task effects, +contributions, awards, audit, and outbox. There is no manual FinalAcceptance +command and no adjudication/reopen step in v0.1. ## Rejection Workflow 1. Reviewer rejects submission or task. -2. Review must include rejection reason. -3. Reputation event is recorded. -4. The frozen reviewer contribution award rule determines whether the resulting +2. Review must include a bounded human rejection reason. +3. REV sets the Task to canonical `rejected`, blocks only the same-task + TaskAssignment, and binds that block to the reject Review. It changes no + actor grant or unrelated task. +4. Reputation event is recorded. +5. The frozen reviewer contribution award rule determines whether the resulting `completed_review` contribution creates a `CompensationAward`; rejection creates no submitter `accepted_submission` contribution. +For `needs_revision`, REV instead sets the Task to `needs_revision`, keeps the +same TaskAssignment `active`, and creates no FinalAcceptance or submitter +contribution. `closed/review_rejected` is not a canonical task state. + ## Lessons Learned Every project maintains lessons learned: diff --git a/docs/operations_payment_reputation.md b/docs/operations_payment_reputation.md index c47c45fe..6e24d1e3 100644 --- a/docs/operations_payment_reputation.md +++ b/docs/operations_payment_reputation.md @@ -7,7 +7,8 @@ the authorized award and immutable fulfillment result with the same discipline as automated settlement. Every valid recorded human Review creates a reviewer `completed_review` -contribution. `accept` additionally creates a submitter `accepted_submission` +contribution. `Review(accept)` first creates REV-owned FinalAcceptance; that +immutable fact is the sole source of a submitter `accepted_submission` contribution. Compensation is evaluated independently for each record from its frozen policy version; an explicit unpaid rule creates no award. Awards, fulfillment receipts, projections, and reputation events attach to contributions @@ -53,17 +54,19 @@ Default: - a valid human `needs_revision`, `accept`, or `reject` decision creates one reviewer `completed_review`; the ReviewLease-frozen `ContributionPolicyVersion` decides whether it creates an award -- `accept` additionally creates one submitter `accepted_submission`; the - TaskAssignment-frozen `ContributionPolicyVersion` decides whether it creates - an award -- `needs_revision` and `reject` create no submitter contribution or award +- `accept` creates one FinalAcceptance and exactly one submitter + `accepted_submission` from it; the TaskAssignment-frozen + `ContributionPolicyVersion` decides whether it creates an award +- `needs_revision` and `reject` create no FinalAcceptance, submitter + contribution, or submitter award - fulfillment is recorded only by an authenticated adapter callback bound to the award's frozen adapter binding - a fulfilled award requires an immutable receipt, exact quantity, and external reference -Review decisions, task acceptance, award creation, and fulfillment remain -separate facts. +Review decisions, FinalAcceptance, contribution recognition, award creation, +and fulfillment remain separate facts. FinalAcceptance has no manual API/action +and v0.1 has no adjudication or reopen path. `ACCEPTED` means the work met the guide. `fulfilled` means the bound adapter reported completion with an immutable receipt and external reference. @@ -120,10 +123,10 @@ Track: - completed reviews - decision distribution -- overturned decisions +- non-mutating quality-audit findings - unclear feedback reports - average turnaround -- second-review agreement +- quality-audit agreement Suggested v0.1 reviewer events: @@ -131,10 +134,14 @@ Suggested v0.1 reviewer events: | --- | ---: | --- | | clear_review | +2 | Structured findings or clear acceptance evidence. | | unclear_feedback | -2 | Finding lacks issue, evidence, or required fix. | -| overturned_accept | -3 | Accepted work later found non-compliant. | -| overturned_reject | -3 | Rejected work that belonged in accepted or needs-revision state. | +| review_quality_audit_completed | 0 | Records that the decision evidence was independently sampled. | +| review_quality_issue_flagged | -3 | Non-mutating audit found unsupported decision reasoning. | | missed_prior_finding | -2 | Resubmission accepted with unresolved prior issue. | +Quality-audit events may affect reputation only. They do not reopen Review, +replace FinalAcceptance, mutate task status or contributions, or create an +adjudication decision. + ## Skill Tags Reputation is tagged by skill so a contributor can be strong in one domain and weak in another. diff --git a/docs/operations_queue_policy.md b/docs/operations_queue_policy.md index e1738f0c..bfc0dd95 100644 --- a/docs/operations_queue_policy.md +++ b/docs/operations_queue_policy.md @@ -177,8 +177,9 @@ Owner: Policy: -- the accepting Review creates reviewer `completed_review` and submitter - `accepted_submission` contribution records atomically +- the accepting Review creates reviewer `completed_review`, REV-owned + FinalAcceptance, and FinalAcceptance-sourced submitter `accepted_submission` + contribution records atomically - each frozen contribution policy is evaluated independently; only payable contributions create awards and fulfillment follow-up - accepted task is not confused with fulfilled compensation @@ -195,6 +196,10 @@ Owner: Policy: - rejection requires evidence and guide-grounded reason +- the Task enters canonical `rejected`; only its same-task TaskAssignment is + blocked and bound to the reject Review +- no FinalAcceptance or submitter contribution is created; no actor grant or + unrelated task changes ### Compensation Fulfillment Follow-Up @@ -234,9 +239,9 @@ Every operating day starts with: | `SUBMITTED -> EVALUATION_PENDING` | immutable submission version, locked post-submit checker policy id/version/hash/body copied from the task context | | `EVALUATION_PENDING -> REVIEW_PENDING` | checker run for exact submission version, readiness certificate, no blocking failures | | `EVALUATION_PENDING -> NEEDS_REVISION` | checker run id, outcome source `auto_checker`, contributor-visible checker failures with severity, message, suggested fix | -| `REVIEW_PENDING -> NEEDS_REVISION` | review decision, at least one structured finding, reviewer `completed_review` contribution and applicable reviewer award, revision policy still permits revision | -| `REVIEW_PENDING -> ACCEPTED` | accepted review, acceptance evidence refs, reviewer `completed_review` and submitter `accepted_submission` contributions, applicable awards | -| `REVIEW_PENDING -> REJECTED` | rejected review, rejection reason/finding, reviewer `completed_review` contribution and applicable reviewer award; no submitter contribution | +| `REVIEW_PENDING -> NEEDS_REVISION` | review decision, at least one structured finding, TaskAssignment remains `active`, reviewer `completed_review` contribution and applicable reviewer award, no FinalAcceptance or submitter contribution, revision policy still permits revision | +| `REVIEW_PENDING -> ACCEPTED` | accepted Review, one FinalAcceptance for the exact task/Review/Submission, acceptance evidence refs, reviewer `completed_review` and FinalAcceptance-sourced submitter `accepted_submission` contributions, applicable awards | +| `REVIEW_PENDING -> REJECTED` | rejected Review, bounded human reason/finding, only the same-task TaskAssignment blocked with its source Review, reviewer `completed_review` contribution and applicable reviewer award; no FinalAcceptance, submitter contribution, grant change, or unrelated task effect | | pre-submit feedback in `NEEDS_REVISION` | prior findings visible to contributor, revision deadline active, no new submission created | | `NEEDS_REVISION -> SUBMITTED` | replacement submission packet, revision replay covering every high and medium prior finding, revision count under policy limit | | compensation `pending -> fulfilled` | immutable fulfillment receipt, external reference, and audit event | diff --git a/docs/operations_reviewer_workflow.md b/docs/operations_reviewer_workflow.md index 9b66fc40..9617d522 100644 --- a/docs/operations_reviewer_workflow.md +++ b/docs/operations_reviewer_workflow.md @@ -31,9 +31,11 @@ Allowed decisions: Decision rules: -- `accept` means the submission satisfies the project guide and creates the - submitter `accepted_submission` contribution. Its frozen contribution award rule - independently decides whether that contribution creates an award. +- `accept` means the submission satisfies the project guide. The same + transaction creates internal FinalAcceptance, then creates the submitter + `accepted_submission` contribution only from that fact. Its frozen + contribution award rule independently decides whether that contribution + creates an award. - `needs_revision` means the work is fixable and the reviewer can name concrete required changes. - `reject` means the work is not reasonably salvageable or violates policy. @@ -79,9 +81,13 @@ Use accept only when: Accept must create: - review decision record +- one immutable internal FinalAcceptance linked to the exact Review, existing + versioned Submission, task, submitter, recording reviewer, and locked + ReviewPolicy - acceptance audit event - reviewer `completed_review` contribution record -- submitter `accepted_submission` contribution record +- submitter `accepted_submission` contribution record sourced from + FinalAcceptance, not directly from Review.decision - any awards required by the separately frozen reviewer and submitter contribution policies - reputation event @@ -107,6 +113,10 @@ Each high or medium finding must have: - required fix - evidence reference or file/section reference +Recording `needs_revision` sets the Task to `needs_revision`, keeps the same +TaskAssignment `active`, and creates no FinalAcceptance or submitter +contribution. The reviewer `completed_review` still commits atomically. + ## Reject Use reject when: @@ -118,6 +128,11 @@ Use reject when: Use reject carefully. If the work can be reasonably corrected through one revision cycle, use `needs_revision`. +Recording `reject` sets the Task to canonical `rejected` with the bounded human +reason and blocks only the same-task TaskAssignment with its source Review. It +changes no actor grant or unrelated task and creates no FinalAcceptance or +submitter contribution. `closed/review_rejected` is not a canonical state. + Every valid recorded `needs_revision` or `reject` decision still creates the reviewer's `completed_review` contribution and evaluates the ReviewLease-frozen reviewer contribution policy. Neither decision creates a submitter contribution @@ -129,21 +144,22 @@ Track: - review count - decision distribution -- overturned decisions +- non-mutating quality-audit findings - unclear feedback reports - average turnaround -- agreement with second reviewer +- quality-audit agreement Reviewer reputation matters because low-quality review damages the whole system. Reviewer quality events are generated when: -- review is overturned - feedback is marked unclear -- reviewer accepts work later found non-compliant -- reviewer rejects work that belonged in revision +- a non-mutating quality audit finds unsupported acceptance/rejection reasoning - reviewer misses unresolved prior findings +These quality signals never reopen or replace Review, FinalAcceptance, task, or +ContributionRecord truth. V0.1 has no adjudication decision or queue. + ## Reviewer Checklist Before accepting: @@ -153,6 +169,8 @@ Before accepting: - evidence supports the claim - checker results are acceptable - no prior findings are open +- FinalAcceptance can be created exactly once for this task, source Review, and + existing versioned Submission - reviewer and submitter contribution lineage can be created atomically - both frozen contribution policies can be evaluated; explicit unpaid results are valid and create no award @@ -170,13 +188,15 @@ Before rejection: - evidence is cited - task is not merely fixable -## Second Review Sampling +## Non-Mutating Quality Sampling -During the first 30 days, sample at least: +During the first 30 days, audit at least: - 25 percent of accepted submissions - 25 percent of rejected submissions - any submission matching the configured high-value criterion in `ReviewPolicy` -Second review checks whether the first reviewer followed the guide, cited evidence, and made the correct decision type. +Sampling checks whether the reviewer followed the guide and cited evidence. It +does not create a Review, adjudication result, reopen path, replacement +FinalAcceptance, or lifecycle mutation. diff --git a/docs/product_first_user_flows.md b/docs/product_first_user_flows.md index e3ce7f4e..71e459b6 100644 --- a/docs/product_first_user_flows.md +++ b/docs/product_first_user_flows.md @@ -121,8 +121,8 @@ Acceptance: 4. Reviewer enters structured findings. 5. Reviewer selects accept, needs_revision, or reject. 6. Workstream atomically creates the reviewer `completed_review` contribution; - `accept` additionally creates the submitter `accepted_submission` - contribution. + `accept` also creates internal FinalAcceptance and then the submitter + `accepted_submission` contribution from that fact. Acceptance: @@ -130,6 +130,14 @@ Acceptance: - needs_revision and reject require at least one finding. - accept requires no unresolved critical- or high-severity checker failure. - Every valid human decision has exactly one reviewer contribution. +- Accept sets Task `accepted`, Assignment `completed`, and has exactly one + FinalAcceptance and one submitter contribution. +- Needs revision sets Task `needs_revision`, keeps Assignment `active`, and has + neither FinalAcceptance nor submitter contribution. +- Reject sets Task `rejected` with a bounded human reason, blocks only the + same-task Assignment with its source Review, changes no grant or unrelated + task, and has neither FinalAcceptance nor submitter contribution. +- FinalAcceptance has no manual API/action and no adjudication/reopen path. - Only accept has a submitter contribution. ## Flow 6: Revision Replay diff --git a/docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification(2).pdf b/docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification(2).pdf new file mode 100644 index 00000000..72fcf5ac Binary files /dev/null and b/docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification(2).pdf differ diff --git a/docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.md b/docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.md new file mode 100644 index 00000000..6078311c --- /dev/null +++ b/docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.md @@ -0,0 +1,3161 @@ +# WS-CON-001: Workstream Contribution Record and Compensation Boundary Specification + +**Status:** Reconciled design candidate; human approval required +**Architecture maturity:** Planned; not yet runtime-proven +**Version:** 0.1 +**Revision:** Authorization and contribution-evidence storage integration update +**Date:** 2026-07-15 +**Owner:** Flow Research / Workstream Engineering +**Scope:** Centralized contribution/compensation authorization, immutable contribution recognition, artifact-backed contribution evidence, project-scoped compensation policy, frozen compensation terms, compensation awards, transactional events, external fulfillment adapters, fulfillment receipts, and authorized contribution read views +**Depends on:** `WS-AUTH-001` ActorProfile and Authorization Service; approved AUTH ActionId/PermissionId catalogue; updated `WS-REV-001` review lifecycle; ART-owned typed contribution-evidence capabilities; immutable Review, Submission, TaskAssignment, and ReviewLease records; shared transactional outbox; and PostgreSQL transaction guarantees +**Current proof boundary:** The existing live API drill proves the intake spine through review_pending. WS-REV-001 and this reconciled candidate are not yet runtime-proven +**Precedes:** Reputation scoring policy, provider-specific payment integration, project-points ledger implementation, credits, adjudication, and lessons learned + +--- + +## 1. Purpose + +This specification defines how Workstream recognizes completed contributor work after a valid human review decision. + +It establishes: + +- when a submitter has produced a recognized contribution; +- when a reviewer has produced a recognized contribution; +- which exact Authorization Service permissions and resource contexts protect contribution, policy, award, adapter-binding, reconciliation, and callback operations; +- how contribution recognition remains independent of the review outcome; +- how a global contribution history remains filterable by project; +- how project compensation terms are versioned and frozen before work begins; +- how money and project-points awards are derived deterministically; +- how Workstream hands fulfillment to external adapters; +- how adapter acknowledgements differ from fulfillment results; +- how Workstream records fulfillment results without mutating contribution history; +- how Workstream creates a deterministic immutable evidence bundle for each contribution without duplicating artifact bytes or making Artifact Storage canonical; +- how authorized readers retrieve contribution evidence through Workstream ArtifactBinding references; +- how duplicate events, callbacks, retries, failures, and races are handled; +- which responsibilities stop at the Workstream boundary. + +The fundamental model is: + +~~~text +Valid Review recorded + | + +--> Reviewer ContributionRecord + | +--> ContributionRecorded + | +--> zero or more CompensationAwards + | + +--> if decision = accept: + Submitter ContributionRecord + +--> ContributionRecorded + +--> zero or more CompensationAwards + +Each CompensationAward + | + +--> CompensationFulfillmentRequested + | + +--> external money or project-points adapter + | + +--> CompensationFulfillmentReported + | + +--> immutable fulfillment receipt + +--> mutable status projection +~~~ + +Workstream records the fact that work was performed and the exact project-scoped compensation authorized for it. Workstream does not implement payment-provider transactions, point balances, or provider ledgers. + +--- + +## 2. Implementation Status and Proof Boundary + +The coding agent MUST preserve the difference between proven behaviour, locked design, and deferred work. + +| Lifecycle area | Status | +|---|---| +| Project guide, submission policy, task lock, submission finalization, and durable checker run | Proven | +| Transition through review_pending | Proven | +| Reviewer routing, leases, immutable decisions, and revision chain | Locked by WS-REV-001; not yet runtime-proven | +| ActorProfile and centralized Authorization Service contract | Locked by WS-AUTH-001; implementation proof required before protected WS-CON APIs | +| Reviewer Contribution Record for every completed Review | Locked by this specification | +| Submitter Contribution Record after accept | Locked by this specification | +| Project CompensationPolicy and immutable versions | Locked by this specification | +| Money and project-points CompensationAwards | Locked by this specification | +| External fulfillment event and callback boundary | Locked by this specification | +| Contribution evidence-bundle projection and retention | Locked by this revision; not yet runtime-proven | +| Provider payment requests, attempts, settlement, balances, and reconciliation | External and deferred | +| Project-points ledger and balances | External and deferred | +| Reputation scoring formula and aggregate | Deferred | +| Adjudication and contribution adjustment | Deferred | + +### 2.1 Starting preconditions + +This specification begins when WS-REV-001 is recording a valid Review against an active ReviewLease. + +The Review decision may be: + +- accept; +- needs_revision; +- reject. + +No Contribution Record may be created for: + +- an automated checker result; +- a pending or merely claimed review; +- an expired lease; +- a manually released lease; +- an administratively revoked lease; +- an invalid or rolled-back Review transaction. + +### 2.2 Narrow precedence over WS-REV-001 + +WS-REV-001 section 12.1 uses ContributionRecordRequested as a temporary integration event because contribution creation was deferred to the next specification. + +After WS-CON-001 is implemented, the following rules supersede only that temporary seam: + +1. Every valid Review transaction creates the reviewer Contribution Record directly. +2. An accept Review transaction additionally creates the submitter Contribution Record directly. +3. Those records, their CompensationAwards, and their outbox events are committed atomically with the Review. +4. ContributionRecordRequested MUST NOT be emitted by the completed implementation. +5. ContributionRecorded and CompensationFulfillmentRequested are the canonical downstream events. + +All other WS-REV-001 authority, routing, lease, revision, reject, and immutability rules remain unchanged. + +For authorization identifiers only, merged `WS-AUTH-001` is authoritative. +`review.decision`, `artifact.verification_job.retry`, and +`artifact.verification.execute` are canonical. `outbox.dispatch` and the +WS-CON actions in section 5.4 remain proposed until AUTH registers them; this +reference cannot make an identifier executable by naming it. + +--- + +## 3. Normative Language + +The terms MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY are normative. + +- MUST or REQUIRED means the implementation is non-conformant if the rule is absent. +- MUST NOT means the behaviour is prohibited. +- SHOULD means deviation requires an explicit Architecture Decision Record. +- MAY means the implementation choice is allowed without changing domain behaviour. + +Database time is authoritative for all transaction timestamps. Decimal quantities MUST never be represented or calculated using binary floating-point types. + +**Version notation:** Workstream and this lifecycle specification are release v0.1. The `/api/v1` API prefix, `event_version: 1`, event idempotency suffix `:v1`, route-key suffix `-v1`, and references such as `Submission(v1)` are independent API, event-schema, route, or submission-version identifiers. None denotes a Workstream v1.0 release. + +--- + +## 4. Locked v0.1 Decisions + +The following decisions are not left to coding-agent interpretation. + +1. Contribution Records are globally addressable in Workstream and always carry a mandatory project_id. +2. Global contribution history can be filtered by project, contributor, task, contribution type, and time. +3. A valid completed Review always creates exactly one reviewer Contribution Record, regardless of accept, needs_revision, or reject. +4. An accept Review additionally creates exactly one submitter Contribution Record. +5. Needs-revision and reject Reviews do not create submitter Contribution Records. +6. Every completed revision-review round is an independently recognized reviewer contribution. +7. Expired, released, and revoked review leases create no contribution and no compensation. +8. Contribution Records are immutable and have no mutable fulfillment fields. +9. Review, contribution, award, and outbox creation occur in one database transaction. +10. Every project MUST bind an active published CompensationPolicyVersion before new TaskAssignments or ReviewLeases can be created. +11. Unpaid work uses an explicit policy rule with no awards; missing policy configuration is never treated as unpaid. +12. V0.1 compensation is fixed per project and contribution type. +13. V0.1 has no contributor-specific rates, manually negotiated rates, compensation tiers, or task-specific overrides. +14. Submitter compensation terms are frozen on TaskAssignment creation. +15. Reviewer compensation terms are frozen on successful ReviewLease creation. +16. A later project-policy change never alters an existing TaskAssignment, ReviewLease, Contribution Record, or CompensationAward. +17. V0.1 supports only money and project_points compensation instruments. +18. Monetary awards are project obligations even when their unit is a standard currency. +19. Project points belong to a project-specific namespace and are not global Workstream points. +20. A contribution may create no award, one award, or two awards: at most one money award and at most one project-points award. +21. Workstream creates immutable CompensationAwards and emits fulfillment events. +22. External adapters own payment requests, provider attempts, finance approval, point ledgers, balances, provider retries, and provider reconciliation. +23. Workstream retries event delivery only until the external adapter acknowledges receipt. +24. Adapter delivery acknowledgement is not proof of compensation fulfillment. +25. Fulfillment is reported later through an authenticated, idempotent callback. +26. V0.1 fulfillment outcomes are fulfilled or failed; partial fulfillment is prohibited. +27. A failed award may later receive a valid fulfilled receipt. +28. A fulfilled award is terminal and cannot later become failed. +29. Fulfillment responses create immutable receipts and update a derived status projection; they never mutate the Contribution Record or CompensationAward. +30. Reputation consumes ContributionRecorded independently of compensation fulfillment. +31. Reputation scoring formulas and reputation aggregates are not implemented by this specification. +32. Acceptance is final in v0.1; no adjudication or adjustment lifecycle exists. +33. All provider-specific and ledger-specific objects remain outside Workstream. +34. `WS-AUTH-001` is the sole authority for ActorProfile resolution, AdminRoleGrant evaluation, contributor self-read authority, project scope, service-actor status, and authorization decisions. +35. Finance Authority is the only human Admin role that creates, edits, publishes, retires, or activates compensation policy and manages compensation adapter bindings in v0.1. +36. A reason-bound Operator may request authorized compensation delivery +reconciliation but cannot execute provider delivery, publish policy, alter +awards, or mark fulfillment complete. +37. An external fulfillment adapter reports results only through an active service ActorProfile and the exact frozen ProjectCompensationAdapterBinding for the referenced award. +38. Workstream owns ContributionRecord, CompensationAward, fulfillment receipt, projection, and lifecycle meaning. Artifact Storage owns contribution-evidence bundle bytes, content identity, verification, generic bindings, receipts, retention, and recovery. +39. Every ContributionRecord produces one asynchronous, deterministic contribution-evidence projection request after the canonical Review/contribution transaction commits. +40. Artifact projection failure never rolls back or mutates a committed Review, ContributionRecord, CompensationAward, or fulfillment receipt. +41. Human Identity Issuer tokens are never forwarded to Artifact Storage or compensation adapters. Workstream uses separately authorized service identities and least-privilege scopes. +42. Public contribution evidence references use Workstream ArtifactBinding IDs. Raw provider CIDs, arbitrary URLs, filesystem paths, credentials, and provider tokens are not public authority. + +--- + +## 5. Actor and Authority Model + +### 5.1 Relevant actors + +~~~text +Workstream Actor +├── Admin +│ ├── Access Administrator +│ ├── Operator +│ ├── Project Manager +│ ├── Finance Authority +│ └── Audit Authority +│ +├── Contributor +│ ├── Submitter +│ ├── Reviewer +│ └── Both +│ +└── External Service Actor + ├── Money Fulfillment Adapter + └── Project Points Fulfillment Adapter +~~~ + +External adapters are service actors. They are not Admins or Contributors and receive no authority over Reviews, tasks, assignments, policies, or Contribution Records. + +These are authority domains, not separate human profiles. One Identity Issuer subject resolves to one Workstream ActorProfile. An ActorProfile may hold AdminRoleGrants and project contributor grants independently; neither implies the other. + +### 5.2 Normative relationship to WS-AUTH-001 + +`WS-AUTH-001` is authoritative for: + +- Identity Issuer token verification; +- ActorProfile and ActorIdentityLink provisioning and state; +- AdminRoleGrant and ProjectRoleGrant evaluation; +- registered permission identifiers; +- system, project and record scope; +- service ActorProfile provisioning; +- authorization decisions, revocation and audit linkage. + +`WS-AUTH-001` is authoritative where it replaces broad preliminary permission names with the closed granular action/resource catalogue. This document consumes those exact identifiers and introduces no compatibility alias. + +This specification is authoritative for: + +- compensation policy and adapter-binding lifecycle guards; +- contribution and award creation invariants; +- frozen compensation terms; +- adapter-binding ownership of fulfillment callbacks; +- immutable receipt and projection behavior; +- contribution-evidence ArtifactBinding and projection guards. + +Every protected request first obtains an AuthorizationDecision. An allowed decision permits an attempt; WS-CON domain services still enforce policy state, frozen references, ownership, adapter binding, award state, artifact visibility and transaction invariants. + +### 5.3 Identity boundary + +All human and service requests pass through the Identity Issuer boundary. + +~~~text +Identity Issuer token + -> TokenVerifier verifies issuer, subject, audience, expiry and coarse scopes + -> AuthorizationService resolves current ActorProfile and identity link + -> Workstream loads the canonical policy, contribution, award, binding or receipt resource chain + -> AuthorizationService evaluates the registered permission and canonical scope + -> WS-CON service applies compensation, ownership and state guards + -> operation proceeds only when every layer allows it +~~~ + +A valid service token is insufficient by itself. The service actor must also match the adapter binding frozen on the referenced CompensationAward. + +The human or service token is consumed at the Workstream boundary. It is never forwarded to Artifact Storage or from Workstream to an external fulfillment provider. + +### 5.4 Required ActionId to PermissionId mapping + +The public boundary is the request-scoped +`AuthorizationService.require(action_id, typed_resource_context)`. The service +already owns the current AuthorizationContext and caller-owned AsyncSession. +WS-CON never passes a raw PermissionId, role, grant, session, or unit of work. + +| ActionId | Canonical PermissionId | Activation owner | +|---|---|---| +| `contribution.read_self` | `contribution.read_self` | CON-09B; reused by CON-10A | +| `contribution.read_project` | `contribution.read_project` | CON-09B; reused by CON-10A | +| `compensation.policy.read` | `compensation.policy.manage` | CON-04B | +| `compensation.policy.create_draft` | `compensation.policy.manage` | CON-04B | +| `compensation.policy.update_draft` | `compensation.policy.manage` | CON-04B | +| `compensation.policy.publish` | `compensation.policy.manage` | CON-04B | +| `compensation.policy.retire` | `compensation.policy.manage` | CON-04B | +| `compensation.adapter_binding.read` | `compensation.adapter_binding.manage` | CON-04A | +| `compensation.adapter_binding.create` | `compensation.adapter_binding.manage` | CON-04A | +| `compensation.adapter_binding.suspend` | `compensation.adapter_binding.manage` | CON-04A | +| `compensation.adapter_binding.resume` | `compensation.adapter_binding.manage` | CON-04A | +| `compensation.adapter_binding.retire` | `compensation.adapter_binding.manage` | CON-10B | +| `compensation.award.read_self` | `contribution.read_self` | CON-10A | +| `compensation.award.read_project` | `compensation.award.read` | CON-10A | +| `compensation.delivery.reconcile` | `compensation.delivery.reconcile` | CON-10B | +| `compensation.status.read` | `operations.status.read` | CON-10B | +| `compensation.reconcile.run` | `operations.reconcile.run` | CON-10B | +| `contribution.projection.rebuild` | `operations.projection.rebuild` | CON-10B | +| `audit.read` | `audit.read` | CON-10B | +| `audit.export` | `audit.export` | CON-10B | +| `compensation.fulfillment.report` | new service-only `compensation.fulfillment.report` | CON-08B after AUTH registration | +| `outbox.dispatch` | new service-only `outbox.dispatch` | shared-outbox CON-02B prerequisite; consumed by CON-08A | +| `artifact.contribution_evidence.binding.create` | `artifact.binding.create` | named ART prerequisite; consumed by CON-09A | + +`compensation.fulfillment.report` is assigned only to the service ActorProfile +on the exact ProjectCompensationAdapterBinding frozen on an existing award. +`outbox.dispatch` is assigned only to the fixed shared-outbox dispatcher. Human +AdminRoleGrant, ProjectRoleGrant, Finance Authority, reconciliation, or +`operations.outbox.retry` authority cannot satisfy either action. + +ContributionRecord and CompensationAward writes are mandatory internal +participants in the already-authorized `review.decision` transaction. They +flush through its caller-owned session and never commit or require separate +materialization actions. Artifact reads and recovery use narrow ART-owned typed +capabilities; operators request verification recovery through the existing +`artifact.verification_job.retry` action, and ART owns execution. + +### 5.5 Human authority matrix + +| Action | Authorized human authority in v0.1 | +|---|---| +| Manage any compensation-policy lifecycle stage | Finance Authority within covered project scope | +| Manage money or project-points adapter binding | Finance Authority within covered project scope | +| Read own Contribution Records | Contributor owning the records | +| Read project Contribution Records | Project Manager, Finance Authority, Audit Authority, or operationally authorized Operator within covered scope | +| Read global cross-project contribution history | Contributor reading only their own history; Admin cross-project analysis uses separately authorized audit/operational projections, not a contribution-history bypass | +| Read monetary award and fulfillment detail | Finance Authority, Audit Authority, or operationally authorized Operator within covered scope | +| Request compensation integrity reconciliation | Reason-bound Operator within covered project/system scope; fixed shared-outbox dispatcher executes any async work | +| Request compensation delivery reconciliation | Finance Authority for covered project work or reason-bound system-scoped Operator; fixed shared-outbox dispatcher executes any requeued delivery | +| Request eligible artifact recovery | Covered Operator with `artifact.verification_job.retry`; fixed recovery actor executes | +| Create ContributionRecord or CompensationAward | No human authority; system transaction only | +| Report fulfillment | No human authority; bound service actor only | + +Project Manager may read project contribution history needed for project management but cannot create, publish, activate, retire or edit compensation policy and cannot manage adapter bindings solely by that role. Operator recovers delivery/runtime state but cannot change economic policy, award quantity, or fulfillment truth. + +### 5.6 Canonical resource contexts + +The authorization service receives canonical relationships loaded from Workstream records, never trusted from request paths or callback payload fields. + +| Resource | Canonical project resolution | Required guard attributes | +|---|---|---| +| CompensationPolicy/Version | stored project_id, cross-checked through owning policy and Project | status; version; current active reference; instruments | +| AdapterBinding | stored project_id | instrument; adapter_actor_id; status; reference usage | +| ContributionRecord | source Review -> Submission -> Task -> Project | contributor owner; type; source review; immutable state | +| CompensationAward | ContributionRecord -> Project and frozen policy/binding | contributor; instrument; binding; quantity; fulfilled state | +| FulfillmentReceipt | Award -> ContributionRecord -> Project | adapter binding; external event; current fulfilled receipt | +| Contribution ArtifactBinding | Binding owner -> ContributionRecord -> source Review/Task -> Project | artifact role; visibility; integrity/projection state | + +Any mismatch fails closed with `resource_project_mismatch` and produces an integrity alert. + +### 5.7 Authorization evaluation points + +Authorization MUST be evaluated: + +1. before returning contribution, award, policy, binding, receipt or evidence metadata; +2. inside policy publication/activation/retirement transactions; +3. inside adapter-binding mutation transactions; +4. inside delivery reconciliation mutations; +5. inside every fulfillment callback transaction after loading the award and binding; +6. again before any actor-attributed deferred job commits; +7. before every contribution-evidence retrieval. + +Routers MUST NOT query AdminRoleGrant tables, inspect role strings, infer project scope from request JSON, or reproduce callback-binding authorization. + +Every route and independently invocable asynchronous command declares exactly +one primary ActionId from `WS-AUTH-001`. Derived contribution and award writes +are mandatory internal participants of the originating `review.decision` +transaction; they are not separate commands or authorities. + +### 5.8 System-owned creation + +ContributionRecord, CompensationAward, their canonical outbox events and +evidence-projection requests are created inside the authorized Review decision +transaction using its caller-owned AsyncSession. Each participant flushes but +never commits, and the originating decision remains linked as causation. + +Background dispatch, projection and reconciliation workers use provisioned service ActorProfiles with explicit system permissions. They do not fabricate a Finance Authority, Operator or Contributor identity. + +No API permits an Admin, Contributor, or adapter to create or edit a Contribution Record directly. + +--- + +## 6. Core Object Model + +### 6.1 ContributionRecord + +ContributionRecord is the permanent recognition that one contributor completed one eligible unit of work. + +~~~yaml +ContributionRecord: + id: uuid + project_id: uuid + task_id: uuid + contributor_id: uuid + + contribution_type: enum [ + accepted_submission, + completed_review + ] + + source_review_id: uuid + source_review_lease_id: uuid | null + source_task_assignment_id: uuid + submission_id: uuid + + compensation_policy_version_id: uuid + + source_submission_artifact_digest: string + recorded_at: timestamp + recorded_by: system_actor_id + + correlation_id: string + causation_event_id: uuid | null +~~~ + +#### ContributionRecord invariants + +- The record is immutable from insertion. +- project_id, task_id, contributor_id, source Review, assignment, submission version, and compensation version MUST all belong to one internally consistent chain. +- contribution_type = accepted_submission requires Review.decision = accept. +- contribution_type = accepted_submission requires contributor_id to equal the submission creator and TaskAssignment contributor. +- contribution_type = completed_review requires contributor_id to equal Review.reviewer_id. +- contribution_type = completed_review requires source_review_lease_id to equal Review.review_lease_id. +- accepted_submission records reference the active submitter TaskAssignment completed by the accept Review. +- completed_review records reference the TaskAssignment whose work was reviewed but do not attribute that assignment to the reviewer. +- source_submission_artifact_digest equals the immutable digest locked to the reviewed Submission. For `completed_review`, it identifies the work judged; it is not misrepresented as the reviewer's own artifact. +- compensation_policy_version_id comes from the frozen TaskAssignment field for accepted_submission. +- compensation_policy_version_id comes from the frozen ReviewLease field for completed_review. +- Exactly one accepted_submission record may exist per accepted Review. +- Exactly one completed_review record may exist per Review. +- An accept Review therefore creates exactly two Contribution Records unless one of the contributors is represented by a prohibited self-review, which WS-REV-001 prevents. +- Needs-revision and reject Reviews create exactly one Contribution Record: completed_review. +- A record may exist even when its compensation policy produces no awards. +- The record has no payment_status, points_status, mutable status, deleted_at, or editable metadata. + +Recommended uniqueness constraints: + +~~~text +UNIQUE(source_review_id, contribution_type) +UNIQUE(id, project_id) +~~~ + +### 6.2 CompensationPolicy + +CompensationPolicy is the stable project-owned policy identity. + +~~~yaml +CompensationPolicy: + id: uuid + project_id: uuid + name: string + status: enum [draft, active, retired] + current_published_version_id: uuid | null + + created_by: actor_id + created_at: timestamp + retired_by: actor_id | null + retired_at: timestamp | null +~~~ + +One project may have multiple historical policy identities, but at most one CompensationPolicy and, when the project is configured for new work, exactly one published version are active at a time. A newly created policy remains draft with a null current_published_version_id until its first version is published. + +### 6.3 CompensationPolicyVersion + +~~~yaml +CompensationPolicyVersion: + id: uuid + compensation_policy_id: uuid + project_id: uuid + version_number: int + status: enum [draft, published, retired] + + created_by: actor_id + created_at: timestamp + published_by: actor_id | null + published_at: timestamp | null + retired_by: actor_id | null + retired_at: timestamp | null +~~~ + +#### Version invariants + +- version_number starts at 1 and increases monotonically within one CompensationPolicy. +- Draft versions may be edited only through explicit draft APIs. +- Publishing validates the complete version and makes every field and award definition immutable. +- A published version may be retired but never edited or deleted. +- Retiring a version does not invalidate frozen references from assignments or leases. +- A retired version remains valid for contribution and award creation when it was frozen before retirement. +- At most one published version is active for new work within a project. + +### 6.4 CompensationRule + +Every policy version contains exactly one rule for each contribution type. This makes unpaid work explicit rather than indistinguishable from missing configuration. + +~~~yaml +CompensationRule: + id: uuid + compensation_policy_version_id: uuid + project_id: uuid + contribution_type: enum [ + accepted_submission, + completed_review + ] + compensation_mode: enum [compensated, unpaid] +~~~ + +#### Rule invariants + +- Exactly one accepted_submission rule and one completed_review rule exist in every publishable version. +- A compensated rule has at least one and at most two award definitions. +- An unpaid rule has zero award definitions. +- Rule and definitions become immutable together when the version is published. +- V0.1 rules have no condition expression, priority, fallback, multiplier, or outcome selector. + +### 6.5 CompensationAwardDefinition + +Each published version defines fixed awards for the two contribution types. + +~~~yaml +CompensationAwardDefinition: + id: uuid + compensation_rule_id: uuid + compensation_policy_version_id: uuid + project_id: uuid + + contribution_type: enum [ + accepted_submission, + completed_review + ] + + instrument_type: enum [ + money, + project_points + ] + + unit_code: string + quantity: decimal + adapter_binding_id: uuid +~~~ + +#### Definition invariants + +- At most one definition exists for each contribution_type and instrument_type within a version. +- quantity MUST be greater than zero. +- Money unit_code MUST be an uppercase ISO 4217 currency code configured for the project. +- Project-points unit_code MUST match the project-scoped point unit configured by the policy. +- A points unit has identity (project_id, unit_code). The same text in another project is a different unit. +- adapter_binding_id must match the same project and instrument. +- Published definitions are immutable. +- An explicitly unpaid rule has zero award definitions. +- Zero-quantity award definitions are prohibited. +- V0.1 rule evaluation is exact matching on contribution_type only. No other condition, multiplier, tier, score, task class, contributor class, or outcome rule is allowed. + +### 6.6 Frozen compensation references + +WS-CON-001 extends Project and two existing work objects. + +~~~yaml +Project: + # existing fields omitted + active_compensation_policy_version_id: uuid | null +~~~ + +~~~yaml +TaskAssignment: + # existing fields omitted + submitter_compensation_policy_version_id: uuid +~~~ + +~~~yaml +ReviewLease: + # existing fields omitted + reviewer_compensation_policy_version_id: uuid +~~~ + +The references are set once: + +- TaskAssignment freezes the project active version in the assignment-creation transaction. +- ReviewLease freezes the project active version in the successful claim transaction. +- Neither field may be updated later. +- Policy retirement does not change either field. + +### 6.7 CompensationAward + +CompensationAward is Workstream's immutable statement of what the project authorized for one contribution. + +~~~yaml +CompensationAward: + id: uuid + project_id: uuid + contribution_record_id: uuid + contributor_id: uuid + + compensation_policy_version_id: uuid + award_definition_id: uuid + adapter_binding_id: uuid + + instrument_type: enum [ + money, + project_points + ] + + unit_code: string + quantity: decimal + + created_at: timestamp + correlation_id: string +~~~ + +#### CompensationAward invariants + +- Immutable from insertion. +- Project, contributor, policy version, and contribution must match. +- Instrument, unit, quantity, and adapter binding are copied exactly from the published definition. +- At most one award exists per contribution and instrument type. +- A completed_review award does not depend on Review.decision. +- No award may be created for a released, expired, or revoked lease. +- No award may be created by an adapter callback. +- Failed or fulfilled status is never stored on this record. + +Recommended uniqueness constraint: + +~~~text +UNIQUE(contribution_record_id, instrument_type) +~~~ + +### 6.8 ProjectCompensationAdapterBinding + +The binding identifies the logical adapter authorized for one project and instrument. + +~~~yaml +ProjectCompensationAdapterBinding: + id: uuid + project_id: uuid + instrument_type: enum [money, project_points] + adapter_actor_id: actor_id + route_key: string + status: enum [active, suspended, retired] + + created_by: actor_id + created_at: timestamp + suspended_at: timestamp | null + retired_at: timestamp | null +~~~ + +#### Binding invariants + +- At most one active binding exists per project and instrument. +- Published award definitions reference a binding for the same project and instrument. +- The binding identity is frozen into each CompensationAward. +- Endpoint, credentials, and provider configuration are deployment secrets and are not domain fields. +- Suspending a binding pauses new delivery but does not cancel or alter awards. +- Retiring a binding is prohibited while it is referenced by an active policy version, by unfinished work whose frozen policy version contains it, or by an unfulfilled award. +- A service actor bound to money cannot report project-points fulfillment and vice versa. + +### 6.9 CompensationFulfillmentReceipt + +Each valid callback creates an immutable receipt. + +~~~yaml +CompensationFulfillmentReceipt: + id: uuid + compensation_award_id: uuid + project_id: uuid + adapter_binding_id: uuid + + external_event_id: string + reported_status: enum [fulfilled, failed] + + fulfilled_quantity: decimal | null + fulfilled_at: timestamp | null + + failure_code: string | null + + reported_at: timestamp + received_at: timestamp + correlation_id: string +~~~ + +#### Receipt invariants + +- Immutable from insertion. +- external_event_id is an opaque idempotency token, 1-128 ASCII characters + from `[A-Za-z0-9._:-]`, globally unique per adapter binding, and never + returned by contributor/product reads or emitted in integration events. +- fulfilled requires fulfilled_quantity and fulfilled_at. +- fulfilled_quantity must equal the CompensationAward quantity exactly. +- failed requires failure_code. +- failure_code is a closed Workstream-mapped code or a 1-64 character ASCII + token from `[A-Z0-9_:-]`; free-form/provider messages are rejected and never + stored, logged, emitted, or returned. +- failed must have null fulfilled_quantity and fulfilled_at. +- Project, binding, contributor, instrument, unit, and authorized quantity cannot be changed by the callback. +- Multiple failed receipts may exist for one award when their external_event_id values differ. +- At most one fulfilled receipt may exist for one award. +- A fulfilled award rejects all later failed or fulfilled callbacks except an exact idempotent replay of the accepted fulfilled callback. + +### 6.10 CompensationStatusProjection + +This projection exists only for efficient reads and operations. + +~~~yaml +CompensationStatusProjection: + compensation_award_id: uuid + delivery_status: enum [ + pending_delivery, + acknowledged_by_adapter + ] + fulfillment_status: enum [ + pending, + failed, + fulfilled + ] + + latest_receipt_id: uuid | null + last_failure_code: string | null + delivered_at: timestamp | null + fulfilled_at: timestamp | null + updated_at: timestamp +~~~ + +The projection is mutable and rebuildable. It is not the source of truth. ContributionRecord, CompensationAward, outbox delivery history, and CompensationFulfillmentReceipt are authoritative. + +### 6.11 ContributionEvidenceProjection + +Every ContributionRecord receives one rebuildable projection status row for its immutable contribution-evidence bundle. + +~~~yaml +ContributionEvidenceProjection: + contribution_record_id: uuid + project_id: uuid + projection_schema_version: int + status: enum [pending, projected, failed] + + artifact_binding_id: uuid | null + content_digest: string | null + last_error_code: string | null + last_attempt_at: timestamp | null + projected_at: timestamp | null + updated_at: timestamp +~~~ + +The projection row is mutable and rebuildable. ContributionRecord and its source Review chain remain canonical. + +#### Logical evidence-bundle schema + +The deterministic bundle is a versioned manifest; it references already retained artifacts rather than duplicating their bytes. + +~~~yaml +ContributionEvidenceBundle: + schema_version: int + contribution_record_id: uuid + contribution_type: accepted_submission | completed_review + project_id: uuid + task_id: uuid + contributor_id: uuid + + source_task_assignment_id: uuid + submission_id: uuid + source_submission_artifact_digest: string + + locked_task_context_ref: uuid + project_guide_version_ref: uuid + effective_project_policy_version_ref: uuid + review_policy_version_ref: uuid + submission_artifact_binding_ids: list[uuid] + canonical_recorded_at: timestamp +~~~ + +The bundle proves the contribution against its immutable task/submission and +published policy context. It excludes reviewer-private findings, resolutions, +reviewer identity/lease data, compensation policy/award data, provider data, +and internal checker evidence. Any richer derivative requires its own schema, +ActionId, disclosure review, and behavioral tests. + +#### Evidence projection invariants + +- Exactly one ContributionEvidenceProjection row exists per ContributionRecord. +- `artifact_binding_id`, when present, references a verified generic ArtifactBinding with owner_type `contribution_record` and artifact_role `contribution_evidence_bundle`. +- Bundle project, task, contributor, and submission references resolve to the + same canonical chain; excluded review-private and compensation data is not + reintroduced through references. +- Guide, effective-policy and review-policy references are copied from the task's immutable locked context; the worker MUST NOT load the project's current versions as substitutes. +- Bundle generation reads canonical committed Workstream records; it never trusts event payload fields as independent authority. +- The serialized bundle is deterministic for one ContributionRecord and projection schema version. +- Same projection identity and bytes return the same logical storage receipt; changed bytes under the same identity are an integrity conflict. +- Projection failure does not modify or invalidate the ContributionRecord or compensation lifecycle. +- Artifact Storage contains the immutable bundle bytes/manifest; PostgreSQL contains canonical lifecycle truth and projection status/reference. + +#### Canonical serialization contract + +- Media type is `application/vnd.workstream.contribution-evidence+json;version=1`. +- JSON is serialized with RFC 8785 JSON Canonicalization Scheme rules and UTF-8 bytes. +- Timestamps use UTC RFC 3339 form with normalized fractional precision. +- UUIDs are lowercase canonical strings. +- All list fields are present, use empty lists rather than null, and are ordered by canonical record creation time followed by id. +- Scalar optional fields use explicit null when the schema permits null. +- Mutable compensation delivery/fulfillment projections, mutable evidence status and provider-local references are excluded from the bundle. +- `content_digest` is lowercase `sha256:` over the exact canonical bytes. +- A projection schema-version change is required for any semantic or serialization change. + +### 6.12 Artifact Storage ownership boundary + +WS-CON consumes narrow typed contribution-evidence write and read capabilities +owned by ART. It never receives the raw ArtifactStore, provider references, or +provider credentials and never imports storage-adapter internals. + +~~~text +Workstream owns + ContributionRecord and compensation meaning + source Review/task/submission relationships + evidence-bundle schema and projection status + contribution-evidence schema, meaning and visibility + authorization, audit and outbox state + +Artifact Storage owns + prepared-byte admission and raw provider I/O + content identity, verification and generic ArtifactBinding persistence + storage receipts, recovery, fencing and idempotency + immutable completed-object retention policy +~~~ + +The required capability shape is: + +~~~python +class ContributionEvidenceWritePort: + async def write(request: ContributionEvidenceWriteRequest): ... + +class ContributionEvidenceReadPort: + async def read(request: ContributionEvidenceReadRequest): ... +~~~ + +The write request carries canonical contribution/project/schema identity, +expected digest, media type, stable idempotency identity, and deterministic +prepared bytes or a bounded byte source. The read request accepts a Workstream +ArtifactBinding id plus the already-authorized contribution context. ART admits, +stores, verifies, binds, receipts, and recovers the operation; responses expose +only bounded binding/receipt data or verified bytes/stream, never a raw provider +reference. Only ART's ArtifactStorageOrchestrator receives the raw store. + +The projection identity is: + +~~~text +contribution:{contribution_record_id}:evidence-bundle:{projection_schema_version} +~~~ + +### 6.13 Contribution evidence projection flow + +The canonical Review/contribution transaction performs no remote storage call. It creates the ContributionRecord, a pending ContributionEvidenceProjection row and a `ContributionEvidenceProjectionRequested` transactional outbox event. + +After commit, the projection worker: + +1. runs as a provisioned Workstream system actor; +2. loads the ContributionRecord and complete canonical source chain; +3. resolves every referenced Workstream ArtifactBinding and verifies project/task consistency; +4. builds the deterministic versioned bundle; +5. computes the expected digest before the provider call; +6. calls the ART-owned write capability with the stable operation identity; +7. validates the bounded ART receipt, digest, size, media type, scope and operation identity; +8. records the verified `contribution_evidence_bundle` ArtifactBinding returned by ART; +9. updates ContributionEvidenceProjection to `projected`; +10. emits `ContributionEvidenceProjected` audit/integration evidence. + +No ContributionRecord, award, receipt or Review is inferred from provider content. Projection always begins from canonical Workstream records. + +### 6.14 Authorized evidence retrieval + +Contribution-list endpoints return evidence status and authorized Workstream references only; they do not inline artifact bytes. + +When a caller requests contribution evidence: + +1. AuthorizationService requires `contribution.read_self` or `contribution.read_project` for the canonical ContributionRecord. +2. Workstream proves the projection ArtifactBinding belongs to that ContributionRecord and project. +3. Workstream calls the ART-owned typed read capability with that binding and authorized context. +4. ART verifies the binding and exact digest before returning bounded bytes or a stream. +5. Workstream records an attributable access receipt/audit reference. +6. Workstream returns the authorized bundle or approved derivative representation. + +There is no semantic-search disclosure path in v0.1. + +### 6.15 Artifact failure semantics + +| Failure | WS-CON effect | +|---|---| +| Artifact Storage unavailable after contribution commit | Contribution and awards remain canonical; projection stays pending/failed and retries | +| Projection receipt digest mismatch | Do not bind receipt; mark failed; raise integrity alert | +| Same operation identity with different bundle bytes | Permanent integrity conflict; bind nothing and alert | +| Evidence bundle unavailable during authorized read | Return `contribution_evidence_unavailable`; do not change contribution or compensation status | +| Provider outcome uncertain | Use the existing idempotent artifact recovery contract; never guess success | + +An Artifact Storage failure never creates or changes an award, fulfillment receipt, contributor reputation signal, or review outcome. + +### 6.16 Storage-adapter equivalence + +LocalStorage is limited to focused development/tests. MinIO proves the +S3-compatible protocol locally and in CI, and AWS S3 is the v0.1 production +provider. R2 and Flow Node are deferred. Every enabled adapter must preserve +the same digest, binding, idempotency, authorization, and recovery semantics. +Recovery remains an ART orchestration concern through its typed operator port +and existing `artifact.verification_job.retry` action. + +--- + +## 7. Project Scope and Global Contribution Views + +### 7.1 Global record identity + +ContributionRecord.id is globally unique within Workstream. A contributor's complete history may span projects. + +~~~text +Contributor +└── Contribution history + ├── Project A + │ ├── accepted_submission + │ └── completed_review + ├── Project B + │ └── completed_review + └── Project C + └── accepted_submission +~~~ + +### 7.2 Project-scoped economics + +Every CompensationPolicy, policy version, award definition, CompensationAward, adapter binding, and fulfillment receipt has a project_id. + +- A Project A policy cannot compensate Project B work. +- Project A points cannot be fulfilled into Project B's point namespace. +- A USD award from Project A remains Project A's obligation; it is not a global Workstream balance. +- Cross-project totals are read-model calculations only. + +### 7.3 Read views + +Required views: + +- contributor global contribution history; +- contributor history filtered to one project; +- project contribution history; +- task contribution history; +- Contribution Record detail with derived compensation summary; +- Contribution Record detail with contribution-evidence projection status and authorized ArtifactBinding reference; +- project outstanding compensation awards by instrument and age; +- adapter delivery and fulfillment operational view. + +--- + +## 8. Compensation Policy Lifecycle + +### 8.1 Create draft + +An active Finance Authority whose effective scope covers the project and whose AuthorizationDecision allows `compensation.policy.create_draft` creates a CompensationPolicy and version 1 draft, or creates the next draft version under an existing policy. + +Draft creation does not affect existing or new work until publication and activation. + +### 8.2 Validate draft + +Publication validation MUST confirm: + +- policy and every definition belong to the same project; +- only accepted_submission and completed_review rules exist; +- only money and project_points instruments exist; +- no duplicate instrument exists within a contribution type; +- every quantity is a positive decimal; +- every unit code is valid for its instrument; +- every adapter binding belongs to the project, supports the instrument, and is active; +- both contribution types are explicitly present as either compensated or unpaid; +- no task, contributor, tier, outcome, skill, or reputation condition exists; +- AuthorizationService allows `compensation.policy.update_draft` for draft replacement and `compensation.policy.publish` for publication validation on the canonical resource. + +### 8.3 Publish and activate + +Publication and project activation occur in one transaction: + +~~~text +validate complete draft +lock project's active compensation policy reference +publish version immutably +set owning CompensationPolicy.status -> active +set owning CompensationPolicy.current_published_version_id -> new version id +retire any different previously active CompensationPolicy identity +set project active_compensation_policy_version_id +retire prior version for new-work selection +write policy audit events +commit +~~~ + +The transaction revalidates `compensation.policy.publish` through AuthorizationService after loading and locking the canonical project/version resources. Retirement separately revalidates `compensation.policy.retire`. A router-level role check is insufficient. + +Retiring the prior version means it is no longer selected for new assignments or leases. It remains valid for previously frozen work. + +If an active version is retired without an immediate replacement, the same transaction sets Project.active_compensation_policy_version_id to null and CompensationPolicy.status to retired. New TaskAssignments and ReviewLeases then fail until another version is activated. Existing frozen work remains valid. + +### 8.4 Explicit unpaid policy + +An unpaid project still requires a published version. + +~~~yaml +accepted_submission: + compensation_mode: unpaid + awards: [] + +completed_review: + compensation_mode: unpaid + awards: [] +~~~ + +This prevents missing configuration from silently removing contributor compensation. + +### 8.5 Policy-change boundary + +If version 2 becomes active: + +- existing TaskAssignments retain their frozen version; +- existing ReviewLeases retain their frozen version; +- new TaskAssignments freeze version 2; +- new ReviewLeases freeze version 2; +- queued but unleased ReviewQueueEntries use the version active when a reviewer successfully claims them; +- Contribution Records always copy the version from their assignment or lease, never from the project's current setting at decision time. + +--- + +## 9. Contribution Creation Matrix + +| Review outcome or lease result | Reviewer Contribution Record | Submitter Contribution Record | Reviewer compensation evaluated | Submitter compensation evaluated | +|---|---:|---:|---:|---:| +| accept | Yes | Yes | Yes | Yes | +| needs_revision | Yes | No | Yes | No | +| reject | Yes | No | Yes | No | +| manual release | No | No | No | No | +| lease expiry | No | No | No | No | +| administrative revocation | No | No | No | No | +| invalid decision attempt | No | No | No | No | +| idempotent replay of committed decision | Return existing | Return existing if accept | Return existing | Return existing if accept | + +Review compensation is decision-neutral. No award definition may match or vary by decision. + +--- + +## 10. State Machines + +### 10.1 ContributionRecord lifecycle + +ContributionRecord has no mutable state machine. + +~~~text +not present --valid Review transaction--> recorded permanently +~~~ + +It cannot move to pending, failed, fulfilled, cancelled, voided, or deleted. + +### 10.2 CompensationPolicyVersion + +~~~text +draft --publish and activate--> published --replace for new work--> retired +~~~ + +- draft may be edited; +- published is immutable and selectable for new work; +- retired is immutable and valid only through frozen references. + +### 10.3 CompensationAward fulfillment projection + +~~~text + adapter callback: failed + +-------------------------+ + | v +pending_delivery -> acknowledged pending -> failed + | | | | + | | | +--later fulfilled callback--+ + | | | | + +--valid fulfilled callback-----------+---------------------------------v + fulfilled +~~~ + +Normative rules: + +- Delivery acknowledgement changes only delivery_status. +- A failed callback changes fulfillment_status to failed. +- A later valid fulfilled callback changes failed to fulfilled. +- Fulfilled is terminal. +- Delivery state and fulfillment state are independent. +- A callback may arrive before local delivery acknowledgement; it is accepted if otherwise valid and MUST NOT later regress. + +--- + +## 11. Frozen-Terms Operations + +### 11.1 Create TaskAssignment + +Preconditions: + +- project has an active published CompensationPolicyVersion; +- AuthorizationService allows the upstream `task.claim` operation through an active submitter/both ProjectRoleGrant; +- task and project are claimable under existing rules. + +Transaction: + +~~~text +lock project active compensation policy reference +validate version is published +create TaskAssignment +copy version id -> submitter_compensation_policy_version_id +write CompensationTermsFrozenForAssignment +commit +~~~ + +If no active version exists, assignment creation fails with compensation_policy_missing. + +### 11.2 Create ReviewLease + +This extends the atomic WS-REV-001 claim transaction. + +Preconditions: + +- AuthorizationService allows `review.claim` inside the claim transaction and every WS-REV-001 eligibility/capacity guard passes; +- project has an active published CompensationPolicyVersion. + +Transaction addition: + +~~~text +lock project active compensation policy reference +validate version is published +create ReviewLease +copy version id -> reviewer_compensation_policy_version_id +write CompensationTermsFrozenForReviewLease +commit with queue claim +~~~ + +If the project changes policy concurrently, row locking ensures the lease freezes either the old active version before replacement commits or the new active version after replacement commits. It cannot freeze an indeterminate mixture. + +### 11.3 Released, expired, or revoked lease + +The frozen reference remains on the permanent ReviewLease attempt for audit. It creates no contribution or award because no valid Review was recorded. + +--- + +## 12. Atomic Review-to-Contribution Operations + +### 12.1 Common decision transaction + +Every valid Review decision uses one PostgreSQL transaction and one unit of work. + +The caller's primary ActionId is `review.decision` on the active ReviewLease. +Contribution and award creation are mandatory internal participants in that +same caller-owned transaction, with no separate action, authority, or commit. + +After all WS-REV-001 validations pass, the transaction MUST: + +~~~text +1. create immutable Review and any ReviewFinding/FindingResolution records +2. consume ReviewLease and close ReviewQueueEntry +3. apply the decision-specific Task and TaskAssignment transition +4. create reviewer ContributionRecord +5. create reviewer ContributionEvidenceProjection(status=pending) +6. write reviewer ContributionEvidenceProjectionRequested outbox event +7. evaluate the ReviewLease's frozen policy version +8. create reviewer CompensationAwards from exact completed_review definitions +9. create reviewer ContributionRecorded outbox event +10. create CompensationAwardCreated audit/outbox event for each award +11. create CompensationFulfillmentRequested outbox event for each award +12. if decision = accept: + a. create submitter ContributionRecord + b. create submitter ContributionEvidenceProjection(status=pending) + c. write submitter ContributionEvidenceProjectionRequested outbox event + d. evaluate the TaskAssignment's frozen policy version + e. create submitter CompensationAwards from exact accepted_submission definitions + f. create submitter ContributionRecorded outbox event + g. create award and fulfillment-requested events for each award +13. link the originating Review AuthorizationDecision and write all review, contribution, compensation, task, and assignment audit events +14. commit +~~~ + +If any database insert, invariant, event write, or decision-specific transition fails, the entire transaction rolls back. + +No compensation-adapter or Artifact Storage call occurs inside this transaction. External availability therefore cannot delay or invalidate the human decision or contribution recognition. + +### 12.2 Reviewer contribution creation + +Input: + +- canonical Review being created; +- consumed ReviewLease; +- reviewed Submission; +- reviewed TaskAssignment; +- frozen ReviewLease reviewer_compensation_policy_version_id. + +Output: + +~~~yaml +contribution_type: completed_review +contributor_id: Review.reviewer_id +source_review_id: Review.id +source_review_lease_id: ReviewLease.id +source_task_assignment_id: TaskAssignment.id +submission_id: Review.submission_id +compensation_policy_version_id: ReviewLease.reviewer_compensation_policy_version_id +source_submission_artifact_digest: Submission.artifact_digest +~~~ + +The algorithm is identical for accept, needs_revision, and reject. Branching compensation logic by Review.decision is prohibited. + +### 12.3 Submitter contribution creation on accept + +Input: + +- Review with decision = accept; +- accepted Submission; +- completed TaskAssignment; +- frozen TaskAssignment submitter_compensation_policy_version_id. + +Output: + +~~~yaml +contribution_type: accepted_submission +contributor_id: Submission.created_by +source_review_id: Review.id +source_review_lease_id: null +source_task_assignment_id: TaskAssignment.id +submission_id: Review.submission_id +compensation_policy_version_id: TaskAssignment.submitter_compensation_policy_version_id +source_submission_artifact_digest: Submission.artifact_digest +~~~ + +The contribution is created only after all accept validations pass but before transaction commit. + +### 12.4 Needs revision + +Needs revision creates: + +- one completed_review Contribution Record; +- zero or more reviewer CompensationAwards; +- no accepted_submission Contribution Record; +- no submitter CompensationAward. + +When a later submission version is reviewed, that later Review creates another completed_review record. There is no maximum compensated review-round count in v0.1. + +Structured findings, immutable chains, no-self-review, reviewer leasing, and audit events remain the controls against abusive revision cycling. + +### 12.5 Reject + +Reject creates: + +- one completed_review Contribution Record; +- zero or more reviewer CompensationAwards; +- no submitter Contribution Record; +- no submitter CompensationAward. + +Reviewer compensation remains valid even though the submitter TaskAssignment becomes blocked and the task closes. + +### 12.6 Explicitly unpaid result + +If the frozen policy version has no award definition for the relevant contribution type: + +- create the Contribution Record; +- create ContributionRecorded; +- create no CompensationAward; +- create no CompensationFulfillmentRequested event; +- do not treat the absence of an award as an error. + +The Contribution Record's policy version proves that the explicit unpaid rule was evaluated. + +### 12.7 Integrity failure + +If a frozen policy reference is missing, corrupt, from the wrong project, or contains prohibited duplicate definitions: + +- reject the decision transaction with compensation_policy_integrity_error; +- create no Review or contribution; +- after rollback, write a structured integrity-error log, increment workstream_compensation_policy_integrity_errors_total, and trigger the configured operator alert; +- require operator remediation. + +The implementation MUST NOT substitute the current project policy or silently treat the work as unpaid. + +--- + +## 13. Compensation Evaluation + +### 13.1 Deterministic algorithm + +For one Contribution Record: + +~~~text +load exact frozen CompensationPolicyVersion +validate project match +select the one CompensationRule matching record.contribution_type +if rule is unpaid, return zero awards +if rule is compensated, load its award definitions +order definitions deterministically by instrument_type +for each definition: + copy definition fields into immutable CompensationAward + resolve the exact frozen adapter binding + create award and outbox events +return created awards +~~~ + +No scoring engine, rules interpreter, dynamic expression, network call, current reputation lookup, or current project-policy lookup is permitted. + +### 13.2 Decision neutrality + +For completed_review: + +~~~text +award(completed_review, accept) + = award(completed_review, needs_revision) + = award(completed_review, reject) +~~~ + +The Review outcome may be included as provenance in ContributionRecorded, but it cannot select or modify compensation. + +### 13.3 Multiple instruments + +If a completed-review rule defines money and project points: + +~~~text +one ContributionRecord + -> one money CompensationAward + -> one project_points CompensationAward + -> two independent fulfillment events +~~~ + +One instrument's delivery or fulfillment status never blocks or changes the other. + +### 13.4 Decimal and unit rules + +- Use an exact decimal database type. +- API quantities are decimal strings, never JSON floating-point numbers. +- Money quantities are interpreted according to unit_code but are not rounded by Workstream after policy publication. +- Policy publication rejects quantities exceeding the configured currency precision. +- Project-points quantities MUST be whole positive numbers in v0.1. +- Unit conversion is prohibited. +- Adapters cannot substitute another currency or point unit. + +--- + +## 14. Transactional Event Contract + +### 14.1 Outbox requirement + +Every outbound domain or integration event is written to the shared +transactional outbox introduced by prerequisite CON-02A in the same transaction +as its source record. + +The dispatcher uses at-least-once delivery. Consumers and adapters MUST implement idempotency. + +No code path may: + +- commit a Contribution Record and publish its event outside the outbox; +- publish an event before the database transaction commits; +- call an external adapter from the Review transaction; +- delete an outbox event because delivery is temporarily failing. + +### 14.2 Common event envelope + +~~~yaml +event_id: uuid +event_type: string +event_version: 1 +occurred_at: timestamp +producer: workstream + +project_id: uuid +correlation_id: string +causation_event_id: uuid | null +idempotency_key: string + +payload: object +~~~ + +The canonical idempotency key is stable for the logical event and does not change across delivery retries. + +### 14.3 ContributionRecorded + +One event is emitted per Contribution Record. + +~~~yaml +event_type: ContributionRecorded +event_version: 1 +idempotency_key: "contribution:{contribution_record_id}:recorded:v1" + +payload: + contribution_record_id: uuid + project_id: uuid + task_id: uuid + contributor_id: uuid + contribution_type: accepted_submission | completed_review + source_review_id: uuid + source_review_lease_id: uuid | null + source_task_assignment_id: uuid + submission_id: uuid + source_submission_artifact_digest: string + review_decision: accept | needs_revision | reject + compensation_policy_version_id: uuid + compensation_award_ids: list[uuid] + recorded_at: timestamp +~~~ + +Consumers may use this event for reputation signals, analytics, notifications, evidence export, or other authorized projections. + +The event does not assert that compensation has been fulfilled. + +### 14.4 ContributionEvidenceProjectionRequested + +One internal projection event is emitted per Contribution Record in the same transaction that creates it. + +~~~yaml +event_type: ContributionEvidenceProjectionRequested +event_version: 1 +idempotency_key: "contribution:{contribution_record_id}:evidence-bundle:1" + +payload: + contribution_record_id: uuid + project_id: uuid + projection_schema_version: 1 + requested_at: timestamp +~~~ + +The payload is a wake-up reference, not independent evidence. The worker MUST reload the canonical ContributionRecord, Review, Submission, task policy context, ArtifactBindings, findings, resolutions, compensation policy and awards before generating the bundle. + +After verified storage, Workstream emits `ContributionEvidenceProjected` with the Workstream ArtifactBinding ID and verified digest. Raw provider references MUST NOT appear in public integration events. + +~~~yaml +event_type: ContributionEvidenceProjected +event_version: 1 +idempotency_key: "contribution:{contribution_record_id}:evidence-projected:{projection_schema_version}" + +payload: + contribution_record_id: uuid + project_id: uuid + projection_schema_version: int + artifact_binding_id: uuid + content_digest: string + projected_at: timestamp +~~~ + +### 14.5 CompensationAwardCreated + +~~~yaml +event_type: CompensationAwardCreated +event_version: 1 +idempotency_key: "compensation-award:{compensation_award_id}:created:v1" + +payload: + compensation_award_id: uuid + contribution_record_id: uuid + project_id: uuid + contributor_id: uuid + instrument_type: money | project_points + unit_code: string + quantity: decimal_string + compensation_policy_version_id: uuid + adapter_binding_id: uuid + created_at: timestamp +~~~ + +This event is an immutable domain fact. It is not itself the adapter instruction. + +### 14.6 CompensationFulfillmentRequested + +One event is emitted per CompensationAward. + +~~~yaml +event_type: CompensationFulfillmentRequested +event_version: 1 +idempotency_key: "compensation-award:{compensation_award_id}:fulfill:v1" + +payload: + compensation_award_id: uuid + contribution_record_id: uuid + project_id: uuid + contributor_id: uuid + + instrument_type: money | project_points + unit_code: string + quantity: decimal_string + + compensation_policy_version_id: uuid + adapter_binding_id: uuid + adapter_route_key: string + + contribution_type: accepted_submission | completed_review + source_review_id: uuid + created_at: timestamp +~~~ + +The event contains the complete authorized instruction. The adapter MUST NOT query mutable project policy to determine a different quantity. + +### 14.7 CompensationFulfillmentRecorded + +One event is emitted for every accepted fulfillment receipt. + +~~~yaml +event_type: CompensationFulfillmentRecorded +event_version: 1 +idempotency_key: "fulfillment-receipt:{fulfillment_receipt_id}:recorded:v1" + +payload: + fulfillment_receipt_id: uuid + compensation_award_id: uuid + contribution_record_id: uuid + project_id: uuid + contributor_id: uuid + instrument_type: money | project_points + unit_code: string + authorized_quantity: decimal_string + reported_status: fulfilled | failed + failure_code: string | null + fulfilled_at: timestamp | null + received_at: timestamp +~~~ + +This event reports Workstream's accepted receipt. It does not expose provider credentials or create a new award. + +### 14.8 Sensitive-data restriction + +Events MUST NOT contain: + +- bank details; +- wallet private keys; +- provider access tokens; +- Identity Issuer bearer tokens; +- point-account credentials; +- raw personal financial data. +- raw provider CIDs, filesystem paths, or storage credentials. + +The adapter resolves its own external beneficiary mapping from contributor_id through its authorized integration. + +--- + +## 15. External Adapter Contract + +### 15.1 Workstream adapter port + +Workstream exposes one outbound port to its outbox dispatcher. Provider-specific implementations remain outside the Workstream domain. + +~~~python +class CompensationDeliveryAdapter( + ExternalServiceAdapter[ + CompensationFulfillmentRequested, + AdapterDeliveryAcknowledgement, + ], + Protocol, +): + async def deliver( + self, + binding_id: UUID, + event: CompensationFulfillmentRequested, + ) -> AdapterDeliveryAcknowledgement: + ... + + +class AdapterDeliveryAcknowledgement: + event_id: UUID + accepted: Literal[True] + acknowledged_at: datetime +~~~ + +The port implementation MUST: + +- route only through the persisted adapter_binding_id; +- send the persisted event without recalculating it; +- authenticate Workstream to the adapter; +- return success only after the adapter durably stores the event idempotency key; +- translate timeouts and non-success responses into a delivery failure so the outbox retries. + +The adapter is resolved only through the explicitly composed +`ExternalServiceAdapterFactory[CompensationDeliveryAdapter]`. Runtime discovery, +service locators, fallback constructors, concrete adapter imports in domain +services, and a second feature-local factory are prohibited. The repository +includes only the typed adapter contract, shared dispatcher integration, and a +deterministic test adapter for the live drill. + +### 15.2 Delivery + +The outbox dispatcher routes CompensationFulfillmentRequested using the frozen adapter_binding_id and route_key. + +Adapter response to delivery: + +- 2xx means the adapter durably accepted the instruction and its idempotency key; +- non-2xx or timeout means delivery was not acknowledged and Workstream retries; +- a 2xx acknowledgement does not mean money or points were fulfilled. + +After acknowledgement, Workstream does not create provider retries. The adapter owns all provider-side processing. + +### 15.3 Adapter idempotency + +The adapter MUST treat compensation_award_id and the event idempotency key as stable identifiers. + +Repeated delivery of the same event: + +- must not create another payment request; +- must not credit points twice; +- must return a successful acknowledgement after the original instruction is durably recognized. + +### 15.4 Fulfillment callback request + +~~~yaml +CompensationFulfillmentReported: + external_event_id: string + compensation_award_id: uuid + status: fulfilled | failed + + fulfilled_quantity: decimal_string | null + fulfilled_at: timestamp | null + + failure_code: string | null + reported_at: timestamp +~~~ + +The callback does not accept project_id, contributor_id, instrument_type, unit_code, or authorized quantity as mutable authority. Workstream loads those from CompensationAward. + +### 15.5 Callback authentication and authorization + +Workstream MUST: + +1. verify the Identity Issuer service token; +2. resolve one active service ActorProfile and active ActorIdentityLink through WS-AUTH-001; +3. load and lock the CompensationAward, ContributionRecord and frozen adapter binding from canonical identifiers; +4. ask AuthorizationService for `compensation.fulfillment.report` on the canonical award resource; +5. require the service actor to equal the frozen binding adapter_actor_id; +6. require the binding project and instrument to match the award; +7. validate callback schema and timestamps; +8. enforce idempotency before insertion; +9. persist the AuthorizationDecision reference with the callback audit chain. + +The request body cannot supply project, contributor, instrument, quantity, binding or authorization scope. Those values are loaded from the award chain. + +An `active` binding accepts delivery and callback work. A `suspended` binding accepts valid callbacks for already-issued awards but receives no new delivery; this permits an adapter to report a result for work it accepted before suspension. Retirement is prohibited while an award remains unfulfilled. After retirement, only an exact replay of a previously accepted receipt may return its stored result. + +The service permission is binding-derived and award-scoped. A human Admin token, contributor token, different adapter actor, disabled service actor, revoked identity link, or valid service actor without the exact frozen binding is denied. + +### 15.6 Fulfilled callback + +Validation: + +- fulfilled_quantity exactly equals award.quantity; +- fulfilled_at is present and not unreasonably in the future; +- no different fulfilled receipt already exists; +- award project and binding remain internally consistent. + +Effect in one transaction: + +~~~text +revalidate compensation.fulfillment.report against locked canonical award/binding +insert immutable fulfilled receipt +update status projection -> fulfilled +write CompensationFulfilled audit event linked to AuthorizationDecision +write CompensationFulfillmentRecorded outbox event +commit +~~~ + +Fulfilled is terminal. + +### 15.7 Failed callback + +Validation: + +- failure_code is non-empty; +- fulfilled_quantity and fulfilled_at are null; +- no fulfilled receipt already exists. + +Effect: + +~~~text +revalidate compensation.fulfillment.report against locked canonical award/binding +insert immutable failed receipt +update status projection -> failed +write CompensationFulfillmentFailed audit event linked to AuthorizationDecision +write CompensationFulfillmentRecorded outbox event +commit +~~~ + +The adapter may later report fulfilled using a new external_event_id. + +### 15.8 Prohibited partial fulfillment + +If fulfilled_quantity differs from award.quantity: + +- reject with 422 partial_fulfillment_not_supported; +- create no receipt; +- do not change the projection; +- write a rejected-callback security/audit event. + +The adapter must resolve partial provider behaviour internally before reporting the Workstream award as fulfilled. + +### 15.9 Contradictory callbacks + +- failed followed by fulfilled: allowed. +- failed followed by another failed with a new external_event_id: allowed. +- fulfilled followed by failed: rejected with 409 award_already_fulfilled. +- fulfilled followed by a different fulfilled event: rejected with 409 award_already_fulfilled. +- exact replay of an accepted callback: return the existing receipt with 200. +- reuse of external_event_id with different payload: reject with 409 idempotency_mismatch. + +--- + +## 16. Reputation Boundary + +ContributionRecorded is the canonical reputation input from this lifecycle. + +Recommended raw signal mapping: + +| contribution_type | reputation signal | +|---|---| +| accepted_submission | submission_accepted | +| completed_review | review_completed | + +Normative rules: + +- Signal creation is independent of compensation awards. +- Signal creation is independent of adapter delivery and fulfillment. +- A completed-review signal may carry Review.decision as provenance, but this specification assigns no positive or negative score based on that outcome. +- Needs revision does not automatically reduce submitter reputation. +- Reject does not create a submitter Contribution Record and therefore produces no positive submitter contribution signal. +- Lease expiry and release signals remain the separate audit events defined by WS-REV-001. +- Reputation scoring, aggregation, decay, project-to-global weighting, grant automation, and reviewer-quality adjudication are outside this specification. + +The reputation consumer MUST deduplicate by contribution_record_id and event version. + +--- + +## 17. Read Model and API Composition + +### 17.1 Canonical versus composed data + +The canonical Contribution Record remains unchanged after creation. Contribution +reads compose only contribution and evidence state: + +~~~text +ContributionRecord + ContributionEvidenceProjection + = Contribution detail response +~~~ + +Award, delivery, receipt, and fulfillment data require the separate +`compensation.award.read_self` or `compensation.award.read_project` ActionId and +are returned only from award routes. + +The contribution read composer MUST authorize the canonical ContributionRecord +before loading evidence references. It never loads awards, receipts, or +provider-derived metadata; those require separately authorized award routes. +It MUST NOT use the caller-supplied project_id as authority. + +### 17.2 Example contribution response + +~~~json +{ + "id": "contribution-uuid", + "project_id": "project-uuid", + "task_id": "task-uuid", + "contributor_id": "contributor-uuid", + "contribution_type": "completed_review", + "source_review_id": "review-uuid", + "submission_id": "submission-version-uuid", + "source_submission_artifact_digest": "sha256:...", + "recorded_at": "2026-07-10T12:00:00Z", + "evidence": { + "status": "projected", + "artifact_binding_id": "artifact-binding-uuid", + "content_digest": "sha256:..." + } +} +~~~ + +This is a read representation, not a mutable aggregate stored as one row. + +The `artifact_binding_id` is a Workstream reference. The response does not disclose a raw provider CID, URL or filesystem path. `content_digest` proves integrity but grants no retrieval authority. + +--- + +## 18. API Contract + +The following paths are normative for Workstream v0.1. The `/api/v1` prefix is the independent API contract namespace, not a Workstream v1.0 release identifier. + +### 18.1 Compensation policies + +~~~text +POST /api/v1/projects/{project_id}/compensation-policies +POST /api/v1/projects/{project_id}/compensation-policies/{policy_id}/versions +PUT /api/v1/projects/{project_id}/compensation-policy-versions/{version_id}/draft +POST /api/v1/projects/{project_id}/compensation-policy-versions/{version_id}/publish +POST /api/v1/projects/{project_id}/compensation-policy-versions/{version_id}/retire +GET /api/v1/projects/{project_id}/compensation-policies +GET /api/v1/projects/{project_id}/compensation-policy-versions/{version_id} +~~~ + +Creating a new policy creates the policy identity and an empty version 1 draft. Creating a version under an existing policy copies the current published version into the next draft version. The draft remains inactive until explicitly published. + +Policy creation request: + +~~~json +{ + "name": "Project default compensation" +} +~~~ + +PUT replaces the complete draft rules; it does not merge individual fields. + +~~~json +{ + "rules": [ + { + "contribution_type": "accepted_submission", + "compensation_mode": "compensated", + "awards": [ + { + "instrument_type": "money", + "unit_code": "USD", + "quantity": "45.00", + "adapter_binding_id": "money-binding-uuid" + } + ] + }, + { + "contribution_type": "completed_review", + "compensation_mode": "compensated", + "awards": [ + { + "instrument_type": "money", + "unit_code": "USD", + "quantity": "60.00", + "adapter_binding_id": "money-binding-uuid" + }, + { + "instrument_type": "project_points", + "unit_code": "REVIEW_POINT", + "quantity": "5", + "adapter_binding_id": "points-binding-uuid" + } + ] + } + ] +} +~~~ + +The publish request and the retire request both require: + +~~~json +{ + "expected_current_version_id": "current-version-uuid-or-null" +} +~~~ + +No edit endpoint exists for a published or retired version. + +Policy routes use exactly one primary ActionId: `compensation.policy.create_draft`, `compensation.policy.update_draft`, `compensation.policy.publish`, `compensation.policy.retire`, or `compensation.policy.read`, matched to the operation and canonical target. Every write requires Finance Authority. Possession of a route path is not authority. + +### 18.2 Adapter bindings + +~~~text +POST /api/v1/projects/{project_id}/compensation-adapter-bindings +POST /api/v1/projects/{project_id}/compensation-adapter-bindings/{binding_id}/suspend +POST /api/v1/projects/{project_id}/compensation-adapter-bindings/{binding_id}/resume +POST /api/v1/projects/{project_id}/compensation-adapter-bindings/{binding_id}/retire +GET /api/v1/projects/{project_id}/compensation-adapter-bindings +~~~ + +Binding creation request: + +~~~json +{ + "instrument_type": "money", + "adapter_actor_id": "service-actor-uuid", + "route_key": "project-money-v1" +} +~~~ + +The route_key identifies deployment routing configuration and contains no endpoint credential or secret. + +Binding routes use exactly one primary ActionId: `compensation.adapter_binding.create`, `compensation.adapter_binding.suspend`, `compensation.adapter_binding.resume`, `compensation.adapter_binding.retire`, or `compensation.adapter_binding.read`, matched to the operation and canonical target. Every mutation requires Finance Authority. Operational views use `compensation.status.read`, `compensation.award.read_project`, or `audit.read` according to the canonical view. + +### 18.3 Contributions + +~~~text +GET /api/v1/contributors/me/contributions +GET /api/v1/contributors/me/contributions/{contribution_record_id} +GET /api/v1/contributors/me/contributions/{contribution_record_id}/evidence +GET /api/v1/projects/{project_id}/contributions +GET /api/v1/projects/{project_id}/contributions/{contribution_record_id} +GET /api/v1/projects/{project_id}/contributions/{contribution_record_id}/evidence +GET /api/v1/projects/{project_id}/contributors/{contributor_id}/contributions +GET /api/v1/projects/{project_id}/tasks/{task_id}/contributions +~~~ + +Supported filters: + +- project_id; +- contribution_type; +- task_id; +- recorded_from; +- recorded_to; +- cursor. + +Ordering is deterministic: + +~~~text +recorded_at DESC, id DESC +~~~ + +Authorization is deterministic: + +- `GET /api/v1/contributors/me/contributions` requires `contribution.read_self` and returns only records whose contributor_id is the caller's ActorProfile id; +- the two `/contributors/me/...` detail/evidence routes use `contribution.read_self` and require the record owner to equal the caller; +- every `/projects/{project_id}/...` contribution route uses `contribution.read_project` and derives exact scope from the canonical Project/ContributionRecord chain; +- project-scoped contributor history uses `/projects/{project_id}/contributors/{contributor_id}/contributions`; no cross-project Admin contributor-history route exists in v0.1; +- project and task endpoints require `contribution.read_project` for the canonical path project scope; +- records from unauthorized projects are never returned and are not revealed through total counts. + +No POST, PATCH, PUT, or DELETE Contribution Record endpoint exists. + +The self and project evidence endpoints apply their one declared contribution-read permission, validate the projection and ArtifactBinding chain, retrieve through ART-owned contribution-evidence capability with a Workstream service scope, verify the digest, record attributable access and return the approved bundle representation. + +Responses: + +- `200` when the verified bundle is available; +- `409 contribution_evidence_not_ready` while projection is pending; +- `503 contribution_evidence_unavailable` when projection or verified retrieval has failed; +- `404 contribution_not_found` when the record is absent or invisible. + +### 18.4 Compensation awards + +~~~text +GET /api/v1/contributors/me/compensation-awards +GET /api/v1/contributors/me/compensation-awards/{award_id} +GET /api/v1/projects/{project_id}/compensation-awards +GET /api/v1/projects/{project_id}/compensation-awards/{award_id} +GET /api/v1/projects/{project_id}/contributors/{contributor_id}/compensation-awards +POST /api/v1/projects/{project_id}/compensation-awards/{award_id}/reconcile-delivery +~~~ + +Supported operational filters: + +- instrument_type; +- delivery_status; +- fulfillment_status; +- created_from; +- created_to; +- minimum_pending_age. + +Self award routes require `compensation.award.read_self` and exact beneficiary +ownership. Project award routes require `compensation.award.read_project` and +covered canonical project scope. No unscoped award-detail or cross-project +Admin route exists, and contribution endpoints never compose award data. + +The reconciliation route requires `compensation.delivery.reconcile`, a mandatory `Idempotency-Key` header and a bounded structured reason. It may inspect delivery evidence or make the existing unacknowledged outbox instruction immediately eligible for dispatch with the same event_id, payload and idempotency key. It cannot create an award, change quantity/binding, fabricate acknowledgement, or mark fulfillment. A second equivalent request returns the stored result; an incompatible live request returns `409 compensation_reconciliation_in_progress`. + +### 18.5 Fulfillment callback + +~~~text +POST /api/v1/integrations/compensation/fulfillment-reports +~~~ + +Responses: + +- 201 when a new receipt is created; +- 200 for exact idempotent replay; +- 400 for malformed schema; +- 401 for invalid identity; +- 403 for unauthorized adapter or project/instrument mismatch; +- 404 for unknown award; +- 409 for callback conflict or idempotency mismatch; +- 422 for invalid fulfillment semantics. + +No endpoint allows an adapter to change the Contribution Record, CompensationAward, policy, assignment, lease, Review, task, or contributor. + +The callback requires an Identity Issuer service token and an allowed `compensation.fulfillment.report` AuthorizationDecision for the exact frozen award binding. Human Admin permissions cannot satisfy this route. + +--- + +## 19. Error Contract + +Errors MUST use the existing Workstream structured-error envelope and stable machine codes. + +| Code | HTTP | Meaning | +|---|---:|---| +| compensation_policy_missing | 409 | Project has no active published compensation version | +| compensation_policy_not_draft | 409 | Attempt to edit non-draft version | +| compensation_policy_invalid | 422 | Draft violates policy rules | +| compensation_policy_integrity_error | 500 | Frozen reference or published data is internally inconsistent | +| authentication_required | 401 | Required bearer token is absent | +| invalid_token | 401 | Identity Issuer token verification failed | +| actor_not_active | 403 | ActorProfile or identity link is not active | +| permission_not_granted | 403 | AuthorizationService denied the registered permission | +| resource_project_mismatch | 403 | Canonical record chain does not belong to the covered project scope | +| service_actor_not_provisioned | 403 | Callback identity is not an active provisioned service actor | +| adapter_binding_missing | 409 | Required instrument has no compatible binding | +| adapter_binding_in_use | 409 | Binding is referenced by active policy, unfinished frozen work, or unfulfilled awards | +| adapter_unauthorized | 403 | Callback actor is not bound to the award | +| compensation_reconciliation_in_progress | 409 | An incompatible live delivery-reconciliation request already exists for the award/event | +| contribution_not_found | 404 | Contribution Record does not exist or is not visible | +| compensation_award_not_found | 404 | Award does not exist or is not visible | +| contribution_already_recorded | 409 | Logical contribution already exists | +| compensation_award_already_exists | 409 | Logical award already exists | +| fulfillment_callback_invalid | 422 | Callback fields do not match status rules | +| partial_fulfillment_not_supported | 422 | Fulfilled quantity differs from authorized quantity | +| award_already_fulfilled | 409 | A contradictory post-fulfillment callback was attempted | +| idempotency_mismatch | 409 | Idempotency identifier was reused with different payload | +| contribution_evidence_not_ready | 409 | Contribution evidence projection has not completed | +| contribution_evidence_unavailable | 503 | Verified contribution evidence cannot currently be retrieved | +| artifact_binding_not_visible | 404 | ArtifactBinding does not exist in the caller's authorized contribution scope | +| artifact_integrity_mismatch | 500 | Stored evidence receipt or bytes do not match the expected digest or source identity | +| artifact_idempotency_conflict | 409 | Stable artifact operation identity was reused with different bytes or scope | +| artifact_verification_retry_ineligible | 409 | ART verification job is not exhausted provider_unavailable or is already queued/running | + +Internal uniqueness races MUST be translated into the corresponding stable conflict or idempotent success rather than leaking database errors. + +Authentication, authorization, domain-state, adapter-binding, and Artifact Storage failures MUST retain distinct codes. The API MUST NOT translate every denial into `not_found` or every dependency failure into a generic 500. + +--- + +## 20. Database Constraints and Indexes + +Required constraints: + +~~~text +ContributionRecord: + UNIQUE(source_review_id, contribution_type) + CHECK(contribution_type IN accepted_submission, completed_review) + source_submission_artifact_digest NOT NULL + +ContributionEvidenceProjection: + PRIMARY KEY(contribution_record_id) + CHECK(status IN pending, projected, failed) + CHECK(projected requires artifact_binding_id, content_digest, projected_at) + CHECK(pending or failed forbids projected_at) + +CompensationPolicyVersion: + UNIQUE(compensation_policy_id, version_number) + +CompensationPolicy: + partial UNIQUE(project_id) WHERE status = active + +CompensationRule: + UNIQUE(compensation_policy_version_id, contribution_type) + CHECK(compensation_mode IN compensated, unpaid) + +CompensationAwardDefinition: + UNIQUE(compensation_policy_version_id, contribution_type, instrument_type) + CHECK(quantity > 0) + +CompensationAward: + UNIQUE(contribution_record_id, instrument_type) + CHECK(quantity > 0) + +ProjectCompensationAdapterBinding: + partial UNIQUE(project_id, instrument_type) WHERE status = active + +CompensationFulfillmentReceipt: + UNIQUE(adapter_binding_id, external_event_id) + partial UNIQUE(compensation_award_id) WHERE reported_status = fulfilled + +CompensationStatusProjection: + PRIMARY KEY(compensation_award_id) + +TaskAssignment: + submitter_compensation_policy_version_id NOT NULL + +ReviewLease: + reviewer_compensation_policy_version_id NOT NULL + +~~~ + +The generic ArtifactBinding tables MUST enforce one verified `contribution_evidence_bundle` binding per `(contribution_record_id, projection_schema_version)` and the same project_id as the owner ContributionRecord. An ArtifactBinding from another owner, project or artifact role cannot satisfy a projection. + +Foreign keys MUST prevent project-chain mismatches. Composite foreign keys MUST be used where a single-column foreign key cannot express project ownership. Transaction-level validation remains additional defence and MUST NOT replace enforceable database ownership constraints. AuthorizationDecision references on sensitive audit/mutation records MUST point to an immutable WS-AUTH decision; bearer tokens are never stored. + +Required indexes: + +~~~text +ContributionRecord(contributor_id, recorded_at DESC, id DESC) +ContributionRecord(project_id, recorded_at DESC, id DESC) +ContributionRecord(project_id, task_id, recorded_at, id) +ContributionRecord(source_review_id, contribution_type) +ContributionEvidenceProjection(project_id, status, updated_at) +ContributionEvidenceProjection(status, last_attempt_at) + +CompensationPolicyVersion(project_id, status) +CompensationAward(contribution_record_id) +CompensationAward(project_id, created_at DESC) +CompensationAward(adapter_binding_id, created_at) + +CompensationFulfillmentReceipt(compensation_award_id, received_at) +CompensationStatusProjection(fulfillment_status, updated_at) + +Outbox(event_type, delivery_state, next_attempt_at) +~~~ + +All timestamps are stored in UTC. + +--- + +## 21. Concurrency and Idempotency + +### 21.1 Review-decision replay + +The WS-REV-001 decision idempotency key protects the entire combined transaction. + +Repeating the same committed decision request MUST return: + +- the existing Review; +- the existing reviewer Contribution Record; +- the existing submitter Contribution Record when decision = accept; +- the existing CompensationAwards; +- no new outbox events. + +Reusing the decision idempotency key with a different decision or payload returns 409 idempotency_mismatch. + +### 21.2 Concurrent decision attempts + +If two requests attempt to decide the same ReviewLease or Submission: + +- exactly one may create the Review; +- exactly one completed_review Contribution Record exists; +- at most one accepted_submission Contribution Record exists; +- award uniqueness follows the winning contribution records; +- the losing transaction returns the existing result only if it is an exact idempotent replay; otherwise it returns a conflict. + +### 21.3 Concurrent policy activation + +Project policy activation locks the project active-version reference. + +If two versions are activated concurrently: + +- exactly one becomes active first; +- the other transaction must re-evaluate and either replace it explicitly under its request semantics or fail with a version conflict; +- assignments and leases freeze one committed version, never a mixture. + +Activation endpoints MUST require expected_current_version_id. Null is supplied only when the project has no active version. + +### 21.4 Policy activation versus assignment + +Assignment and lease creation lock the same project active-version reference used by activation. + +The result is serializable at that boundary: + +- work freezes the old version before activation commits; or +- work freezes the new version after activation commits. + +Server request timing outside the transaction does not determine the version. + +### 21.5 Award duplication + +CompensationAward creation is part of the contribution transaction and protected by uniqueness constraints. + +An insert conflict caused by an exact replay resolves to the existing award. A conflict with different unit, quantity, policy version, or binding is an integrity error. + +### 21.6 Outbox delivery replay + +Outbox delivery is at-least-once. + +- The event_id and idempotency_key remain unchanged across retries. +- Delivery-attempt count and next-attempt time are operational metadata. +- A transient adapter failure does not create another CompensationAward or outbox event. +- After durable adapter acknowledgement, provider-side retries belong to the adapter. + +### 21.7 Concurrent callbacks + +Callback processing locks the CompensationAward or its status row. + +If failed and fulfilled callbacks race: + +- if fulfilled commits first, the failed callback is rejected; +- if failed commits first, the fulfilled callback may subsequently commit; +- final state is fulfilled. + +If two different fulfilled callbacks race, exactly one may create the unique fulfilled receipt. The other is rejected unless it is the exact idempotent replay of the winner. + +### 21.8 Callback before delivery acknowledgement + +A valid authenticated callback may be received before Workstream records local delivery acknowledgement. + +In that case: + +- accept and store the receipt; +- set fulfillment_status according to the receipt; +- set delivery_status to acknowledged_by_adapter because possession of the award instruction is proven; +- mark the associated outbox instruction delivered or suppress further delivery idempotently; +- never regress fulfilled state when a late dispatcher acknowledgement arrives. + +### 21.9 Authorization and mutation races + +Policy publication, binding mutation, outbox retry, projection rebuild, reconciliation and callback processing MUST evaluate AuthorizationService against canonical resources after those resources are loaded. Sensitive write transactions revalidate the decision after acquiring the rows whose state determines authority or domain validity. + +If a grant, service ActorProfile, identity link or binding becomes invalid before the write commits, the operation fails closed. A previously allowed router decision is not a perpetual capability and cannot authorize a later transaction after revocation. + +### 21.10 Contribution-evidence projection replay + +Decision replay returns the existing ContributionEvidenceProjection row and MUST NOT create another projection event. + +Projection delivery is at-least-once: + +- the worker always reloads canonical data; +- the same contribution id and projection schema version produce the same canonical serialization and digest; +- retry uses the same artifact operation identity and idempotency key; +- the same identity and digest resolves to the existing verified ArtifactBinding; +- the same identity with different bytes, owner, project, media type or scope is an integrity conflict; +- concurrent workers may produce at most one verified current projection for the contribution/schema version. + +An authorized rebuild to a later projection schema version creates a new deterministic storage identity and retains the prior ArtifactBinding for audit. It never rewrites an existing bundle. + +### 21.11 Artifact verification recovery + +WS-CON does not model provider recovery attempts. ART persists operation and +verification receipts. Only an exhausted `provider_unavailable` +ArtifactVerificationJob is operator-retry eligible through +`ArtifactOperatorRecoveryPort`; ART creates one ArtifactRecoveryAttempt and a +new retry ArtifactVerificationJob while leaving the exhausted source job +unchanged. The retry job's fixed `artifact.verification.execute` actor performs +execution. Exact replay returns the same attempt and retry-job ids. No CON executor, +lease, generation, provider-receipt lookup, or raw provider replay exists. + +--- + +## 22. Background Processing and Recovery + +### 22.1 Outbox dispatcher + +The dispatcher: + +- selects committed undelivered events; +- routes by adapter_binding_id and route_key; +- sends the exact persisted payload; +- records delivery attempts; +- retries transient failures using delay = min(300 seconds, 2 raised to attempt_number minus 1 seconds), plus uniformly distributed jitter from zero through ten percent of that delay; +- marks acknowledged only after a valid adapter 2xx response; +- preserves events until retention policy permits archival. + +It MUST NOT derive a new award quantity from current policy. + +Compensation delivery uses the bounded shared-outbox retry policy. Exhaustion +dead-letters the same immutable event and triggers the delayed-delivery alert; +reason-bound recovery requeues that event with its original payload and +idempotency identity. Tests prove no duplicate logical adapter effect. + +### 22.2 Contribution-evidence projection worker + +The worker consumes `ContributionEvidenceProjectionRequested` after commit and executes section 6.13 through ART-owned contribution-evidence capability. It runs under a provisioned Workstream system ActorProfile and uses least-privilege service scopes; it never impersonates the contributor or forwards the initiating human token. + +The worker MUST: + +- claim projection work idempotently; +- reload canonical records and authorized ArtifactBindings; +- serialize the versioned bundle deterministically; +- compute and retain the expected digest before storage; +- accept only the verified ArtifactBinding returned by ART; +- update the projection and audit/outbox records atomically after verified success; +- distinguish retryable availability failure, permanent canonical-integrity failure and uncertain provider outcome. + +### 22.3 Compensation status projection updater + +Projection updates happen synchronously in the same transaction that records adapter delivery acknowledgement or a fulfillment receipt. Projection rebuild remains an asynchronous recovery operation. + +The updater: + +- updates are idempotent; +- fulfilled cannot regress; +- the projection can be fully rebuilt; +- source receipts and delivery records remain authoritative. + +### 22.4 Reconciliation job + +The reconciliation job detects: + +- Review without required reviewer Contribution Record; +- accept Review without submitter Contribution Record; +- Contribution Record without ContributionRecorded outbox event; +- Contribution Record whose frozen policy version does not match its assignment or lease; +- award missing for a published definition; +- unexpected award for an unpaid contribution type; +- award without CompensationFulfillmentRequested; +- fulfilled projection without fulfilled receipt; +- fulfilled receipt whose quantity differs from award; +- multiple fulfilled receipts; +- adapter binding retired while referenced by an unfulfilled award; +- acknowledged delivery whose adapter binding does not match the award. +- Contribution Record without a pending or projected ContributionEvidenceProjection; +- Contribution Record without a ContributionEvidenceProjectionRequested outbox event; +- projected evidence row without one verified contribution_evidence_bundle ArtifactBinding; +- evidence bundle whose owner, project, source identity or digest differs from the canonical chain; +- a raw provider reference exposed by a public contribution read model. + +Reconciliation MUST alert operators and use explicit replay or compensating operational actions. It MUST NOT silently edit immutable Reviews, Contribution Records, awards, definitions, or receipts. + +### 22.5 Event replay + +Safe replay is allowed for: + +- rebuilding read projections; +- recreating a missing delivery attempt from an existing outbox event; +- re-delivering an unacknowledged event with the same identifiers; +- recreating a missing mutable status projection from authoritative records. +- re-running contribution evidence projection from the canonical ContributionRecord chain with the same schema version and operation identity; +- rebuilding a later evidence schema version under an authorized projection-rebuild operation. + +Replay MUST NOT create a second logical Contribution Record, award, fulfilled receipt, or bundle for the same contribution/schema version. + +### 22.6 Artifact recovery + +Recovery is entirely ART-owned. An authorized Operator may retry only an +exhausted `provider_unavailable` ArtifactVerificationJob through +`ArtifactOperatorRecoveryPort.retry_verification`. ART records the request, +creates one ArtifactRecoveryAttempt and a new retry ArtifactVerificationJob, +and leaves the exhausted source job unchanged. Exact replay returns the same +attempt/retry ids; only the retry job executes under the fixed verification +service actor. WS-CON observes the resulting binding/verification +state and never owns an artifact recovery row or provider operation. + +### 22.7 Adapter suspension + +When a binding is suspended: + +- existing awards remain valid; +- undelivered events remain pending; +- no award is cancelled; +- Review decisions and contribution creation continue if the policy version was already frozen; +- new policy publication cannot select the suspended binding; +- new TaskAssignments or ReviewLeases cannot freeze a current policy that depends on a suspended binding. + +Existing assignments and leases are honored because contributors began work under frozen terms. Delivery resumes when the same logical binding is reactivated. + +--- + +## 23. Audit Events + +The following event types are required. + +### Policy + +- CompensationPolicyCreated +- CompensationPolicyVersionDrafted +- CompensationPolicyVersionPublished +- CompensationPolicyVersionActivated +- CompensationPolicyVersionRetired +- CompensationAwardDefinitionCreated +- ProjectCompensationAdapterBound +- ProjectCompensationAdapterSuspended +- ProjectCompensationAdapterResumed +- ProjectCompensationAdapterRetired + +### Frozen terms + +- CompensationTermsFrozenForAssignment +- CompensationTermsFrozenForReviewLease + +### Contribution + +- ReviewerContributionRecorded +- SubmitterContributionRecorded +- ContributionRecorded +- ContributionEvidenceProjectionRequested +- ContributionEvidenceProjected +- ContributionEvidenceProjectionFailed +- ContributionEvidenceProjectionReconciled +- ContributionEvidenceAccessed +- ContributionEvidenceUnavailable +- ContributionEvidenceIntegrityMismatch + +### Award and delivery + +- CompensationAwardCreated +- CompensationFulfillmentRequested +- CompensationFulfillmentDeliveryAttempted +- CompensationFulfillmentDeliveryAcknowledged +- CompensationFulfillmentDeliveryFailed + +### Callback + +- CompensationFulfillmentReported +- CompensationFulfilled +- CompensationFulfillmentFailed +- CompensationFulfillmentCallbackRejected +- CompensationFulfillmentCallbackReplayed + +### Artifact recovery + +- ART-owned recovery attempt/retry-job ids and status may be linked as external + operational evidence; WS-CON emits no artifact-recovery lifecycle event. + +Every audit event records: + +~~~yaml +event_id: uuid +event_type: string +occurred_at: timestamp +actor_id: actor_id | system_actor_id +authorization_decision_id: uuid | null + +project_id: uuid +contributor_id: uuid | null +task_id: uuid | null +review_id: uuid | null +review_lease_id: uuid | null +contribution_record_id: uuid | null +compensation_award_id: uuid | null +compensation_policy_version_id: uuid | null +adapter_binding_id: uuid | null +artifact_binding_id: uuid | null +artifact_operation_id: uuid | null +artifact_recovery_attempt_id: uuid | null + +correlation_id: string +causation_event_id: uuid | null +reason_code: string | null +metadata: object +~~~ + +Audit metadata MUST redact credentials and sensitive financial data. + +Sensitive human and service mutations record the exact WS-AUTH AuthorizationDecision id, permission, canonical scope and policy version by reference. Audit records MUST NOT persist bearer tokens, Artifact Storage service credentials, raw provider URLs, or full evidence-bundle contents. + +--- + +## 24. Notifications and Operational Views + +Notification transport is an adapter concern. Workstream emits events sufficient to notify: + +- contributor that a submission contribution was recorded; +- reviewer that a review contribution was recorded; +- contributor of the compensation instruments authorized; +- Admin that adapter delivery is delayed; +- contributor or Admin that fulfillment was reported failed; +- contributor that fulfillment was reported completed; +- Admin that policy or adapter binding is missing or suspended. +- authorized Operator that an exhausted provider-unavailable artifact verification job is retry eligible through ART. + +### 24.1 Contributor view + +Must show: + +- global contribution history; +- project filter; +- contribution type and source task; +- recorded time; +- compensation awarded per instrument; +- pending, failed, or fulfilled status from the projection; +- contribution-evidence projection status and an authorized Workstream evidence reference when projected; +- external reference only when permitted by data policy. + +It MUST NOT imply that adapter acknowledgement means fulfillment. + +### 24.2 Project Admin view + +Must show: + +- active compensation version; +- historical frozen versions; +- assignment and lease counts by frozen version; +- contribution counts by type; +- awards by instrument and unit; +- oldest pending-delivery age; +- oldest pending-fulfillment age; +- failed fulfillment count and failure codes; +- adapter binding health and suspension state. +- contribution-evidence projection completion/failure counts and oldest pending age. + +### 24.3 Finance Authority view + +Within authorized project scope, Finance Authority may read: + +- monetary award totals; +- monetary awards by fulfillment status; +- policy versions containing money; +- money-adapter delivery health; +- external references returned by the authorized adapter. + +Workstream does not provide provider balances, payout batches, or settlement ledgers. + +### 24.4 Audit Authority and authorized reputation-consumer view + +Within covered scope, Audit Authority may read the attributable contribution, authorization, compensation and evidence-projection chain. An external reputation service consumes only the authorized `ContributionRecorded` event contract; it is a service consumer, not a human Admin role. + +The allowed view includes: + +- Contribution Records; +- contribution types; +- source Reviews and provenance; +- ContributionRecorded event delivery status to the reputation consumer. +- contribution-evidence projection status and audit references, without raw provider authority. + +Compensation fulfillment is not a reputation input. + +Every operational and aggregate view is filtered after AuthorizationService evaluates the canonical project/system scope. Unauthorized rows are excluded before counts, totals, oldest-age calculations or failure-code aggregation. + +--- + +## 25. Observability + +Required metrics: + +~~~text +workstream_contributions_created_total{project_id, contribution_type} +workstream_contribution_transaction_failures_total{reason} +workstream_compensation_awards_created_total{project_id, instrument_type, unit_code} +workstream_compensation_award_quantity_total{project_id, instrument_type, unit_code} +workstream_compensation_outbox_pending_total{adapter_binding_id} +workstream_compensation_outbox_oldest_seconds{adapter_binding_id} +workstream_compensation_delivery_attempts_total{adapter_binding_id, result} +workstream_compensation_fulfillment_callbacks_total{adapter_binding_id, status, result} +workstream_compensation_pending_fulfillment_total{project_id, instrument_type} +workstream_compensation_pending_fulfillment_oldest_seconds{project_id, instrument_type} +workstream_compensation_reconciliation_violations_total{type} +workstream_contribution_authorization_decisions_total{permission, result, reason_code} +workstream_contribution_evidence_projection_total{result, error_code} +workstream_contribution_evidence_projection_lag_seconds{project_id} +workstream_contribution_evidence_retrieval_total{result} +workstream_contribution_evidence_unavailable_total{reason} +workstream_contribution_evidence_integrity_mismatch_total{type} +workstream_contribution_artifact_recovery_total{result} +~~~ + +Required tracing attributes: + +- correlation_id; +- project_id; +- task_id; +- review_id; +- contribution_record_id; +- compensation_award_id; +- adapter_binding_id; +- event_id; +- authorization_decision_id; +- artifact_binding_id; +- artifact_operation_id; +- projection_schema_version. + +Logs MUST NOT contain bearer tokens, credentials, private keys, bank details, or full provider payloads containing sensitive data. + +Suggested alerts: + +- outbox oldest age exceeds project operational threshold; +- adapter delivery failure rate exceeds threshold; +- fulfillment callback rejection spikes; +- reconciliation detects any missing contribution or duplicate fulfilled receipt; +- an active policy loses a usable adapter binding; +- monetary awards remain pending beyond project service target; +- contribution-evidence projection lag exceeds the configured service target; +- any contribution-evidence integrity mismatch occurs; +- any ART verification retry remains exhausted or fails integrity checks; +- authorization denials or callback-actor mismatches spike unexpectedly. + +--- + +## 26. Security Requirements + +1. Verify Identity Issuer tokens and resolve the current ActorProfile/identity link on every protected human and service request. +2. Use WS-AUTH-001 AuthorizationService for every registered action; local role-name conditionals are prohibited. +3. Derive project and record scope from canonical Workstream rows, not request paths, query filters, event payloads or callback fields. +4. Require Finance Authority and the exact granular `compensation.policy.*` action from WS-AUTH-001 for every compensation-policy mutation, whether money, project points or unpaid. +5. Require Finance Authority and the exact granular `compensation.adapter_binding.*` action from WS-AUTH-001 for every adapter-binding mutation. +6. Never allow a human actor to create, edit, fulfill or delete ContributionRecords, CompensationAwards or fulfillment receipts. +7. Bind callbacks to an active service ActorProfile, `compensation.fulfillment.report`, and the exact frozen adapter actor, project, instrument and award. +8. Treat callback and external adapter payloads as untrusted input. +9. Use exact decimal parsing with bounded length and precision. +10. Reject reported_at or fulfilled_at more than five minutes ahead of database time. A fulfilled_at value must not be more than five minutes later than reported_at. +11. Enforce request-body size limits and rate-limit callback endpoints per adapter actor. +12. Store adapter and Artifact Storage credentials outside domain tables. +13. Sign or mutually authenticate adapter delivery in addition to service identity where deployment policy requires it. +14. Prevent insecure direct-object references in contribution, award, receipt, audit and evidence endpoints. +15. Re-authorize every Artifact Storage search candidate against its canonical ContributionRecord before disclosure. +16. Human bearer tokens MUST NOT cross the Workstream boundary. Artifact Storage and compensation adapters receive separate service credentials/scopes. +17. Artifact Storage service scopes MUST be least-privilege and bind project, owner, operation, artifact role and expiry where the provider supports those fields. +18. Verify contribution-evidence digest, source identity, project ownership, artifact role, media type and operation identity before creating an ArtifactBinding. +19. Do not expose artifact bytes through list endpoints or expose raw CIDs, arbitrary URLs, filesystem paths, credentials or provider capabilities as authority. +20. Redact external failure messages before showing them to contributors. +21. Preserve immutable, attributable audit evidence for authorization, policy publication, award creation, delivery, callbacks, evidence projection, access and recovery. +22. Treat money and project-points fulfillment events as economically sensitive messages. +23. Treat contribution evidence as project-confidential unless the project's explicit disclosure policy grants a broader authorized view. +24. A storage or adapter outage MUST fail the dependent projection/delivery operation without weakening authorization or mutating canonical contribution history. + +--- + +## 27. End-to-End Reference Sequences + +### 27.1 Accepted submission with paid reviewer and paid submitter + +~~~text +1. TaskAssignment created under CompensationPolicyVersion P1 + - submitter terms frozen to P1 +2. Submission v1 passes checkers and enters review queue +3. Reviewer claims under current policy P1 + - ReviewLease terms frozen to P1 +4. Reviewer records accept; AuthorizationService allows `review.decision` for the locked lease/task scope +5. One transaction: + - Review accept created + - lease consumed and queue closed + - Task.status -> accepted + - TaskAssignment.status -> completed + - reviewer completed_review ContributionRecord created + - reviewer awards created from P1 completed_review rules + - submitter accepted_submission ContributionRecord created + - submitter awards created from P1 accepted_submission rules + - one pending ContributionEvidenceProjection and projection event per ContributionRecord + - contribution, award, fulfillment and projection outbox events created + - commit +6. Evidence worker builds deterministic reviewer/submitter bundles and stores them through ART-owned contribution-evidence capability +7. Adapter deliveries occur after commit +8. Money and points adapters acknowledge independently +9. Each bound service actor is authorized and later reports fulfilled or failed +10. Workstream stores receipts and updates read projections +~~~ + +### 27.2 Needs revision with reviewer compensation + +~~~text +1. Reviewer records needs_revision with required findings +2. One transaction: + - Review created + - task -> needs_revision + - reviewer completed_review ContributionRecord created + - reviewer awards created independent of decision + - no submitter Contribution Record + - commit +3. Contributor submits v2 +4. v2 is reviewed later +5. That later valid Review creates another reviewer Contribution Record +~~~ + +### 27.3 Reject with reviewer compensation + +~~~text +1. Reviewer records reject +2. One transaction: + - Review reject created + - reviewer completed_review ContributionRecord and awards created + - submitter TaskAssignment blocked + - task closed + - no submitter Contribution Record + - commit +3. Reviewer compensation proceeds through external adapter +~~~ + +### 27.4 Explicitly unpaid project + +~~~text +1. Project has active published unpaid policy +2. Reviewer records accept +3. Reviewer and submitter Contribution Records are created +4. No CompensationAwards are created +5. ContributionRecorded events still feed reputation and history +~~~ + +### 27.5 Money plus project points + +~~~text +completed_review ContributionRecord + -> money award USD 1.25 -> money adapter + -> project points award REVIEW_POINT 5 -> points adapter + +money callback -> fulfilled +points callback -> failed + +read view: + money = fulfilled + points = failed + contribution remains permanently recorded +~~~ + +### 27.6 Adapter failure followed by success + +~~~text +1. Adapter acknowledges award instruction +2. Adapter reports failed with external_event_id F1 +3. Workstream stores failed receipt; projection -> failed +4. Adapter retries provider work internally +5. Adapter reports fulfilled with external_event_id F2 +6. Workstream stores fulfilled receipt; projection -> fulfilled +7. A later failed callback is rejected +~~~ + +### 27.7 Policy changes during existing work + +~~~text +1. TaskAssignment freezes P1 +2. Reviewer R1 claims and freezes P1 +3. Project activates P2 +4. R1 completes review: + - reviewer award uses P1 + - accepted submitter award uses TaskAssignment P1 +5. Reviewer R2 claims later: + - R2 lease freezes P2 +6. No existing object is rewritten +~~~ + +### 27.8 Duplicate decision and duplicate callback + +~~~text +1. Decision request commits Review, contributions, awards, and events +2. Same idempotency key and payload is retried +3. Existing complete result is returned; no duplicate records +4. Adapter callback commits one receipt +5. Same external_event_id and payload is retried +6. Existing receipt is returned with 200 +~~~ + +### 27.9 Authorized contribution-evidence retrieval + +~~~text +1. Caller requests the self or project-scoped contribution evidence route with Identity Issuer token +2. AuthorizationService allows contribution.read_self or contribution.read_project on canonical record +3. Workstream validates the projected ArtifactBinding owner, project, role and digest +4. Workstream retrieves through ART-owned contribution-evidence capability using a separate least-privilege service scope +5. Digest is verified and attributable access is recorded +6. Approved bundle representation is returned +7. Raw provider authority and the caller token are never forwarded or exposed +~~~ + +### 27.10 Storage outage and uncertain recovery + +~~~text +1. Review transaction commits Review, contributions, awards and pending evidence projections +2. Artifact Storage is unavailable; projection retry fails +3. Review, ContributionRecords and CompensationAwards remain valid +4. An exhausted provider_unavailable verification job becomes retry eligible +5. Authorized Operator requests retry through ART's typed recovery port +6. ART creates one recovery attempt and a new retry verification job while leaving the exhausted source job unchanged +7. Verified success supplies the binding; continued failure remains ART state +8. No WS-CON canonical lifecycle fact is rewritten +~~~ + +--- + +## 28. Conformance Tests + +An implementation is not conformant until all applicable tests pass against PostgreSQL and the real API transaction boundary. + +### 28.1 Policy tests + +1. Project without an active policy cannot create a TaskAssignment. +2. Project without an active policy cannot create a ReviewLease. +3. Explicit unpaid policy allows work and creates no awards. +4. Draft policy may be edited by Finance Authority with an allowed `compensation.policy.update_draft` decision for the canonical version. +5. Published policy cannot be edited. +6. Retired policy cannot be edited. +7. Money policy cannot be published by Project Manager, Operator, Access Administrator, Audit Authority or Contributor. +8. Points-only and explicitly unpaid policies have the same Finance Authority requirement; Project Manager cannot publish them. +9. Duplicate money definition for one contribution type is rejected. +10. Duplicate points definition for one contribution type is rejected. +11. Zero or negative quantity is rejected. +12. Floating-point JSON quantity is rejected when the API requires a decimal string. +13. Invalid currency code is rejected. +14. Fractional project points are rejected. +15. Definition using another project's binding is rejected. +16. Dynamic outcome, contributor, task, skill, tier, or reputation condition is rejected. +17. Concurrent activation produces one deterministic active version. +17a. Router-level role state without a transaction-time AuthorizationDecision cannot publish or retire a version. +17b. Revoked Finance Authority fails closed before policy mutation commits. +17c. Cross-project policy or adapter-binding path substitution is denied from canonical ownership. +17d. Finance Authority can create, suspend, resume and retire a valid project binding; Project Manager and Operator cannot. + +### 28.2 Freeze tests + +18. TaskAssignment stores the active version at creation. +19. ReviewLease stores the active version at claim. +20. Later activation does not change existing assignment. +21. Later activation does not change existing lease. +22. New assignment after activation uses the new version. +23. New lease after activation uses the new version. +24. Retired frozen version remains usable at decision time. +25. Suspended binding prevents new work from freezing a dependent current policy. +26. Existing frozen work remains recognizable while binding is suspended. +26a. TaskAssignment freeze is reached only after the upstream `task.claim` authorization succeeds. +26b. ReviewLease freeze is reached only after the upstream `review.claim` authorization succeeds. +26c. Binding suspension permits a valid callback for an already-issued award but prevents new delivery and new frozen work. + +### 28.3 Contribution tests + +27. Accept creates exactly one reviewer contribution. +28. Accept creates exactly one submitter contribution. +29. Needs revision creates exactly one reviewer contribution and no submitter contribution. +30. Reject creates exactly one reviewer contribution and no submitter contribution. +31. Review decision does not change reviewer award quantity. +32. Second completed revision review creates a second reviewer contribution. +33. Released lease creates no contribution. +34. Expired lease creates no contribution. +35. Revoked lease creates no contribution. +36. Automated checker result creates no Contribution Record. +37. Contribution project, task, assignment, submission, Review, and contributor chain must match. +38. Contribution Record cannot be updated. +39. Contribution Record cannot be deleted. +40. Global contributor view returns records from authorized projects. +41. Project filter returns only that project. +41a. Every ContributionRecord creates exactly one pending ContributionEvidenceProjection in the same transaction. +41b. Every ContributionRecord creates exactly one ContributionEvidenceProjectionRequested outbox event. +41c. Contribution source_submission_artifact_digest equals the judged Submission digest. +41d. A completed-review contribution identifies the reviewed submission; it does not invent a reviewer-upload artifact. + +### 28.4 Atomicity and idempotency tests + +42. Failure creating reviewer contribution rolls back Review. +43. Failure creating submitter contribution rolls back accept Review. +44. Failure creating an award rolls back Review and all contributions. +45. Failure writing an outbox event rolls back Review, contributions, and awards. +46. External adapter outage does not roll back committed Review. +47. Exact decision replay returns existing Review, contributions, and awards. +48. Changed payload with reused decision idempotency key is rejected. +49. Concurrent decision attempts create one Review and one logical set of contributions. +50. Award uniqueness prevents duplicates under replay. +50a. Failure creating a pending evidence-projection row rolls back the Review transaction. +50b. Failure writing the evidence-projection outbox event rolls back the Review transaction. +50c. Artifact Storage outage after commit does not roll back Review, contributions or awards. +50d. Exact decision replay returns existing projection rows and creates no new projection event. + +### 28.5 Compensation evaluation tests + +51. Completed-review money award is copied exactly from frozen definition. +52. Completed-review points award is copied exactly from frozen definition. +53. Accepted-submission awards use TaskAssignment frozen version. +54. Reviewer awards use ReviewLease frozen version. +55. One contribution can create money and points awards independently. +56. Unpaid contribution creates zero awards. +57. Current project policy is never consulted instead of frozen reference. +58. Missing frozen version fails with integrity error and commits nothing. +59. Money award carries project_id and project binding. +60. Same points unit text in different projects remains separately scoped. + +### 28.6 Delivery tests + +61. CompensationFulfillmentRequested is committed with each award. +62. Dispatcher sends exact persisted payload. +63. Retry preserves event_id and idempotency_key. +64. Non-2xx adapter response leaves event unacknowledged. +65. 2xx acknowledgement marks delivery acknowledged but fulfillment pending. +66. Repeated delivery does not create another award. +67. Suspended binding pauses delivery without cancelling award. +67a. Finance Authority or operational Operator with `compensation.delivery.reconcile` may request eligible delivery reconciliation in covered scope. +67b. Project Manager, Contributor and foreign-project Admin are denied delivery reconciliation. +67c. Reconciliation reuses the existing event_id, payload, adapter binding and idempotency key and cannot mark acknowledgement or fulfillment. + +### 28.7 Callback tests + +68. Active bound service ActorProfile with `compensation.fulfillment.report` may report its own award. +69. Invalid Identity Issuer token is rejected. +70. Money adapter cannot report points award. +71. Project A adapter cannot report Project B award. +72. Unknown award is rejected. +73. Fulfilled callback requires external reference, quantity, and timestamp. +74. Fulfilled quantity must exactly equal award quantity. +75. Partial fulfillment is rejected. +76. Failed callback requires failure code. +77. Failed callback creates immutable receipt. +78. Failed followed by fulfilled is allowed. +79. Fulfilled followed by failed is rejected. +80. Exact callback replay returns existing receipt. +81. Reused external_event_id with different payload is rejected. +82. Concurrent fulfilled callbacks produce one fulfilled receipt. +83. Callback does not mutate Contribution Record. +84. Callback does not mutate CompensationAward. +85. Valid callback before delivery acknowledgement does not regress later. +85a. Human Admin, contributor, unprovisioned service actor, disabled actor and revoked identity link cannot report fulfillment. +85b. Valid service actor bound to another project or instrument is denied. +85c. Suspended binding may report an existing award it previously accepted, but cannot receive new delivery. +85d. Retired binding accepts only exact replay of an already accepted receipt. +85e. Accepted callback audit chain references the exact AuthorizationDecision. +85f. Callback request project, contributor, instrument, quantity or binding fields cannot grant or alter authority. + +### 28.8 Read and recovery tests + +86. Contribution detail composes award status without modifying canonical record. +87. Projection can be rebuilt from awards, delivery records, and receipts. +88. Reconciliation detects accepted Review missing submitter contribution. +89. Reconciliation detects Review missing reviewer contribution. +90. Reconciliation detects missing award. +91. Reconciliation detects unexpected award for unpaid policy. +92. Reconciliation detects missing fulfillment event. +93. Reconciliation detects projection/receipt mismatch. +94. Reconciliation never silently edits immutable records. +95. Binding retirement is rejected while an active policy, unfinished frozen work, or unfulfilled award depends on it. +96. Retiring the active policy without replacement clears the project active-version reference and blocks new work. +97. No cross-project Admin contributor-history or contributor-award endpoint exists in v0.1. +98. `contribution.read_self` returns only the caller's ContributionRecords and composed award summaries. +99. `contribution.read_project` filters rows, counts, totals and ages to covered canonical project scope. +100. `compensation.award.read_project` is required for project award detail. +101. Unauthorized contribution/evidence IDs do not reveal record existence. +102. Projection worker reloads canonical data rather than trusting the projection event payload. +103. Same contribution/schema version produces identical canonical bytes and digest under repeated generation. +104. LocalStorage focused tests and MinIO S3-protocol conformance pass the same evidence-projection contract used by AWS S3 production. +105. ART capability result with wrong owner, project, source identity, artifact role, media type or digest is rejected. +106. Same artifact operation identity and bytes resolves to one verified ArtifactBinding. +107. Same artifact operation identity with changed bytes returns `artifact_idempotency_conflict` and binds nothing. +108. Contribution-list responses expose only evidence status and Workstream ArtifactBinding ID, not raw provider authority. +109. Authorized evidence retrieval verifies digest and creates an attributable access audit record. +110. Human Identity Issuer token is never forwarded to Artifact Storage or compensation adapters. +111. Artifact Storage outage returns the stable evidence error without changing contribution or compensation state. +112. Reconciliation detects missing projection row, missing event, invalid binding and digest mismatch. +113. Authorized rebuild to a newer schema version retains the prior immutable bundle. +114. Only exhausted provider_unavailable verification jobs are retry eligible. +115. Equivalent retry requests return the same ART recovery-attempt and retry-job ids; the exhausted source job is unchanged. +116. Non-eligible job status or failure class is denied without mutation. +117. WS-CON never persists an artifact recovery executor, lease, generation, or provider receipt. +118. ART verification retry cannot create a second logical ArtifactBinding. +119. Continued verification failure changes no ContributionRecord or award truth. +120. Operator requester identity never becomes artifact execution authority. +120a. The same outbox/idempotency/recovery contract passes under LocalStorage and MinIO; recovery is not skipped merely because storage is local. + +--- + +## 29. Implementation Delivery Order + +### Phase 0: Dependency contracts and authority catalogue + +- confirm WS-AUTH-001 ActorProfile, AuthorizationDecision and canonical resource-context interfaces; +- register the section 5.4 granular ActionIds through an AUTH-owned chunk and + map them to the listed stable PermissionIds; +- add the service-only `outbox.dispatch` and + `compensation.fulfillment.report` PermissionIds and exact service-action + assignments through AUTH; neither is currently registered; +- reuse the canonical `artifact.verification_job.retry` and + `artifact.verification.execute` actions through ART-owned capabilities; +- extend the existing `artifact.binding.create` resource mapping to ContributionRecord for the fixed projection system actor and `contribution_evidence_bundle` role; +- confirm updated WS-REV-001 Review, ReviewFinding, FindingResolution, Submission, ReviewLease and ArtifactBinding contracts; +- freeze the shared provider-independent ART-owned contribution-evidence capability conformance contract; +- add contract tests that prevent local role-name checks, human-token forwarding and raw provider-reference disclosure. + +### Phase 1: Schema and immutable policy model + +- CompensationPolicy and version tables; +- CompensationRule; +- award definitions; +- adapter bindings; +- frozen references on TaskAssignment and ReviewLease; +- ContributionRecord; +- CompensationAward; +- FulfillmentReceipt; +- status projection; +- ContributionEvidenceProjection; +- constraints and indexes. + +### Phase 2: Policy and binding APIs + +- draft creation and validation; +- WS-AUTH permission/resource enforcement and immutable decision linkage; +- publish/activate/retire transaction; +- adapter binding lifecycle; +- explicit unpaid policy; +- concurrency guards. + +### Phase 3: Freeze integration + +- TaskAssignment freeze; +- ReviewLease freeze; +- policy-change concurrency tests; +- legacy-data migration guard; +- suspended-binding behaviour. + +### Phase 4: Atomic Review integration + +- reviewer contribution for all decisions; +- submitter contribution for accept; +- deterministic award evaluation; +- outbox events; +- pending evidence projections and evidence-projection outbox events; +- exact decision replay; +- rollback and race tests; +- removal of ContributionRecordRequested emission. + +### Phase 5: External adapter boundary + +- outbox routing; +- delivery acknowledgement; +- callback authentication and authorization; +- exact bound service-actor permission evaluation; +- immutable receipts; +- status projection; +- conflict and idempotency handling. + +### Phase 6: Contribution evidence projection and authorized retrieval + +- deterministic versioned evidence-bundle generator; +- ART-owned contribution-evidence capability with LocalStorage focused-test and MinIO S3-protocol conformance; +- verified generic ArtifactBinding creation; +- authorized evidence retrieval and attributable access audit; +- ART verification-job retry and projection reconciliation; +- no search-result disclosure before Workstream reauthorization. + +### Phase 7: Read APIs and operations + +- global and project-filtered contribution views; +- compensation summaries; +- Admin operational views; +- metrics, tracing, alerts; +- reconciliation and projection rebuild. + +### Phase 8: Live API drill + +The drill MUST prove at minimum: + +1. paid accept producing reviewer and submitter contributions; +2. needs revision producing reviewer contribution only; +3. reject producing reviewer contribution only; +4. explicit unpaid policy; +5. policy change with frozen old and new work; +6. money and project-points awards from one contribution; +7. adapter acknowledgement without fulfillment; +8. failed callback followed by fulfilled callback; +9. exact decision and callback replay; +10. adapter outage with eventual delivery; +11. database evidence for atomicity and uniqueness; +12. projection rebuild and reconciliation. +13. Finance-only policy and binding mutation with Project Manager and Operator denials; +14. exact bound service-actor callback and human/foreign-adapter denials; +15. reviewer and submitter evidence-bundle projection through the configured ART-owned contribution-evidence capability; +16. storage outage after contribution commit with canonical records unchanged; +17. authorized evidence retrieval with digest verification and attributable access; +18. ART recovery creates one attempt and new retry job while leaving the exhausted source job unchanged; +19. LocalStorage focused-test and MinIO S3-protocol conformance evidence. + +The drill report must clearly separate observed runtime proof from specification claims. + +--- + +## 30. Definition of Done + +WS-CON-001 is implemented only when: + +- every valid Review creates exactly one reviewer Contribution Record; +- accept additionally creates exactly one submitter Contribution Record; +- no other outcome creates a submitter Contribution Record; +- review compensation is identical across accept, needs_revision, and reject under the same frozen policy; +- TaskAssignment and ReviewLease freeze immutable policy versions; +- policy replacement cannot alter existing work; +- explicit unpaid policy works without missing configuration; +- Contribution Records and CompensationAwards are immutable; +- money and project points remain project-scoped; +- Contribution Records remain globally addressable and project-filterable; +- Review, contribution, awards, and outbox events commit atomically; +- one pending ContributionEvidenceProjection and projection event commit atomically with every ContributionRecord; +- every protected human/service operation uses WS-AUTH-001 with the canonical resource context and immutable decision linkage; +- Finance Authority alone manages compensation policy and adapter bindings in v0.1; +- fulfillment callbacks require the exact bound active service actor and `compensation.fulfillment.report`; +- adapter outage cannot invalidate a committed Review; +- delivery acknowledgement and fulfillment are represented separately; +- callbacks are authenticated, authorized, idempotent, and exact-quantity; +- failed may become fulfilled, while fulfilled is terminal; +- fulfillment receipts are immutable; +- read projections are rebuildable; +- provider-specific payment and points internals are absent from Workstream; +- deterministic contribution-evidence bundles are stored only through the shared ART-owned contribution-evidence capability; +- LocalStorage, MinIO, and AWS S3 satisfy the same Workstream evidence contract at their approved environment boundaries; +- public responses expose Workstream ArtifactBinding references, never raw provider authority; +- authorized evidence reads verify integrity, recheck scope and create attributable access records; +- storage failure and uncertain recovery cannot rewrite canonical Review, contribution or compensation facts; +- human tokens are never forwarded to Artifact Storage or compensation adapters; +- all conformance tests pass; +- the live drill captures authorization, API, database, event, artifact, retry, recovery, callback, and audit evidence. + +--- + +## 31. Explicitly Out of Scope + +The coding agent MUST NOT implement any of the following under WS-CON-001: + +- payment-request objects; +- payment-attempt objects; +- payment-provider SDK logic; +- bank, wallet, card, stablecoin, x402, or settlement execution; +- payout batching; +- balances or account statements; +- KYC or beneficiary onboarding; +- finance-approval workflow inside Workstream; +- provider retry or provider reconciliation logic; +- project-points ledger; +- point balances or transfers; +- Workstream-wide points; +- credits or credit ledger; +- token issuance; +- compensation tiers; +- task-specific compensation overrides; +- contributor-specific rates; +- skill- or reputation-derived rates; +- bonuses, penalties, multipliers, or dynamic formulas; +- partial fulfillment; +- currency conversion; +- reputation score calculation; +- reputation aggregate maintenance; +- automated reviewer-role grants; +- adjudication or second-level review; +- contribution reversal, voiding, or adjustment; +- retroactive policy application; +- mutation or deletion of canonical Contribution Records, awards, or receipts; +- a second contribution-specific artifact store; +- direct Local Storage, Flow Node, filesystem or CID calls outside ART-owned contribution-evidence capability; +- treating Artifact Storage as the canonical source for a ContributionRecord, Review, award or fulfillment result; +- public raw provider URLs, CIDs, filesystem paths or provider capability tokens; +- forwarding human Identity Issuer tokens to Artifact Storage or compensation adapters; +- adding a semantic-search disclosure path in v0.1; +- changing canonical contribution history because ART verification or evidence + read failed; +- Operator ownership or cross-Operator takeover of artifact-recovery execution leases; +- unrelated product architectures. + +External adapters may later connect to those systems, but this specification defines only the Workstream-facing contract. + +--- + +## 32. Future Additive Directions + +The following may be designed later through separate specifications: + +- provider-specific money adapters; +- project-points service and ledger; +- credits and other compensation instruments; +- finance approval adapters; +- task-category and compensation-tier policy rules; +- bonuses or quality incentives based on independently verified evidence; +- partial fulfillment; +- compensation adjustment and reversal records; +- adjudication and audit review; +- Workstream-wide economic reporting; +- reputation scoring and project-to-global aggregation; +- automated ProjectRoleGrant policy; +- external evidence publication. + +Future additions MUST preserve: + +- original Contribution Records; +- original CompensationAwards; +- frozen policy references; +- original fulfillment receipts; +- decision-neutral base reviewer compensation; +- project scope; +- event idempotency. + +--- + +## 33. Coding-Agent Handoff Rules + +The coding agent MUST follow these rules without reinterpretation: + +1. Implement this specification as an extension of WS-REV-001, not as a separate competing lifecycle. +2. Replace the temporary ContributionRecordRequested seam with direct atomic creation. +3. Keep the combined Review transaction short and database-local. +4. Do not call external adapters inside the Review transaction. +5. Do not use current project policy when a frozen assignment or lease version exists. +6. Do not derive reviewer compensation from Review.decision. +7. Do not create submitter contribution for needs_revision or reject. +8. Do not create contribution for an incomplete lease. +9. Do not store fulfillment state on ContributionRecord or CompensationAward. +10. Do not build payment, point-ledger, credit, or provider domain models. +11. Use exact decimal types and decimal-string API fields. +12. Enforce uniqueness in PostgreSQL, not only application code. +13. Require idempotency for Review decisions, event consumers, adapter delivery, and callbacks. +14. Treat external adapter payloads as untrusted. +15. Preserve project scope on every economic record and event. +16. Keep global contribution views as queries/read models, not a second global ledger. +17. Use append-only receipts and rebuildable projections. +18. Never silently repair immutable history. +19. Add no adjudication, appeal, reversal, or adjustment path. +20. Add no conditional compensation rule beyond exact contribution_type matching. +21. If existing code conflicts with a MUST rule, stop and raise the conflict before weakening the specification. +22. Completion requires conformance tests and a live API drill report; code compilation alone is insufficient. +23. Use WS-AUTH-001 AuthorizationService for every protected action; do not add local role-name checks or a second permission system. +24. Finance Authority alone manages compensation policy and adapter bindings in v0.1. +25. Require `compensation.fulfillment.report` from the exact frozen adapter service actor; no human role can satisfy a callback. +26. Load canonical resource ownership before authorization and revalidate sensitive writes inside the transaction. +27. Create one pending ContributionEvidenceProjection and event with every ContributionRecord. +28. Generate evidence asynchronously from canonical committed records; never trust the projection event as independent truth. +29. Use the shared ART-owned contribution-evidence capability and generic ArtifactBinding contract; do not import provider internals or create another byte store. +30. Never forward human tokens to Artifact Storage or compensation adapters. +31. Never expose raw provider CIDs, paths, URLs, credentials or search candidates as authority. +32. Treat LocalStorage as focused dev/test, MinIO as local/CI S3 protocol proof, and AWS S3 as production; keep R2 and Flow Node deferred. +33. Keep artifact projection/retrieval failure separate from contribution and compensation validity. +34. Delegate artifact recovery to ART: one recovery attempt creates a new retry verification job, exact replay returns the same ids, and the source job never changes. +35. Link policy, binding, callback, read, recovery and projection operations to immutable AuthorizationDecision and audit records without storing bearer tokens. +36. Register granular ActionIds in WS-AUTH-001 and map them to the canonical stable PermissionIds, including `compensation.policy.manage`, `compensation.adapter_binding.manage`, `operations.reconcile.run`, `operations.outbox.retry`, and `review.decision`; do not treat those PermissionIds as removed aliases. + +--- + +## 34. Final Implementation Contract + +The complete v0.1 contract is: + +> Workstream records every valid completed Review as one immutable reviewer contribution, regardless of decision. An accepted Review additionally records one immutable submitter contribution. Each contribution is evaluated against compensation terms frozen before work began. Workstream creates immutable, project-scoped money or project-points awards and emits transactional fulfillment instructions. Exact bound service actors perform provider and ledger work and report immutable fulfilled or failed results. In the same canonical transaction, Workstream schedules one deterministic evidence-bundle projection per contribution; after commit, the shared ART-owned contribution-evidence capability retains and verifies the bundle under a Workstream ArtifactBinding. WS-AUTH-001 governs every human and service action. Contribution and award history never changes; API views compose fulfillment and evidence status from append-only facts and rebuildable projections without exposing raw provider authority. diff --git a/docs/risk_register.md b/docs/risk_register.md index bdf83a1b..8cb5679b 100644 --- a/docs/risk_register.md +++ b/docs/risk_register.md @@ -62,7 +62,7 @@ Mitigation: - structured findings required - reviewer quality metrics -- second-review audits +- post-decision non-mutating reviewer-quality audits ### R4: Revision Loops Without Closure @@ -105,8 +105,8 @@ Bad review decisions can demoralize contributors and corrupt quality metrics. Mitigation: - reviewer reputation -- second-review sampling -- overturned decision tracking +- non-mutating reviewer-quality sampling +- reviewer-quality signal tracking - escalation process ### R7: Fake Evidence @@ -172,11 +172,12 @@ Reviewers can repeatedly approve weak work for favored contributors or skip evid Mitigation: -- sample accepted work for second review +- sample accepted work for a non-mutating post-decision quality audit - flag repeated contributor-reviewer pairs - require evidence citation on accept -- track overturned accept decisions -- require independent review for high-value or disputed tasks +- track unsupported-decision quality signals +- require independent non-mutating quality audits for high-value or disputed + tasks; they cannot delay or replace the recorded decision ### R12: Bad Project Guides diff --git a/docs/template_project_guide.md b/docs/template_project_guide.md index e331eb34..dc52d254 100644 --- a/docs/template_project_guide.md +++ b/docs/template_project_guide.md @@ -152,17 +152,17 @@ Needs revision requires: - required fix per finding - severity per finding -Second-review sampling: - -- accepted: -- rejected: -- high-value tasks: - -Mandatory second review: +Post-decision non-mutating reviewer-quality audit sampling: +- accepted sample rate: +- rejected sample rate: - suspected copied or confidential material: - high-value criterion defined by `ReviewPolicy`: - reviewer conflict of interest: + +These criteria select quality audits only. They do not delay Review, +FinalAcceptance, contribution creation, or task closure and do not create a +second decision or adjudication path. - registered recovery operation used (permission, actor, reason, evidence): ## Revision Policy diff --git a/docs/template_review_packet.md b/docs/template_review_packet.md index a38ae16a..f0278ddf 100644 --- a/docs/template_review_packet.md +++ b/docs/template_review_packet.md @@ -17,8 +17,11 @@ - assigned reason: - conflict-of-interest attestation: - contributor-reviewer pair risk: -- second review required: -- second review trigger: +- non-mutating quality audit selected: +- quality audit selection reason: + +Quality-audit selection cannot delay or replace the Review decision, +FinalAcceptance, task effects, or contribution transaction. ## Decision diff --git a/scripts/check_internal_review_evidence.py b/scripts/check_internal_review_evidence.py index d5823c79..0a2b3705 100644 --- a/scripts/check_internal_review_evidence.py +++ b/scripts/check_internal_review_evidence.py @@ -230,7 +230,10 @@ def reviewer_rows(text: str) -> dict[str, tuple[str, str, str]]: in_reviewer_table = False continue notes = cells[3] if len(cells) > 3 else "" - rows[cells[0]] = (cells[1], cells[2], notes) + # Evidence addenda are newest-first, matching reviewed_sha() and + # provenance_value(). Preserve the first authoritative result for each + # track instead of letting an older table below overwrite it. + rows.setdefault(cells[0], (cells[1], cells[2], notes)) return rows @@ -423,8 +426,14 @@ def required_chunk_ids(paths: list[str]) -> list[str]: continue contract_path = ROOT / path try: - heading = contract_path.read_text(encoding="utf-8").splitlines()[0] - except (IndexError, OSError, UnicodeDecodeError) as exc: + if os.path.lexists(contract_path): + if contract_path.is_symlink() or not contract_path.is_file(): + raise RuntimeError("changed chunk contract is not a regular file") + text = contract_path.read_text(encoding="utf-8") + else: + text = historical_contract_text(path) + heading = text.splitlines()[0] + except (IndexError, OSError, UnicodeDecodeError, RuntimeError) as exc: raise RuntimeError(f"cannot read changed chunk contract {path}") from exc chunk_id = chunk_id_from_heading(heading) if chunk_id is None: @@ -436,6 +445,24 @@ def required_chunk_ids(paths: list[str]) -> list[str]: return chunk_ids +def historical_contract_text(path: str) -> str: + """Recover a deleted contract from index, HEAD, or the review base.""" + base_ref = resolve_base_ref() + object_names = (f":{path}", f"HEAD:{path}", f"{base_ref}:{path}") + for object_name in object_names: + result = subprocess.run( + ["git", "show", object_name], + cwd=ROOT, + check=False, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + if result.returncode == 0: + return result.stdout + raise RuntimeError(f"deleted contract has no recoverable provenance: {path}") + + def chunk_id_from_heading(heading: str) -> str | None: """Return the exact chunk ID from a canonical contract heading.""" for pattern in CHUNK_HEADING_PATTERNS: diff --git a/scripts/check_stale_artifact_contracts.py b/scripts/check_stale_artifact_contracts.py index 50e7c2f2..0127af73 100644 --- a/scripts/check_stale_artifact_contracts.py +++ b/scripts/check_stale_artifact_contracts.py @@ -42,6 +42,7 @@ "docs/internal_reviews/2026-06-13_week1_week2_deterministic_hardening.md", "docs/internal_reviews/2026-06-16_submission_artifact_policy_architecture.md", "docs/reference_specs/WS-AUTH-001-actor-profile-role-and-authorization-service-specification.md", + "docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.md", "docs/reference_specs/WS-IMP-001-workstream-v0.1-coding-agent-implementation-specification.md", "docs/reference_specs/WS-REV-001-review-lifecycle-specification.md", "docs/roadmap_30_day_master_plan.md", diff --git a/scripts/check_stale_authorization_docs.py b/scripts/check_stale_authorization_docs.py index 220b1453..69297841 100644 --- a/scripts/check_stale_authorization_docs.py +++ b/scripts/check_stale_authorization_docs.py @@ -26,6 +26,7 @@ "docs/internal_reviews/2026-06-13_week1_week2_deterministic_hardening.md": "closed internal review", "docs/internal_reviews/2026-06-16_submission_artifact_policy_architecture.md": "closed internal review", "docs/reference_specs/WS-AUTH-001-actor-profile-role-and-authorization-service-specification.md": "immutable archival input", + "docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.md": "immutable archival input", "docs/reference_specs/WS-IMP-001-workstream-v0.1-coding-agent-implementation-specification.md": "immutable archival input", "docs/reference_specs/WS-REV-001-review-lifecycle-specification.md": "immutable archival input", "docs/roadmap_30_day_master_plan.md": "historical initial plan", diff --git a/scripts/check_stale_workstream_wording.py b/scripts/check_stale_workstream_wording.py index 1f81f21f..6dd5b412 100644 --- a/scripts/check_stale_workstream_wording.py +++ b/scripts/check_stale_workstream_wording.py @@ -208,6 +208,7 @@ "docs/internal_reviews/2026-06-13_week1_week2_deterministic_hardening.md", "docs/internal_reviews/2026-06-16_submission_artifact_policy_architecture.md", "docs/reference_specs/WS-AUTH-001-actor-profile-role-and-authorization-service-specification.md", + "docs/reference_specs/WS-CON-001-contribution-record-and-compensation-boundary-specification.md", "docs/reference_specs/WS-IMP-001-workstream-v0.1-coding-agent-implementation-specification.md", "docs/reference_specs/WS-REV-001-review-lifecycle-specification.md", "docs/roadmap_30_day_master_plan.md", @@ -235,8 +236,13 @@ ), } UNIMPLEMENTED_CURRENT_RUNTIME_COMPENSATION_PATTERNS = ( - re.compile(r"\bCompensationPolicyVersion\b"), + re.compile(r"\bContributionPolicy\b"), + re.compile(r"\bContributionPolicyVersion\b"), + re.compile(r"\bContributionRule\b"), + re.compile(r"\bContributionAwardDefinition\b"), + re.compile(r"\bProjectCompensationAdapterBinding\b"), re.compile(r"\bReviewLease\b"), + re.compile(r"\bContributionRecord\b"), re.compile(r"\bCompensationAward\b"), re.compile(r"\bCompensationFulfillmentReceipt\b"), re.compile(r"\bCompensationStatusProjection\b"), diff --git a/scripts/test_agent_gates.py b/scripts/test_agent_gates.py index caaaaf24..1e3d4f9c 100644 --- a/scripts/test_agent_gates.py +++ b/scripts/test_agent_gates.py @@ -372,15 +372,13 @@ def test_evidence_must_reference_changed_chunk() -> None: chunks = gate.ROOT / ".agent-loop/initiatives/example/chunks" chunks.mkdir(parents=True) invalid_contracts = { - "missing.md": None, "empty.md": b"", "malformed.md": b"# Contract without a lifecycle id\n", "invalid-utf8.md": b"\xff", } for filename, content in invalid_contracts.items(): relative_path = ".agent-loop/initiatives/example/chunks/" + filename - if content is not None: - (chunks / filename).write_bytes(content) + (chunks / filename).write_bytes(content) try: gate.required_chunk_ids([relative_path]) except RuntimeError: @@ -400,6 +398,74 @@ def test_evidence_must_reference_changed_chunk() -> None: pass else: raise AssertionError("unreadable changed contract did not fail closed") + + missing_relative = ( + ".agent-loop/initiatives/example/chunks/missing.md" + ) + try: + gate.required_chunk_ids([missing_relative]) + except RuntimeError: + pass + else: + raise AssertionError("missing changed contract did not fail closed") + + dangling_path = chunks / "dangling.md" + dangling_path.symlink_to(chunks / "absent-target.md") + try: + gate.required_chunk_ids( + [".agent-loop/initiatives/example/chunks/dangling.md"] + ) + except RuntimeError: + pass + else: + raise AssertionError( + "dangling changed contract did not fail closed" + ) + + linked_target = chunks / "linked-target.md" + linked_target.write_text( + "# Chunk Contract: WS-EXAMPLE-001-LINKED - External\n", + encoding="utf-8", + ) + linked_path = chunks / "linked.md" + linked_path.symlink_to(linked_target) + try: + gate.required_chunk_ids( + [".agent-loop/initiatives/example/chunks/linked.md"] + ) + except RuntimeError: + pass + else: + raise AssertionError( + "resolvable symlink contract did not fail closed" + ) + + replacement = chunks / "WS-EXAMPLE-001-NEW-replacement.md" + replacement.write_text( + "# Chunk Contract: WS-EXAMPLE-001-NEW - Replacement\n", + encoding="utf-8", + ) + original_historical_contract_text = gate.historical_contract_text + gate.historical_contract_text = lambda _path: ( + "# Chunk Contract: WS-EXAMPLE-001-OLD - Deleted\n" + ) + try: + assert gate.required_chunk_ids( + [ + ".agent-loop/initiatives/example/chunks/" + "WS-EXAMPLE-001-OLD-deleted.md" + ] + ) == ["ws-example-001-old"] + assert gate.required_chunk_ids( + [ + ".agent-loop/initiatives/example/chunks/" + "WS-EXAMPLE-001-OLD-deleted.md", + ".agent-loop/initiatives/example/chunks/" + "WS-EXAMPLE-001-NEW-replacement.md", + ] + ) == ["ws-example-001-old", "ws-example-001-new"] + finally: + gate.historical_contract_text = original_historical_contract_text finally: gate.ROOT = original_root original_changed_files = gate.changed_files @@ -526,6 +592,17 @@ def test_evidence_accepts_exact_pass_and_approved_na_results() -> None: ) assert gate.validate_reviewer_rows(text.lower(), required) == [] + newest_first_text = ( + "| Reviewer | Result | Blocking findings | Notes |\n" + "|---|---:|---|---|\n" + "| senior engineering | PASS AFTER FIXES | None | current addendum |\n" + "\nHistorical addendum\n\n" + "| Reviewer | Result | Blocking findings | Notes |\n" + "|---|---:|---|---|\n" + "| senior engineering | Pending | Old finding | superseded |\n" + ) + assert gate.validate_reviewer_rows(newest_first_text.lower(), required) == [] + bad_text = ( "| Reviewer | Result | Blocking findings | Notes |\n" "|---|---:|---|---|\n" @@ -1339,8 +1416,13 @@ def test_current_runtime_walkthrough_rejects_unimplemented_compensation_records( ) sample = " ".join( ( - "CompensationPolicyVersion", + "ContributionPolicy", + "ContributionPolicyVersion", + "ContributionRule", + "ContributionAwardDefinition", + "ProjectCompensationAdapterBinding", "ReviewLease", + "ContributionRecord", "CompensationAward", "CompensationFulfillmentReceipt", "CompensationStatusProjection", @@ -1351,8 +1433,13 @@ def test_current_runtime_walkthrough_rejects_unimplemented_compensation_records( pattern.pattern for pattern in stale.UNIMPLEMENTED_CURRENT_RUNTIME_COMPENSATION_PATTERNS } == { - r"\bCompensationPolicyVersion\b", + r"\bContributionPolicy\b", + r"\bContributionPolicyVersion\b", + r"\bContributionRule\b", + r"\bContributionAwardDefinition\b", + r"\bProjectCompensationAdapterBinding\b", r"\bReviewLease\b", + r"\bContributionRecord\b", r"\bCompensationAward\b", r"\bCompensationFulfillmentReceipt\b", r"\bCompensationStatusProjection\b", @@ -1361,6 +1448,13 @@ def test_current_runtime_walkthrough_rejects_unimplemented_compensation_records( pattern.search(sample) for pattern in stale.UNIMPLEMENTED_CURRENT_RUNTIME_COMPENSATION_PATTERNS ) + current_walkthrough = Path("docs/current_system_data_flow.html").read_text( + encoding="utf-8" + ) + assert not any( + pattern.search(current_walkthrough) + for pattern in stale.UNIMPLEMENTED_CURRENT_RUNTIME_COMPENSATION_PATTERNS + ) def test_stale_wording_skips_only_docs_internal_reviews_prefix() -> None: @@ -3788,6 +3882,7 @@ def test_stale_authorization_rule_examples_are_rejected() -> None: "Celery worker_id identifies the background process.", "The checker worker_id is included in internal telemetry.", "See backend/app/workers/tasks.py.", + "See app/workers/tasks.py.", "coverage report --include='app/workers/*' --precision=2 --fail-under=90", "ruff check app/workers/reviews.py", "review_lifecycle_live_drill.py --start-api-worker-beat --require-workers",