Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
e54f498
feat: enter root reconciliation write context
Joncallim Jul 27, 2026
75dc9e5
fix: use prelocked root authority reads
Joncallim Jul 27, 2026
cda8e74
merge: propagate root context owner order
Joncallim Jul 27, 2026
7999221
merge: propagate root context owner order
Joncallim Jul 27, 2026
fe5442c
feat: fence root reconciler task updates
Joncallim Jul 27, 2026
45c6b93
merge: propagate root routine grant ordering
Joncallim Jul 27, 2026
926e85e
merge: propagate root routine grant ordering
Joncallim Jul 27, 2026
4db1a90
merge: propagate root routine grant ordering
Joncallim Jul 27, 2026
d2805a5
feat: extract filesystem grant block validator
Joncallim Jul 27, 2026
4426077
fix: qualify root reconciliation SQL references
Joncallim Jul 27, 2026
71d398e
refactor: use filesystem grant block validator
Joncallim Jul 27, 2026
6259c79
feat: fence root reconciler package updates
Joncallim Jul 27, 2026
5238c2a
fix: qualify filesystem grant validators
Joncallim Jul 27, 2026
c6cbc72
fix: stop root reconciliation after completion
Joncallim Jul 27, 2026
f25388b
test: make phase suppression assertion semantic
Joncallim Jul 27, 2026
f928d1c
fix: escape cutover SQL dollar quotes
Joncallim Jul 27, 2026
22f0bf5
fix: restore root index cutover proof sequence
Joncallim Jul 27, 2026
6e7614e
fix: inventory root write contexts
Joncallim Jul 27, 2026
82a7210
feat: mirror root write contexts in schema
Joncallim Jul 27, 2026
8a17609
fix: recover root index builds safely
Joncallim Jul 27, 2026
e9d173e
fix: require exact root index at cutover
Joncallim Jul 27, 2026
4880b1d
test: prove root index recovery lifecycle
Joncallim Jul 27, 2026
3321a1f
fix: classify missing root index safely
Joncallim Jul 27, 2026
7038466
test: require root index lifecycle proof
Joncallim Jul 27, 2026
560600f
test: seed root authority project fixture
Joncallim Jul 27, 2026
1742838
test: use portable index proof matcher
Joncallim Jul 27, 2026
c2cf6b2
test: seed root authority package fixture
Joncallim Jul 27, 2026
bd70392
fix: check root index before coverage
Joncallim Jul 27, 2026
76c425f
test: prove root authority reconciliation
Joncallim Jul 27, 2026
f462f60
test: serialize root proof reconciliation
Joncallim Jul 27, 2026
bdc3b49
fix: type root index classifier state
Joncallim Jul 27, 2026
368d28d
test: prove root reconciliation rollback
Joncallim Jul 27, 2026
62423f5
fix: parse root authority package fixture
Joncallim Jul 27, 2026
36bf6d7
test: prove root reconciliation replay
Joncallim Jul 27, 2026
da51a83
test: prove root reconciler privileges
Joncallim Jul 27, 2026
9c59003
fix: assert root rollback error
Joncallim Jul 27, 2026
930136a
test: prove stale root contexts
Joncallim Jul 27, 2026
106b865
fix: bind root negative assertion inputs
Joncallim Jul 27, 2026
a855c8a
test: prove root reconciliation contention
Joncallim Jul 27, 2026
758c579
test: keep negative reconciliation inputs transactional
Joncallim Jul 27, 2026
ec91143
test: diagnose root proof psql failures
Joncallim Jul 27, 2026
d21aa17
test: distinguish root proof psql statuses
Joncallim Jul 27, 2026
9a49233
test: bind root authority assertion inputs
Joncallim Jul 27, 2026
b6d92aa
test: align root authority recovery fixture
Joncallim Jul 27, 2026
f467330
test: make root authority additions admissible
Joncallim Jul 27, 2026
07072ae
test: close root reconciler privilege allowlist
Joncallim Jul 27, 2026
0484f01
test: prove root reconciler privilege allowlist mutations
Joncallim Jul 27, 2026
52d798a
fix: gate root reconciler maintain privilege by server version
Joncallim Jul 27, 2026
2ed915c
test: isolate root reconciliation binding rejections
Joncallim Jul 27, 2026
30b0fab
fix: close root reconciler routine allowlist
Joncallim Jul 27, 2026
392290e
test: prove root reconciler actor boundaries
Joncallim Jul 27, 2026
87bf113
test: fix ordinary app trigger proof inputs
Joncallim Jul 27, 2026
d22ad9d
fix: align root write context schema metadata
Joncallim Jul 27, 2026
737e75c
test: close root reconciler column privileges
Joncallim Jul 27, 2026
c728881
test: close root reconciler grant options
Joncallim Jul 27, 2026
15751a6
test: bind root grantor to mutation session
Joncallim Jul 27, 2026
f6a8543
test: use root owner for grant option mutation
Joncallim Jul 27, 2026
445a66a
test: run root privilege mutations in upgrade proof
Joncallim Jul 27, 2026
b47ecda
Merge PR #281 into codex/pr198-root-grantor-owner
Joncallim Jul 27, 2026
f1c87f1
Merge PR #280 into codex/pr198-root-grantor-session
Joncallim Jul 27, 2026
d58e392
Merge PR #279 into codex/pr198-root-reconciler-grant-options
Joncallim Jul 27, 2026
4ebe6ef
Merge PR #278 into codex/pr198-root-reconciler-column-allowlist
Joncallim Jul 27, 2026
4b0b7b7
Merge PR #277 into codex/pr198-root-write-context-metadata
Joncallim Jul 27, 2026
99ca55b
Merge PR #276 into codex/pr198-ordinary-app-trigger-inputs
Joncallim Jul 27, 2026
e422b46
Merge PR #275 into codex/pr198-root-reconciler-wrong-actor-proof
Joncallim Jul 27, 2026
87c5321
Merge PR #274 into codex/pr198-root-reconciler-allowlist-routines
Joncallim Jul 27, 2026
f161638
Merge PR #273 into codex/pr198-root-reconciler-wrong-binding-proof
Joncallim Jul 27, 2026
ce843a5
Merge PR #272 into codex/pr198-root-reconciler-allowlist-maintain-cap…
Joncallim Jul 27, 2026
e5c8c36
Merge PR #271 into codex/pr198-root-reconciler-allowlist-mutation
Joncallim Jul 27, 2026
e338313
Merge PR #270 into codex/pr198-root-reconciler-closed-allowlist
Joncallim Jul 27, 2026
1e33d1a
Merge PR #269 into codex/pr198-root-authority-addition
Joncallim Jul 27, 2026
7bc3d18
Merge PR #268 into codex/pr198-root-authority-convergence
Joncallim Jul 27, 2026
560c68f
Merge PR #267 into codex/pr198-root-authority-assertion-inputs
Joncallim Jul 27, 2026
3271c0b
Merge PR #266 into codex/pr198-root-proof-psql-status
Joncallim Jul 27, 2026
9bee042
Merge PR #265 into codex/pr198-root-proof-status-diagnostics
Joncallim Jul 27, 2026
e41ff3d
Merge PR #264 into codex/pr198-root-negative-assertion-temp-inputs
Joncallim Jul 27, 2026
eae659d
Merge PR #263 into codex/pr198-root-contention-proof
Joncallim Jul 27, 2026
4386910
Merge PR #262 into codex/pr198-root-negative-assertion-inputs
Joncallim Jul 27, 2026
5c7ffdf
Merge PR #261 into codex/pr198-root-stale-context-proof
Joncallim Jul 27, 2026
ce38fb2
Merge PR #260 into codex/pr198-root-rollback-proof-fix
Joncallim Jul 27, 2026
433828a
Merge PR #259 into codex/pr198-root-reconciler-privilege-proof
Joncallim Jul 27, 2026
64ed722
Merge PR #258 into codex/pr198-root-reconciliation-replay-proof
Joncallim Jul 27, 2026
5d170f2
Merge PR #257 into codex/pr198-root-authority-fixture-syntax
Joncallim Jul 27, 2026
7f6007b
Merge PR #256 into codex/pr198-root-reconciliation-negative-proof
Joncallim Jul 27, 2026
a483f0b
Merge PR #255 into codex/pr198-root-index-state-type
Joncallim Jul 27, 2026
ec5bc86
Merge PR #254 into codex/pr198-root-single-drain-proof
Joncallim Jul 27, 2026
3a9f7cf
Merge PR #253 into codex/pr198-root-authority-positive-proof
Joncallim Jul 27, 2026
471c94c
Merge PR #252 into codex/pr198-root-cutover-index-first
Joncallim Jul 27, 2026
d39c098
Merge PR #251 into codex/pr198-root-authority-package-fixture
Joncallim Jul 27, 2026
6c12872
Merge PR #250 into codex/pr198-root-index-proof-portable
Joncallim Jul 27, 2026
32056d6
Merge PR #249 into codex/pr198-root-authority-project-fixture
Joncallim Jul 27, 2026
7bc7266
Merge PR #248 into codex/pr198-root-index-proof-mandatory
Joncallim Jul 27, 2026
a346ba6
Merge PR #247 into codex/pr198-root-index-missing-safe-builder
Joncallim Jul 27, 2026
79099f2
Merge PR #246 into codex/pr198-root-index-pg-proof
Joncallim Jul 27, 2026
e88c80b
Merge PR #245 into codex/pr198-root-index-exact-cutover
Joncallim Jul 27, 2026
268da6f
Merge PR #244 into codex/pr198-root-index-restartable
Joncallim Jul 27, 2026
de8c2a8
Merge PR #243 into codex/pr198-root-write-context-schema
Joncallim Jul 27, 2026
4993f86
Merge PR #242 into codex/pr198-root-write-context-schema
Joncallim Jul 27, 2026
2fecbf5
Merge PR #241 into codex/pr198-root-index-cutover-sequence
Joncallim Jul 27, 2026
b4b910b
Merge PR #240 into codex/pr198-root-cutover-heredoc
Joncallim Jul 27, 2026
cb4ea69
Merge PR #239 into codex/pr198-root-reconciliation-test-contract
Joncallim Jul 27, 2026
3ea58bb
Merge PR #238 into codex/pr198-root-reconciliation-complete-loop
Joncallim Jul 27, 2026
ffa1c39
Merge PR #237 into codex/pr198-root-reconciliation-complete-loop
Joncallim Jul 27, 2026
c29eee5
Merge PR #236 into codex/pr198-root-reconciler-validator
Joncallim Jul 27, 2026
dc40e9d
Merge PR #235 into codex/pr198-root-reconciler-validator
Joncallim Jul 27, 2026
f9c285c
Merge PR #234 into codex/pr198-root-reconciler-package-fence
Joncallim Jul 27, 2026
347fef3
Merge PR #233 into codex/pr198-root-reconciler-validator
Joncallim Jul 27, 2026
c8c9271
Merge PR #232 into codex/pr198-root-reconciliation-claim-qualification
Joncallim Jul 27, 2026
2827cf8
Merge PR #231 into codex/pr198-root-reconciliation-authority-lock
Joncallim Jul 27, 2026
e47823c
Merge PR #230 into codex/pr198-root-reconciliation-entry
Joncallim Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/web-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ jobs:
'filesystem_mcp_decision_nonce_claims', 'project_root_ref_reconciliation',
'project_root_change_journal_counter', 'project_root_change_journal',
'project_root_reconciliation_operations', 'project_root_reconciliation_checkpoints',
'project_root_reconciliation_outcomes'
'project_root_reconciliation_outcomes', 'project_root_reconciliation_write_contexts'
] LOOP
FOREACH table_privilege IN ARRAY ARRAY[
'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'
Expand Down Expand Up @@ -371,7 +371,7 @@ jobs:
'filesystem_mcp_decision_nonce_claims', 'project_root_ref_reconciliation',
'project_root_change_journal_counter', 'project_root_change_journal',
'project_root_reconciliation_operations', 'project_root_reconciliation_checkpoints',
'project_root_reconciliation_outcomes'
'project_root_reconciliation_outcomes', 'project_root_reconciliation_write_contexts'
];
projection_tables constant text[] := ARRAY[
'forge_epic_172_s3_release_state', 'work_package_local_projection_sources',
Expand Down
393 changes: 392 additions & 1 deletion web/__tests__/project-root-reconciliation.test.ts

Large diffs are not rendered by default.

84 changes: 15 additions & 69 deletions web/db/migrations/0026_epic_172_s3_grant_lifecycle.sql
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ CREATE TABLE "project_filesystem_grant_decisions" (
CONSTRAINT "project_filesystem_grant_decisions_fingerprint_check"
CHECK ("decision_fingerprint" ~ '^sha256:[0-9a-f]{64}$'),
CONSTRAINT "project_filesystem_grant_decisions_capabilities_check"
CHECK (forge_is_canonical_filesystem_capability_set("capabilities")),
CHECK (public.forge_is_canonical_filesystem_capability_set("capabilities")),
CONSTRAINT "project_filesystem_grant_decisions_prior_tuple_check"
CHECK (
(
Expand Down Expand Up @@ -411,81 +411,27 @@ BEFORE UPDATE OR DELETE ON "project_filesystem_grant_decisions"
FOR EACH ROW EXECUTE FUNCTION "forge_reject_project_filesystem_decision_mutation"();

-- SQL mirrors the closed TypeScript S3 hold-state union. Older marker-shaped
-- Pure reusable validator; the table constraint below preserves the legacy
-- status/absence semantics while this predicate owns the marker grammar.
CREATE FUNCTION forge_is_canonical_filesystem_grant_block_v2(p_block jsonb)
RETURNS boolean LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$
SELECT (jsonb_typeof(p_block)='object'
AND p_block ?& ARRAY['schemaVersion','kind','source','taskDisposition','autoRetryable','terminalFailure','requirementKeys','requestedCapabilities','recoveryAction','blockFingerprint','blockedAt','holdKind','grantPhase','grantConsumed','grantDecisionRevision','revocationReason']
AND p_block - ARRAY['schemaVersion','kind','source','taskDisposition','autoRetryable','terminalFailure','requirementKeys','requestedCapabilities','recoveryAction','blockFingerprint','blockedAt','holdKind','grantPhase','grantConsumed','grantDecisionRevision','revocationReason']='{}'::jsonb
AND p_block->'schemaVersion'='2'::jsonb AND p_block->>'kind'='filesystem_grant' AND p_block->>'source'='filesystem-grant-approval' AND p_block->>'taskDisposition'='operator_hold' AND p_block->'autoRetryable'='false'::jsonb AND p_block->'terminalFailure'='false'::jsonb
AND public.forge_is_canonical_bounded_string_set(p_block->'requirementKeys',256,240) AND public.forge_is_canonical_bounded_string_set(p_block->'requestedCapabilities',3,240) AND public.forge_is_canonical_filesystem_capability_set(p_block->'requestedCapabilities')
AND p_block->>'recoveryAction'='approve_project_filesystem_context' AND (p_block->>'blockFingerprint') ~ '^sha256:[0-9a-f]{64}$' AND public.forge_is_canonical_utc_timestamp(p_block->>'blockedAt')
AND ((p_block->>'holdKind'='approval_required' AND p_block->>'grantPhase' IN ('none','proposed','not_issued') AND p_block->'grantConsumed'='false'::jsonb AND p_block->'grantDecisionRevision'='null'::jsonb AND p_block->'revocationReason'='null'::jsonb) OR (p_block->>'holdKind'='denied_required' AND p_block->>'grantPhase'='denied' AND p_block->'grantConsumed'='false'::jsonb AND (p_block->'grantDecisionRevision'='null'::jsonb OR (p_block->>'grantDecisionRevision') ~ '^[1-9][0-9]*$') AND p_block->'revocationReason'='null'::jsonb) OR (p_block->>'holdKind'='revoked_required' AND p_block->>'grantPhase'='revoked' AND p_block->'grantConsumed'='false'::jsonb AND (p_block->>'grantDecisionRevision') ~ '^[1-9][0-9]*$' AND p_block->>'revocationReason' IN ('project_grant_removed','project_grant_narrowed','project_root_repoint')) OR (p_block->>'holdKind'='consumed_once' AND p_block->>'grantPhase'='approved' AND p_block->'grantConsumed'='true'::jsonb AND (p_block->>'grantDecisionRevision') ~ '^[1-9][0-9]*$' AND p_block->'revocationReason'='null'::jsonb))
) IS TRUE
$$;
-- JSON remains retained as data but is not S3 recovery authority; every
-- version-2 writer is constrained to exact S3 keys, bounds, and blocked status.
ALTER TABLE "work_packages"
ADD CONSTRAINT "work_packages_filesystem_grant_hold_v2_check"
CHECK (
NOT ("metadata" ? 'mcpGrantBlock')
OR COALESCE("metadata"->'mcpGrantBlock'->>'schemaVersion', '') <> '2'
OR (
(
jsonb_typeof("metadata"->'mcpGrantBlock') = 'object'
AND "status" = 'blocked'
AND ("metadata"->'mcpGrantBlock') ?& ARRAY[
'schemaVersion','kind','source','taskDisposition','autoRetryable',
'terminalFailure','requirementKeys','requestedCapabilities',
'recoveryAction','blockFingerprint','blockedAt','holdKind',
'grantPhase','grantConsumed','grantDecisionRevision','revocationReason'
]
AND ("metadata"->'mcpGrantBlock') - ARRAY[
'schemaVersion','kind','source','taskDisposition','autoRetryable',
'terminalFailure','requirementKeys','requestedCapabilities',
'recoveryAction','blockFingerprint','blockedAt','holdKind',
'grantPhase','grantConsumed','grantDecisionRevision','revocationReason'
] = '{}'::jsonb
AND "metadata"->'mcpGrantBlock'->'schemaVersion' = '2'::jsonb
AND "metadata"->'mcpGrantBlock'->>'kind' = 'filesystem_grant'
AND "metadata"->'mcpGrantBlock'->>'source' = 'filesystem-grant-approval'
AND "metadata"->'mcpGrantBlock'->>'taskDisposition' = 'operator_hold'
AND "metadata"->'mcpGrantBlock'->'autoRetryable' = 'false'::jsonb
AND "metadata"->'mcpGrantBlock'->'terminalFailure' = 'false'::jsonb
AND forge_is_canonical_bounded_string_set(
"metadata"->'mcpGrantBlock'->'requirementKeys', 256, 240
)
AND forge_is_canonical_bounded_string_set(
"metadata"->'mcpGrantBlock'->'requestedCapabilities', 3, 240
)
AND forge_is_canonical_filesystem_capability_set(
"metadata"->'mcpGrantBlock'->'requestedCapabilities'
)
AND "metadata"->'mcpGrantBlock'->>'recoveryAction' = 'approve_project_filesystem_context'
AND ("metadata"->'mcpGrantBlock'->>'blockFingerprint') ~ '^sha256:[0-9a-f]{64}$'
AND forge_is_canonical_utc_timestamp("metadata"->'mcpGrantBlock'->>'blockedAt')
AND (
(
"metadata"->'mcpGrantBlock'->>'holdKind' = 'approval_required'
AND "metadata"->'mcpGrantBlock'->>'grantPhase' IN ('none','proposed','not_issued')
AND "metadata"->'mcpGrantBlock'->'grantConsumed' = 'false'::jsonb
AND "metadata"->'mcpGrantBlock'->'grantDecisionRevision' = 'null'::jsonb
AND "metadata"->'mcpGrantBlock'->'revocationReason' = 'null'::jsonb
) OR (
"metadata"->'mcpGrantBlock'->>'holdKind' = 'denied_required'
AND "metadata"->'mcpGrantBlock'->>'grantPhase' = 'denied'
AND "metadata"->'mcpGrantBlock'->'grantConsumed' = 'false'::jsonb
AND (
"metadata"->'mcpGrantBlock'->'grantDecisionRevision' = 'null'::jsonb
OR ("metadata"->'mcpGrantBlock'->>'grantDecisionRevision') ~ '^[1-9][0-9]*$'
)
AND "metadata"->'mcpGrantBlock'->'revocationReason' = 'null'::jsonb
) OR (
"metadata"->'mcpGrantBlock'->>'holdKind' = 'revoked_required'
AND "metadata"->'mcpGrantBlock'->>'grantPhase' = 'revoked'
AND "metadata"->'mcpGrantBlock'->'grantConsumed' = 'false'::jsonb
AND ("metadata"->'mcpGrantBlock'->>'grantDecisionRevision') ~ '^[1-9][0-9]*$'
AND "metadata"->'mcpGrantBlock'->>'revocationReason' IN (
'project_grant_removed','project_grant_narrowed','project_root_repoint'
)
) OR (
"metadata"->'mcpGrantBlock'->>'holdKind' = 'consumed_once'
AND "metadata"->'mcpGrantBlock'->>'grantPhase' = 'approved'
AND "metadata"->'mcpGrantBlock'->'grantConsumed' = 'true'::jsonb
AND ("metadata"->'mcpGrantBlock'->>'grantDecisionRevision') ~ '^[1-9][0-9]*$'
AND "metadata"->'mcpGrantBlock'->'revocationReason' = 'null'::jsonb
)
)
) IS TRUE
)
OR ("status" = 'blocked' AND public.forge_is_canonical_filesystem_grant_block_v2("metadata"->'mcpGrantBlock') IS TRUE)
);
--> statement-breakpoint
-- The release ledger is owned by a separate NOLOGIN role. The administrator-
Expand Down
Loading
Loading