feat(workflows): restack-verify — the post-merge gate, as a relayflow - #230
Conversation
On 2026-09-07 this exact sequence was typed out by hand eight times against
cloud#3270 in one evening. Three of the defects it would have caught were
introduced BY a restack and existed in NEITHER parent:
- a renumbered migration whose cumulative snapshot still described its old
position: 87 tables where the base had 90
- a policy file whose deliberately-emptied exemption list was silently
re-populated from the stale side of a merge
- a base-branch test meeting a feature-branch guard, so neither side was
wrong and only the combination was
None of those produce a conflict marker. That is the whole point: a clean
`git merge` is not evidence, and the checks that catch this are mechanical, so
a human should not be re-deriving them from memory every time.
Proven against the real cloud checkout in BOTH directions rather than asserted:
real main no-conflict-markers PASSED
migration-journal PASSED (126 entries)
worker-bindings PASSED (86 env keys)
pre-fix 0127 snapshot migration-journal FAILED, exit 1
(restored from 567724e06~1) named the same three missing tables CI
surfaced hours later
injected conflict marker no-conflict-markers FAILED, exit 1
Every runner skips cleanly rather than failing where a repo has no such
artifact — "not applicable" must not read as "broken", or the gate gets
disabled the first time someone runs it elsewhere.
No output_contains gate is layered on the exit codes, for the reason already
recorded in workflows/preswarm-check.yaml: a substring match on a
diff-derived body is fail-open.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Empty commit. The previous run on this PR (20:53Z) predates the mint at 20:58Z, so it exercised the older CLOUD_API_KEY. This fires a synchronize event so the swarm runs with the current secret. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR
There was a problem hiding this comment.
All reported issues were addressed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR
Review swarm: maintainabilityNo fresh transcript was produced for run |
Review swarm: historyNo fresh transcript was produced for run |
Review swarm: structureNo fresh transcript was produced for run |
|
🎯 review-swarm: FAILED (M:fail H:fail S:missing) Lens transcripts posted as sibling comments above. |
kjgbot
left a comment
There was a problem hiding this comment.
Spec review: original bd7fda3; fixes pushed on this PR branch at abf4442. Leave open pending credential repair and independent review.
This is a zero-agent deterministic relayflow, serving RFC-0001 §1/Gate 1 and §2 dogfooding with existing primitives (decision #13). It is a standalone restack checker, not the review/merge gate judging this assignment; those gates were not edited.
Findings fixed on this branch:
ops/restack-verify/no-conflict-markers.sh:8: Git errors falsely passed and lockfiles were excluded. Check exit 1 separately, surface errors, scan lockfiles, and use a private temporary file instead of a shared /tmp path.ops/restack-verify/migration-journal.sh:18,39,47: require entries, strictly increasing timestamps, and snapshot id/prevId lineage; the prior code never checked the documented prevId chain.- The old table-loss heuristic rejected legitimate DROP TABLE migrations. Replaced with structural lineage validation; documentation now explicitly says SQL/schema equivalence requires database replay and target repo suites run separately.
ops/restack-verify/worker-bindings.sh:11: missing configuration was mislabeled missing script. Both absent is inapplicable; a partial installation fails naming the actual missing path.
Added black-box temporary-repository tests. This is local fixture evidence, not a claim that a deployed consumer or full workflow ran. Captured command/output (also committed in ops/restack-verify/SPEC-REVIEW-EVIDENCE.md):
$ python3 ops/restack-verify/test_checks.py
test_bindings_inapplicable_skips (__main__.RestackChecks) ... ok
test_bindings_missing_config_fails (__main__.RestackChecks) ... ok
test_bindings_missing_script_fails (__main__.RestackChecks) ... ok
test_bindings_passes_config_argument (__main__.RestackChecks) ... ok
test_bindings_propagates_checker_failure (__main__.RestackChecks) ... ok
test_broken_snapshot_chain_fails (__main__.RestackChecks) ... ok
test_clean_tracked_file_ignores_untracked_markers (__main__.RestackChecks) ... ok
test_empty_journal_passes (__main__.RestackChecks) ... ok
test_equal_or_out_of_order_timestamps_fail (__main__.RestackChecks) ... ok
test_git_error_fails (__main__.RestackChecks) ... ok
test_lockfile_conflicts_fail (__main__.RestackChecks) ... ok
test_missing_entries_fails (__main__.RestackChecks) ... ok
test_missing_sql_fails (__main__.RestackChecks) ... ok
test_orphan_sql_fails (__main__.RestackChecks) ... ok
test_valid_drop_is_not_a_stale_snapshot (__main__.RestackChecks) ... ok
----------------------------------------------------------------------
Ran 15 tests in 0.375s
OK
exit_code=0
New-head CI still cannot perform the content review. gh run view 34164170263 --log-failed captured:
review Launch cloud swarm 2026-09-07T21:44:38.3541771Z Workflow prepare failed: 401 Unauthorized: Unauthorized
The CI credential owner must restore accepted credentials. Independent reviewers must examine abf4442, acknowledge the fixes in outstanding threads, and provide genuine signoff. No merge or green-CI claim.
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Review swarm: FAILED
Cloud run: |
kjgbot
left a comment
There was a problem hiding this comment.
Follow-up spec review at 8229763. Leave open pending completed CI and independent signoff.
The review of abf4442 correctly identified that lineage-only validation lost the original stale-table signal. This head restores a fail-closed table-content check: removal of a table between snapshots requires semantic schema verification. The diagnostic explicitly distinguishes the unresolved possibilities (intentional drop or stale snapshot); it does not silently accept either and adds no override. SQL/schema equivalence and execution of the target repo suites remain outside this structural check.
The remaining original repairs (Git errors/lockfiles, malformed journals, strict timestamps, id/prevId chain, partial worker installation) are retained. Captured command/output, also in ops/restack-verify/SPEC-REVIEW-EVIDENCE.md:
$ python3 ops/restack-verify/test_checks.py
test_bindings_inapplicable_skips (__main__.RestackChecks) ... ok
test_bindings_missing_config_fails (__main__.RestackChecks) ... ok
test_bindings_missing_script_fails (__main__.RestackChecks) ... ok
test_bindings_passes_config_argument (__main__.RestackChecks) ... ok
test_bindings_propagates_checker_failure (__main__.RestackChecks) ... ok
test_broken_snapshot_chain_fails (__main__.RestackChecks) ... ok
test_clean_tracked_file_ignores_untracked_markers (__main__.RestackChecks) ... ok
test_empty_journal_passes (__main__.RestackChecks) ... ok
test_equal_or_out_of_order_timestamps_fail (__main__.RestackChecks) ... ok
test_git_error_fails (__main__.RestackChecks) ... ok
test_lockfile_conflicts_fail (__main__.RestackChecks) ... ok
test_missing_entries_fails (__main__.RestackChecks) ... ok
test_missing_sql_fails (__main__.RestackChecks) ... ok
test_orphan_sql_fails (__main__.RestackChecks) ... ok
test_table_loss_requires_semantic_verification (__main__.RestackChecks) ... ok
test_valid_lineage_passes (__main__.RestackChecks) ... ok
----------------------------------------------------------------------
Ran 16 tests in 0.421s
OK
exit_code=0
CI infrastructure has changed: Actions run 34164770687 now completed Launch cloud swarm successfully at 2026-09-07T21:54:49Z and is waiting for the swarm. The earlier 401 is historical, not the current blocker. This is not a content pass or permission to bypass the outstanding review thread. Await the final verdict and independent acknowledgement at 8229763. No merge.
There was a problem hiding this comment.
All reported issues were addressed across 4 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
kjgbot
left a comment
There was a problem hiding this comment.
Final disposition at 8229763: LEFT OPEN.
The branch contains repairs abf4442 and 8229763 and 16 passing local fixture tests, as captured in the earlier review. A remaining P2 at ops/restack-verify/migration-journal.sh:67 is valid: scanning every historical snapshot means a legitimate DROP TABLE or table rename permanently triggers the loss guard. The guard cannot distinguish that from stale content and currently has no scoped restack baseline or semantic replay. This is not comprehensive restack acceptance. The restack flow owner must define the comparison baseline or implement semantic replay and exercise both stale snapshots and legitimate historical drops/renames. Removing the loss guard would recreate the previous P1 and is not a fix. The latest review failed with all fresh lens transcripts MISSING; review infrastructure owner must restore the swarm. Leave open with the unresolved thread; no merge.
Captured exact-head check query and output:
$ gh api repos/AgentWorkforce/flows/commits/82297638ec8c4f18ac5acd355134d20c78a1b08c/check-runs --jq '[.check_runs[] | {name,head_sha,status,conclusion,details_url}]'
[{"conclusion":"success","details_url":"https://www.cubic.dev/pr/AgentWorkforce/flows/pull/230","head_sha":"82297638ec8c4f18ac5acd355134d20c78a1b08c","name":"cubic · AI code reviewer","status":"completed"},{"conclusion":"failure","details_url":"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/AgentWorkforce/flows/actions/runs/34164770687/job/101873532992","head_sha":"82297638ec8c4f18ac5acd355134d20c78a1b08c","name":"review","status":"completed"}]
exit_code=0
Current swarm report: #230 (comment)
Review swarm: FAILED
- maintainability: MISSING
- history: MISSING
- structure: MISSING
Cloud run: 95a34434-5f01-4efe-a0fb-6453266effc0
…corded Two cubic findings on #230, both about the same loop. P2 is right and serious: the loss check scans every consecutive snapshot pair in the whole journal, so one legitimate DROP TABLE — or a RENAME, which drizzle snapshots as a drop plus a create — fails this gate on every future run forever. The PR description warned about exactly that shape ("the gate gets disabled the first time someone runs it elsewhere") and then shipped it. Deliberate removals are now recorded once in ops/restack-verify/intentional-drops.txt, one `<snapshot>:<table>` or `<snapshot>:<table>.<column>` per line. P1's premise is not accurate — the loop does inspect the payload, at the `tables` comparison — but its residual concern is real and worth more than the correction: a snapshot with coherent lineage and an unchanged table set could still be stale in its contents. That is not hypothetical. The defect this gate was written for was a snapshot missing a single jsonb column, which a table-name comparison alone would have passed. Columns are now compared per retained table. Verified with a fixture whose lineage is coherent throughout: a successor missing one column exits 1; the same tree with that drop acknowledged exits 0; a dropped table exits 1; a snapshot that only adds a table exits 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR
…s own bug The permanent-red failure mode cubic found is named in the PR description I wrote. Columns are now compared as well as tables, and deliberate drops get an acknowledgement file instead of reddening the gate forever. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR
… slip Ran #230's gate against the six merges (2 of 3 checks skip in flows, worth noting), then bash -n on every run: block since three PRs edited one shell block. 7/0. Caught and fixed a two-space misalignment from my conflict resolution in #236. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR
The deterministic gate that should run after merging a base branch into a long-lived feature branch — expressed as a relayflow instead of typed out by hand.
Provenance
On 2026-09-07 this exact sequence was hand-driven eight times against
cloud#3270in one evening. Three of the defects it catches were introduced by a restack and existed in neither parent:None of those produce a conflict marker. That's the point: a clean
git mergeis not evidence, and these checks are mechanical, so nobody should be re-deriving them from memory.Proven in both directions
Against a real cloud checkout, rather than asserted:
main0127snapshot, restored from567724e06~1migration-journalFAILED, exit 1 — naming the same three missing tables CI surfaced hours laterno-conflict-markersFAILED, exit 1In this repo the migration step reports SKIPPED — every runner skips where a repo has no such artifact, because "not applicable" must not read as "broken" or the gate gets disabled the first time someone runs it elsewhere.
Design note
No
output_containsgate is layered on the exit codes, for the reason already recorded inworkflows/preswarm-check.yaml: a substring match on a diff-derived body is fail-open.🤖 Generated with Claude Code
https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR