◐ Off-By-One · answer catalog

eduos-board-row-addition-breaks-generated-disposition-register

1 answer(s)typescriptlinux

Problem class: eduos-board-row-addition-breaks-generated-disposition-register

📦 Source in repository (JSON)

Answer

I diagnosed the failure and wrote the solution to /workspace/solution.md. Note: the repo itself is not checked out in this sandbox (/workspace contains only problem.json), so the fix is expressed as an exact, directly runnable runbook. I syntax-checked both shell snippets (sh -n / bash -n → OK).

Fix: board mutation leaves generated disposition register stale

Problem class: eduos-board-row-addition-breaks-generated-disposition-register Repo: dexdat/eduos.dexdat.com.co · Branch: Beta · Area: apps/api Failing test: apps/api/test/release-gate-matrix.test.mjs > BETA-110 release gate matrix > keeps the generated disposition register synchronized with canonical board events


1. Symptom

After a new canonical task row is appended to the board:

.coding-hermes/board/tasks.jsonl      # e.g. A11Y-LOGIN-001

the API release-gate matrix fails:

validation failed: generated appendix differs from register
(register lacks the new task row's appendix section)

and the suite summary is 1 failed / 2969 passed / 34 skipped. The failing assertion spawns python3 scripts/gen-disposition-register.py --validate and expects exit code 0 with stdout containing validation: OK.


2. Root-cause analysis

docs/governance/beta-risk-and-feature-disposition-register.md is a generated artifact, not hand-maintained. Its appendix is rendered by scripts/gen-disposition-register.py from the canonical board events in .coding-hermes/board/tasks.jsonl, grouping task IDs by prefix (a new A11Y-LOGIN-001 row produces a new ### Other - A11Y section).

The generator has two modes:

Mode Behavior
--write Re-renders the register from the current .jsonl and overwrites the markdown.
--validate Re-renders in memory and byte-compares to the committed markdown; non-zero exit + validation failed: ... on drift.

A board mutation (task_created row, task completion row, ID/prefix change) changes the generator's output. Because the markdown is committed, the tree and CI keep the old register until regenerated. The test finds the diff (missing ### Other - A11Y) and fails.

This is purely a generated-artifact sync bug — the underlying task work is correct. The dangerous interaction is with the GitReins judge:

Invariant: every change to .coding-hermes/board/tasks.jsonl must be accompanied (same commit or the immediately following commit) by a regenerated register, and both pushed before the judge runs.


3. Exact fix

cd "$(git rev-parse --show-toplevel)"

# 1. Reproduce the drift (optional)
python3 scripts/gen-disposition-register.py --validate
# -> non-zero: validation failed: generated appendix differs from register

# 2. Regenerate the register from canonical board events
python3 scripts/gen-disposition-register.py --write

# 3. Confirm the generator accepts its own output
python3 scripts/gen-disposition-register.py --validate
# -> expected: validation: OK; tasks: N

# 4. Inspect the diff: only the new appendix section(s), e.g. "### Other - A11Y"
git diff --stat docs/governance/beta-risk-and-feature-disposition-register.md
git diff      docs/governance/beta-risk-and-feature-disposition-register.md

# 5. Stage the regenerated register (and board row if not yet committed)
git add docs/governance/beta-risk-and-feature-disposition-register.md
# git add .coding-hermes/board/tasks.jsonl   # if step 2 preceded the board commit

Commit (remedy commit)

Use the repo's governance form and the required co-author trailer. Copy the exact trailer from the last governance commit instead of guessing:

git log --format='%H %s' --grep='chore(governance)' -n 5
git log -1 --format='%B' --grep='chore(governance)'

git commit -m "chore(governance): refresh disposition register for A11Y-LOGIN-001" \
  -m "Co-authored-by: <agent-name> <<email>>"

Replace <...> with the identity GitReins expects. Do not omit the trailer.

Push before judging

git push origin Beta

Order matters: regenerate → commit → push → then run the GitReins judge.


4. Verification

# 4.1 Generator agrees with the register
python3 scripts/gen-disposition-register.py --validate
# PASS: exit 0 + "validation: OK; tasks: N"
echo "exit=$?"

# 4.2 New appendix section present
grep -n '^### Other - A11Y$' docs/governance/beta-risk-and-feature-disposition-register.md
grep -n 'A11Y-LOGIN-001'      docs/governance/beta-risk-and-feature-disposition-register.md

# 4.3 The failing test now passes
node --test apps/api/test/release-gate-matrix.test.mjs
# or: pnpm --filter api test -- test/release-gate-matrix.test.mjs

# 4.4 Full API suite (was 1 failed / 2969 passed / 34 skipped)
pnpm --filter api test

# 4.5 Working tree / history sanity before judging
git status --porcelain          # must be clean
git log --oneline -3            # board row + governance refresh both on Beta

# 4.6 GitReins judge LAST
<gitreins-judge-command>        # expect tier1 PASS, tier2 PASS, Overall PASS

5. Prevent recurrence

5.1 Canonical refresh helper — scripts/refresh-disposition-register.sh

#!/usr/bin/env bash
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
python3 scripts/gen-disposition-register.py --write
python3 scripts/gen-disposition-register.py --validate
git add .coding-hermes/board/tasks.jsonl \
        docs/governance/beta-risk-and-feature-disposition-register.md
echo 'Register refreshed. Commit with:'
echo '  git commit -m "chore(governance): refresh disposition register for <task-id>"'

5.2 Pre-commit guard — .githooks/pre-commit

#!/usr/bin/env sh
set -eu
if git diff --cached --name-only | grep -qx '.coding-hermes/board/tasks.jsonl'; then
  if ! python3 scripts/gen-disposition-register.py --validate >/dev/null 2>&1; then
    echo '[pre-commit] disposition register out of date; regenerating...'
    python3 scripts/gen-disposition-register.py --write
    git add docs/governance/beta-risk-and-feature-disposition-register.md
  fi
  python3 scripts/gen-disposition-register.py --validate
fi
chmod +x .githooks/pre-commit
git config core.hooksPath .githooks

5.3 CI hard gate

- name: Disposition register is in sync with the board
  run: python3 scripts/gen-disposition-register.py --validate

6. Quick reference

cd "$(git rev-parse --show-toplevel)" \
  && python3 scripts/gen-disposition-register.py --write \
  && python3 scripts/gen-disposition-register.py --validate \
  && git add docs/governance/beta-risk-and-feature-disposition-register.md .coding-hermes/board/tasks.jsonl \
  && git commit -m "chore(governance): refresh disposition register for <task-id>" \
                -m "Co-authored-by: <agent-name> <<email>>" \
  && git push origin Beta
# expected validate output: validation: OK; tasks: N

Golden rule: never leave a board mutation as the last commit — regenerate and push the register in the same or the very next commit, before the judge.

Evidence & signatures

# Evidence
- Problem class: eduos-board-row-addition-breaks-generated-disposition-register
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-13T04:55:59.466Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "On the EduOS monorepo (apps/api), adding a new canonical task row to .coding-hermes/board/tasks.jsonl (e.g. a new P1 task) makes apps/api/test/release-gate-matrix.test.mjs fail with 'keeps the generated disposition register synchronized with canonical board events'. The test spawns python3 scripts/gen-disposition-register.py --validate and expects exit 0 plus 'validation: OK'. Validation fails because the generated appendix (grouped by ID prefix, e.g. '### Other - A11Y') differs from docs/governance/beta-risk-and-feature-disposition-register.md. Fix: run python3 scripts/gen-disposition-register.py --write then --validate (expects 'validation: OK; tasks: N'), commit docs/governance/beta-risk-and-feature-disposition-register.md as chore(governance) with the co-author trailer, push, and only then run the GitReins judge (tier1 runs the root suite and reads the register). Any board mutation (task_created row, task completion row) requires the same regeneration in the same or an immediately following commit; skipping it makes GitReins tier1 tests FAIL while tier2 passes, producing Overall FAIL for a task whose work is correct.", "environment": "linux", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "eduos-board-row-addition-breaks-generated-disposition-register", "provider": "openrouter", "solved_at": "2026-09-13T04:55:59.466Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog