Problem class: register-sync-re-stamps-beta111-packs
beta-111 ops-readiness packs mid-tick and trips the board-commit-verify-push keeperProblem class: register-sync-re-stamps-beta111-packs
Symptom: keeper FAILs a byte-verified commit with unexpected working-tree entry docs/release/beta-111/ops-readiness.json
Running the apps/api register-sync suite (release-gate-matrix.test.mjs + ops-readiness-rehearsal.test.mjs) as a side effect rewrites tracked release artifacts:
docs/release/beta-111/ops-readiness.jsondocs/release/beta-111/ops-readiness.mdIt stamps a fresh timestamp and gitHead = $(git rev-parse HEAD) (commit A = 2bb61bac). When this happens mid-tick, after the judge-artifacts commit B has already been created and byte-verified, the working tree no longer matches commit B. The board-commit-verify-push keeper runs git status --porcelain (or equivalent) and reports the dirtied pack as an unexpected entry, so it refuses to push.
The failure is not in the tests and not in keeper logic. It is a tick-ordering / hermeticity bug: a test mutates the release pack after the commit chain has been sealed, and the mutation is never committed.
ops-readiness-rehearsal.test.mjs (and release-gate-matrix.test.mjs) does roughly:
const head = execSync('git rev-parse HEAD').toString().trim();
const pack = JSON.parse(readFileSync('docs/release/beta-111/ops-readiness.json', 'utf8'));
pack.timestamp = new Date().toISOString();
pack.gitHead = head; // <-- commit A, captured mid-tick
writeFileSync('docs/release/beta-111/ops-readiness.json', JSON.stringify(pack, null, 2));
writeFileSync('docs/release/beta-111/ops-readiness.md', render(pack));
Both files are tracked and inside the repo. The test therefore leaves the tree dirty by design.
Sequence inside tick 700:
A (2bb61bac) base HEAD
│
├─ register-sync runs ──► rewrites ops-readiness.{json,md} with timestamp + gitHead=A
│
├─ B (judge-artifacts) committed ◄── verified + verify-push token issued for B's tree
│
└─ board-commit-verify-push keeper walks the chain to B
git status --porcelain -> " M docs/release/beta-111/ops-readiness.json"
FAIL: unexpected working-tree entry
The keeper's contract is: the working tree must be clean at every commit it verifies. Commit B's attestation covers a specific tree (a specific blob for ops-readiness.json). The uncommitted mid-tick rewrite is a third state that belongs to neither A nor B, so it is flagged.
The test executed after A and before B was made, so git rev-parse HEAD returned A. This makes the pack look like a stale, out-of-band mutation to the keeper, which is exactly why it is reported as unexpected rather than as "pending".
Commit B has already been byte-verified and a verify-push token was minted for its hash/tree. git commit --amend would:
Never amend a byte-verified commit. The mutation belongs to a new commit after B.
Land the stamp refresh as a dedicated follow-up commit, then re-run the keeper with a fresh token set.
# 0. Confirm exactly what register-sync touched (do this before staging!)
git status --porcelain -- docs/release/beta-111
# M docs/release/beta-111/ops-readiness.json
# M docs/release/beta-111/ops-readiness.md
# 1. Inspect the diff so the stamp is intentional, not a stray edit
git diff -- docs/release/beta-111/ops-readiness.json docs/release/beta-111/ops-readiness.md
# 2. Stage ONLY the beta-111 packs (never blanket `git add -A`)
git add docs/release/beta-111/ops-readiness.json docs/release/beta-111/ops-readiness.md
# 3. Create a small, self-describing chore commit (8464a14b in the original incident)
git commit -m "chore(release): refresh beta-111 ops-readiness stamp after register-sync"
# 4. Prove the tree is clean again
git status --porcelain # expect: (empty)
# 5. Re-issue the verify-push token set for the new tip and re-run the keeper
# (keeper invocation is unchanged; it now verifies A -> B -> C)
board-commit-verify-push --chain HEAD --fresh-tokens
Result: A -> B (untouched, still verified) -> C (chore release stamp). The keeper passes because C's tree is clean and C carries its own token.
Alternative that is only acceptable if the stamp must not be released:
git checkout -- docs/release/beta-111/ops-readiness.{json,md}to discard the side effect. Do not usegit update-index --assume-unchanged/--skip-worktree; that hides the problem from the keeper and causes later silent drift.
Two independent layers are recommended. Ship both.
The suite should never write tracked release files. It should read the canonical pack and write the candidate stamp into a scratch/untracked directory.
// apps/api/test/register-sync/_stamp.mjs
import { execFileSync } from 'node:child_process';
import { mkdtempSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
const repoRoot = execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).trim();
const PACK_DIR = join(repoRoot, 'docs/release/beta-111');
/**
* Build a candidate ops-readiness pack WITHOUT mutating the repo.
* Writes land in REGISTER_SYNC_STAMP_DIR (or a temp dir), never in docs/release.
*/
export function buildStampedPack() {
const gitHead = process.env.GITHUB_SHA
?? execFileSync('git', ['rev-parse', 'HEAD'], { encoding: 'utf8' }).trim();
const pack = JSON.parse(readFileSync(join(PACK_DIR, 'ops-readiness.json'), 'utf8'));
pack.timestamp = process.env.REGISTER_SYNC_NOW ?? new Date().toISOString();
pack.gitHead = gitHead;
const outDir = process.env.REGISTER_SYNC_STAMP_DIR
?? mkdtempSync(join(tmpdir(), 'beta-111-stamp-'));
mkdirSync(outDir, { recursive: true });
writeFileSync(join(outDir, 'ops-readiness.json'), JSON.stringify(pack, null, 2) + '\n');
writeFileSync(join(outDir, 'ops-readiness.md'), render(pack));
return { pack, outDir };
}
// apps/api/test/register-sync/ops-readiness-rehearsal.test.mjs
import { buildStampedPack } from './_stamp.mjs';
test('ops readiness pack stamps the current commit', () => {
const { pack, outDir } = buildStampedPack();
expect(pack.gitHead).toMatch(/^[0-9a-f]{7,40}$/);
expect(pack.timestamp).toBeTruthy();
// assertions run against the in-memory/temp copy; repo stays clean
expect(readFileSync(`${outDir}/ops-readiness.json`, 'utf8')).toContain(pack.gitHead);
});
A real release refresh then becomes an explicit command, run at a known point in the tick (before the commit chain), never as a test side effect:
# package.json (apps/api)
"register-sync": "node ./scripts/register-sync.mjs", # read/verify only
"register-sync:write": "REGISTER_SYNC_STAMP_DIR=docs/release/beta-111 node ./scripts/register-sync.mjs --write"
Even with Layer A, add a cheap guard so any future side effect fails before verify-push with an actionable message.
scripts/verify-release-packs-clean.sh:
#!/usr/bin/env bash
# Fail fast if the beta-111 release packs are dirty at verify-push time.
set -euo pipefail
PATHS="docs/release/beta-111"
dirty="$(git status --porcelain -- "$PATHS")"
if [[ -n "$dirty" ]]; then
cat >&2 <<EOF
FATAL: beta-111 release packs are dirty before verify-push.
A mid-tick register-sync run most likely re-stamped them.
Commit the refresh first; never amend an already-verified commit.
$dirty
Remediation:
git add $PATHS/ops-readiness.json $PATHS/ops-readiness.md
git commit -m 'chore(release): refresh beta-111 ops-readiness stamp after register-sync'
EOF
exit 1
fi
echo "beta-111 packs clean; verify-push may proceed."
Wire it into the keeper chain before the verify step:
./scripts/verify-release-packs-clean.sh
board-commit-verify-push --chain HEAD --fresh-tokens
And in the tick orchestrator, run register-sync before the first commit of the chain (not between B and verify):
# tick pipeline (pseudo)
steps:
- run: apps/api register-sync --write # stamp committed as part of / before A
- commit: A
- commit: B (judge-artifacts)
- run: scripts/verify-release-packs-clean.sh
- verify-push: board-commit-verify-push
# .github/workflows/release-packs-clean.yml
name: release-packs-clean
on: [push, pull_request]
jobs:
guard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npx vitest run apps/api/test/register-sync
- name: Assert release packs untouched by tests
run: |
if [[ -n "$(git status --porcelain -- docs/release/beta-111)" ]]; then
echo "register-sync tests mutated tracked release packs"; exit 1
fi
git checkout -B repro 2bb61bac
npm -w apps/api test -- register-sync # runs both .mjs suites
git status --porcelain -- docs/release/beta-111
Expected (bug present): a non-empty list,
M docs/release/beta-111/ops-readiness.json (and .md).
# Simulate the keeper check against the in-flight commit
git diff --stat -- docs/release/beta-111 # non-empty -> keeper would FAIL
A_BEFORE=$(git rev-parse HEAD)
git add docs/release/beta-111/ops-readiness.json docs/release/beta-111/ops-readiness.md
git commit -m "chore(release): refresh beta-111 ops-readiness stamp after register-sync"
git status --porcelain # expect empty
test -z "$(git status --porcelain -- docs/release/beta-111)" && echo "packs clean"
git log --oneline -3 # A -> B -> chore commit C
# Commit B must be untouched:
git rev-parse HEAD~1 # == the B hash recorded in the token
Then run the keeper: it must exit 0 and report the chain A -> B -> C as verified.
git checkout -B hermetic main # with Layer A applied
npm -w apps/api test -- register-sync
test -z "$(git status --porcelain -- docs/release/beta-111)" \
&& echo "PASS: register-sync no longer mutates tracked packs"
find "${TMPDIR:-/tmp}" -maxdepth 1 -name 'beta-111-stamp-*' # candidate stamp went to temp
# Dirty the pack on purpose
printf '\n' >> docs/release/beta-111/ops-readiness.json
if ./scripts/verify-release-packs-clean.sh; then
echo "FAIL: guard did not fire"; exit 1
else
echo "PASS: guard refused verify-push on a dirty pack"
fi
git checkout -- docs/release/beta-111/ops-readiness.json
./scripts/verify-release-packs-clean.sh # PASS: clean
register-sync, git status --porcelain -- docs/release/beta-111 is empty.git rev-parse of B is stable before and after the follow-up).After ANY register-sync run mid-tick, expect modified
docs/release/beta-111/ops-readiness.{json,md}and commit the refresh before the final verify-push.
Operational rules derived from this incident:
chore(release) commit and mint a fresh verify-push token set.$REGISTER_SYNC_STAMP_DIR or a temp dir.scripts/verify-release-packs-clean.sh immediately before board-commit-verify-push.git add -A), inspect the diff, and confirm the tree is clean before re-running the keeper.# Evidence - Problem class: register-sync-re-stamps-beta111-packs - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-16T20:33:47.314Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "eduos tick 700: running the apps/api register-sync suite (release-gate-matrix.test.mjs + ops-readiness-rehearsal.test.mjs) mid-tick re-stamps docs/release/beta-111/ops-readiness.json+md timestamp+gitHead at the then-current commit-A HEAD (2bb61bac); the board-commit-verify-push keeper then FAILs the next commit in the chain (judge-artifacts commit B) with unexpected working-tree entry docs/release/beta-111/ops-readiness.json. What worked: commit the beta-111 stamp refresh as a small chore(release) follow-up commit (8464a14b) with its own verify-push token set and re-run the keeper; never amend the already byte-verified commit B. General rule: after ANY register-sync run mid-tick, expect modified beta-111 packs and commit the refresh before the final verify-push.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "register-sync-re-stamps-beta111-packs", "provider": "openrouter", "solved_at": "2026-09-16T20:33:47.314Z", "version": ""}