Public: anyone can read this; the crew can change it.

The check fails a pull that modifies or deletes a file under src/core/migration-pins/ #6832

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The check now fails a pull that modifies, deletes or renames a migration pin. An added pin passes.

shipped production is serving it deploy 9e284d9

opened this

The check now fails a pull that modifies, deletes or renames a migration pin. An added pin passes.

I ran bun x tsc --noEmit (clean), test/pin-edits.test.ts and test/check-list.test.ts (18 pass), and bun scripts/gate.ts (exits 0). I also edited a pin in a throwaway commit and ran the gate against it with FORGE_CHECK_BASE. It exited 2 and named the file. I did not run the full suite.

What changed

  • src/kernel/pin_edits.ts (new) holds pinEdits(changes), which names every modified, deleted or renamed path under src/core/migration-pins/.

- It also names src/core/migration-pins.json, the frozen pins file the issue flags as history. - A rename counts as the old path being renamed away and the new path being added. - parseNameStatus turns git diff --name-status output into those changes.

  • scripts/gate.ts runs it, since check.fast and check.run both call bun scripts/gate.ts first.

- It diffs $FORGE_CHECK_BASE..HEAD, falling back to the merge base with main, and exits 2 naming each file. - The message says "add a new migration instead". - When the pin's migration is not on the base yet (src/core/migrations/<name>.ts), it says to delete the pin and re-run bun scripts/pin-migrations.ts.

  • test/pin-edits.test.ts covers modified, deleted, renamed, added, a path outside the folder, and the frozen JSON file.

Choices and gaps

  • gate.ts loads pin_edits.ts with a dynamic import inside the check. test/check-list.test.ts copies gate.ts alone into a temp tree, so a top-level import of src/ broke it. My first push had that top-level import and failed it; the second push fixes it.
  • The "delete the pin and re-run" message only fires for a pin that already exists on the base while its migration doesn't. A pin added and then edited inside the same pull shows as a plain addition against the base and passes.
  • If git can't resolve a base, the check passes quietly. I didn't make that an error.

Closes #6821

commented

The check now fails a pull that modifies, deletes or renames a migration pin. An added pin passes.

I ran bun x tsc --noEmit (clean), test/pin-edits.test.ts and test/check-list.test.ts (18 pass), and bun scripts/gate.ts (exits 0). I also edited a pin in a throwaway commit and ran the gate against it with FORGE_CHECK_BASE. It exited 2 and named the file. I did not run the full suite.

What changed

  • src/kernel/pin_edits.ts (new) holds pinEdits(changes), which names every modified, deleted or renamed path under src/core/migration-pins/.

- It also names src/core/migration-pins.json, the frozen pins file the issue flags as history. - A rename counts as the old path being renamed away and the new path being added. - parseNameStatus turns git diff --name-status output into those changes.

  • scripts/gate.ts runs it, since check.fast and check.run both call bun scripts/gate.ts first.

- It diffs $FORGE_CHECK_BASE..HEAD, falling back to the merge base with main, and exits 2 naming each file. - The message says "add a new migration instead". - When the pin's migration is not on the base yet (src/core/migrations/<name>.ts), it says to delete the pin and re-run bun scripts/pin-migrations.ts.

  • test/pin-edits.test.ts covers modified, deleted, renamed, added, a path outside the folder, and the frozen JSON file.

Choices and gaps

  • gate.ts loads pin_edits.ts with a dynamic import inside the check. test/check-list.test.ts copies gate.ts alone into a temp tree, so a top-level import of src/ broke it. My first push had that top-level import and failed it; the second push fixes it.
  • The "delete the pin and re-run" message only fires for a pin that already exists on the base while its migration doesn't. A pin added and then edited inside the same pull shows as a plain addition against the base and passes.
  • If git can't resolve a base, the check passes quietly. I didn't make that an error.
Changes requested — before the latest push

The pure part (pinEdits, parseNameStatus) is sound and tested. The part that makes the check fail is not tested. Fix first: add a test that builds a throwaway git repo in $TMPDIR (base commit, then a commit that modifies a pin) and asserts pinRefusal() or bun scripts/gate.ts with FORGE_CHECK_BASE exits 2 and names the file. Delete gate.ts wiring and every current test still passes, so the stated behaviour (the check fails the pull) has no test that would fail without it. Cover both messages too: a pin whose migration is on the base gets "add a new migration instead", and one whose migration is not on the base gets "delete the pin and re-run". Smaller: a deleted pin whose migration is on the base is told to add a new migration, which does not fit a deletion; and when no base resolves the check passes silently, so say that on stderr rather than being green with no check. Fix the first point to land.

commented

The check now fails a pull that edits, deletes or renames a migration pin. A new test proves it by running the gate itself. The type check and the pin-edits, pin-refusal and gate tests pass here; I did not run the whole check.

  • Test that would fail without the wiring: test/pin-refusal.test.ts builds throwaway git repos in $TMPDIR: a base commit, then a commit that edits a pin. It runs bun scripts/gate.ts with FORGE_CHECK_BASE set and asserts exit 2 with the pin's path on stderr. It also covers:

- a modified pin whose migration is on the base, which gets "add a new migration instead"; - a pin whose migration is not on the base, which gets "delete the pin and re-run"; - an added pin, which passes.

  • Deleted pins: a deleted pin whose migration is on the base now gets "was deleted: a migration on main is history, so restore it" instead of "add a new migration". This is tested.
  • No base: pinRefusal now prints a one-line warning to stderr when no base resolves, and another when the diff against the base fails. It still returns no refusals, so the check is not made stricter, but the output now says the pins were not checked. This is tested.
  • Signature change: pinRefusal and git take an optional cwd that defaults to the current directory. The gate entry's behaviour is unchanged.

I did not make a missing base fail the check. That could break pushes where main isn't fetched, and the warning at least makes it visible.

commented

The failing check was my own doing, and the fix is a one-line test change. I ran test/shards.test.ts and test/pin-refusal.test.ts here and both pass; I did not run the whole check.

The test "a stale exclusion fails it by name; a new unlisted file passes" runs scripts/gate.ts in a scratch directory that is not a git repo. It expected empty stderr on the green path. The warning I added for "no base to compare to" now prints there. The test was wrong, so I changed the test, not the code. The warning is behaviour the reviewer asked for.

The green case in test/shards.test.ts now expects exactly that warning line. The red case (stale exclusion, exit 2, last line names the file) is unchanged and still passes.

The branch is pushed again.

commented

The gate-audit test failed again in the forge's check because my last fix didn't account for how the check runs it. I changed the test, not the code, and pushed. I haven't seen the check's verdict on this push.

The check sets FORGE_CHECK_BASE for the whole run, and the test's child process inherited it. In the scratch directory, which is not a git repo, the gate then printed a different stderr line ("git diff against … failed") from the "no base to compare to" warning my last fix expected. That is why it passed here and failed there.

test/shards.test.ts now strips FORGE_CHECK_BASE from the environment of the child gate process. Its stderr is the same whether or not the check sets the variable. I reran test/shards.test.ts and test/pin-refusal.test.ts with FORGE_CHECK_BASE=HEAD set to mimic the check, and all 77 tests pass.

Approved

Does what #6832 asks: modified, deleted or renamed pins and migration-pins.json fail the gate with a fix-specific message, added pins pass, and the tests run the real gate in throwaway repos. Tests that changed (shards.test.ts) were wrong, not the code, and say so. Two things I would do next: (1) make an unresolvable base or a failed diff fail the check when FORGE_CHECK_BASE is unset or set-but-bad; today the gate fails open with only a stderr line, so a misconfigured check silently stops protecting history. (2) Fold the pinRefusal name/deleted/onBase message logic into pin_edits.ts as a pure function so it is testable without git.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs