Problem class: gitreins-judge-tier1-tests-step-timeout-suite-growth
Solution written to /workspace/solution.md. Full content below.
tests step dies at the 600s step timeout after MOB-037 grew the suiteProblem class: gitreins-judge-tier1-tests-step-timeout-suite-growth
Repo: eduos pnpm monorepo (apps/api, apps/web, packages/shared)
Judge: gitreins tier1 with an explicit pipeline block in .gitreins/config.yaml
Two independent problems were being conflated by the truncated judge log:
pnpm -r suite now needs ~750s wall (api ~270s + web ~440s after MOB-037 added 52 load-simulation tests), but the binding limit is still 600. Under an explicit pipeline: block the step-level timeout is the knob that binds; test_timeout alone is not enough. Raise both 600 -> 1200 in the same commit.release-gate-matrix reports generated-appendix-differs-from-register because board regen artifacts were never committed. Regenerate and commit those artifacts before the retry so the settled tree is exactly what tier1 tests.Then gitreins judge <id> retry is idempotent. This follows the established ladder: t298 raised 120 -> 600; t720 raises 600 -> 1200.
t298 set two things to 600:
| Location | Purpose |
|---|---|
test_timeout: 600 (global/pipeline-level) |
gitreins' own test-harness budget / default applied when a step doesn't override it |
pipeline.stages.tier1.steps.tests.timeout: 600 |
the step limit actually enforced on the spawned command |
When an explicit pipeline: block is present, the per-step timeout overrides the global budget for that step. Changing only test_timeout leaves the command killed at the old step limit. Both must be raised.
api ~270s
web ~440s (base + 52 MOB-037 load-sim tests)
rest ~ 40s
------
~750s wall > 600s step timeout -> killed
1200s gives ~1.6x headroom over the observed 750s.
The tier1 tests leg output is truncated at suite start. A timeout kill is therefore not narrated — no "timed out after 600s" line survives into the summary, so a SIGTERM kill looks like a generic FAIL, and any real assertion failure earlier in the run is hidden.
| Signal | Meaning |
|---|---|
process exits at/near 600s, output stops mid-suite, no vitest summary, shell reports exit 124/SIGTERM |
timeout kill → raise step timeout + test_timeout |
process completes, vitest prints FAIL / Test Files N failed, exit 1 |
genuine test failure → fix code/artifacts (here: regen) |
Even with a raised timeout, tier1 can still fail on release-gate-matrix > generated-appendix-differs-from-register. The matrix test compares a committed register against a freshly generated appendix. When the board regen output was produced locally but not committed, the settled tree the judge checks out is stale, so the generated appendix "differs from register." This is a staleness class, not a flaky test.
Fix ordering matters: regen → commit artifacts → retry. Retrying first tests the stale tree; raising the timeout without committing regen output just waits longer for the same assertion.
gitreins judge <id> retry re-runs the same pipeline against current HEAD. Once both knobs are raised and regen artifacts are committed, the retry is deterministic: same config, same settled tree, same result every time. No judge-side cleanup needed.
grep -nE 'test_timeout|timeout' .gitreins/config.yaml
# expected hits:
# <N>:test_timeout: 600
# <M>: timeout: 600 # inside pipeline.stages.tier1.steps -> tests
600 -> 1200--- a/.gitreins/config.yaml
+++ b/.gitreins/config.yaml
@@
-test_timeout: 600
+test_timeout: 1200
@@
pipeline:
stages:
tier1:
steps:
- name: lint
run: pnpm -r lint
- name: tests
run: pnpm -r test
- timeout: 600
+ timeout: 1200
YAML-aware alternative (avoids clobbering an unrelated 600):
yq -i '.test_timeout = 1200' .gitreins/config.yaml
yq -i '.pipeline.stages.tier1.steps[] |=
(select(.name == "tests") | .timeout) = 1200' .gitreins/config.yaml
grep -nE 'test_timeout|timeout' .gitreins/config.yaml
pnpm -r --if-present run board:regen 2>&1 | tee /tmp/board-regen.log
git status --porcelain # confirm only regen artifacts changed
git add -A # or add the specific generated paths
git commit -m "chore(board): regen release-gate-matrix artifacts for MOB-037"
git status --porcelain # must be EMPTY before retry — settled tree
( cd apps/api && pnpm test ) 2>&1 | tee /tmp/api-tests.log
grep -nE 'Test Files|Tests |Duration|FAIL|timed out|SIGTERM' /tmp/api-tests.log
( cd apps/web && pnpm test ) 2>&1 | tee /tmp/web-tests.log
grep -nE 'Test Files|Tests |Duration|FAIL|timed out|SIGTERM' /tmp/web-tests.log
time ( pnpm -r test ) 2>&1 | tee /tmp/all-tests.log
# timeout kill artifacts
grep -nE 'signal: SIGTERM|exit code: 124|Command timed out|test_timeout' /tmp/*-tests.log
# genuine failure artifacts (the staleness class)
grep -nE 'release-gate-matrix|generated-appendix-differs-from-register' /tmp/*-tests.log
gitreins judge <id> retry # safe to run more than once; deterministic
bash
grep -nE 'test_timeout|timeout' .gitreins/config.yaml
# expect: test_timeout: 1200 AND the tier1 tests step timeout: 1200
bash
python3 - <<'PY'
import yaml
c = yaml.safe_load(open('.gitreins/config.yaml'))
assert c['test_timeout'] == 1200, c['test_timeout']
steps = c['pipeline']['stages']['tier1']['steps']
tests = next(s for s in steps if s.get('name') == 'tests')
assert tests['timeout'] == 1200, tests
print('OK: test_timeout=1200, tier1.steps.tests.timeout=1200')
PY
(Adapt the steps accessor if it uses a mapping keyed by step name: c['pipeline']['stages']['tier1']['steps']['tests']['timeout'].)
bash
git status --porcelain # must print nothing
git log -1 --stat # shows regen artifacts in the commit
Standalone suites pass and finish well under 1200s — every lane log ends with a vitest summary, no generated-appendix-differs-from-register line.
Full-suite wall time < 1200s: time ( pnpm -r test ) → ~750s.
Judge retry passes and is idempotent: gitreins judge <id> retry twice → same PASS.
Negative control (optional): scratch copy with test_timeout: 1200 but step timeout: 600 still dies at 600s — proves the step-level knob binds.
git revert <config-commit> (1200 → 600).pnpm -r test measures > 600s.Commit message
fix(gitreins): raise test_timeout and tier1 tests step timeout 600->1200
Full pnpm -r suite is ~750s after MOB-037 added 52 web load-sim tests.
Under the explicit pipeline block the step timeout binds, so both knobs
move (precedent: t298 120->600, t720 600->1200). Board regen artifacts
committed first so tier1 tests the settled tree; judge retry idempotent.
Note: no repo was mounted at ~ (only /workspace/problem.json), so the document is written from the supplied diagnosis; the commands/diff are directly applicable once run from the repo root.
# Evidence - Problem class: gitreins-judge-tier1-tests-step-timeout-suite-growth - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-18T12:22:52.498Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Judge tier1 tests leg fails after the test suite grows past the configured step timeout. The t298-era fix set test_timeout AND the step-level timeout (line under pipeline.stages.tier1.steps tests) to 600s; that covered api ~270s. After apps/web grew to ~440s wall (52 heavy load-simulation tests added by task MOB-037), the full pnpm -r suite needs ~750s and the step dies. Two pitfalls: (1) under an explicit pipeline block the STEP-level timeout is the knob that binds - test_timeout alone is not enough, check BOTH locations; (2) the judge summary truncates the test output so the timeout is not narrated - run the failing suite standalone (the sibling lane pattern: cd apps/api and pnpm test to a log file, read the vitest summary) to separate a genuine test failure (e.g. release-gate-matrix generated-appendix-differs-from-register staleness class) from a timeout kill. Fix: raise both knobs one rung (600->1200) in the same commit, then gitreins judge <id> retry is idempotent. Commit the regen artifacts BEFORE the retry so the settled tree is what tier1 tests.", "environment": "eduos pnpm monorepo (apps/api, apps/web, packages/shared) judged by gitreins tier1 with an explicit pipeline block in .gitreins/config.yaml", "language": "yaml", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "gitreins-judge-tier1-tests-step-timeout-suite-growth", "provider": "openrouter", "solved_at": "2026-09-18T12:22:52.499Z", "version": "Beta a858acc6"}Solution written to /workspace/solution.md. Full content below.
tests step dies at the 600s step timeout after MOB-037 grew the suiteProblem class: gitreins-judge-tier1-tests-step-timeout-suite-growth
Repo: eduos pnpm monorepo (apps/api, apps/web, packages/shared)
Judge: gitreins tier1 with an explicit pipeline block in .gitreins/config.yaml
Two independent problems were being conflated by the truncated judge log:
pnpm -r suite now needs ~750s wall (api ~270s + web ~440s after MOB-037 added 52 load-simulation tests), but the binding limit is still 600. Under an explicit pipeline: block the step-level timeout is the knob that binds; test_timeout alone is not enough. Raise both 600 -> 1200 in the same commit.release-gate-matrix reports generated-appendix-differs-from-register because board regen artifacts were never committed. Regenerate and commit those artifacts before the retry so the settled tree is exactly what tier1 tests.Then gitreins judge <id> retry is idempotent. This follows the established ladder: t298 raised 120 -> 600; t720 raises 600 -> 1200.
t298 set two things to 600:
| Location | Purpose |
|---|---|
test_timeout: 600 (global/pipeline-level) |
gitreins' own test-harness budget / default applied when a step doesn't override it |
pipeline.stages.tier1.steps.tests.timeout: 600 |
the step limit actually enforced on the spawned command |
When an explicit pipeline: block is present, the per-step timeout overrides the global budget for that step. Changing only test_timeout leaves the command killed at the old step limit. Both must be raised.
api ~270s
web ~440s (base + 52 MOB-037 load-sim tests)
rest ~ 40s
------
~750s wall > 600s step timeout -> killed
1200s gives ~1.6x headroom over the observed 750s.
The tier1 tests leg output is truncated at suite start. A timeout kill is therefore not narrated — no "timed out after 600s" line survives into the summary, so a SIGTERM kill looks like a generic FAIL, and any real assertion failure earlier in the run is hidden.
| Signal | Meaning |
|---|---|
process exits at/near 600s, output stops mid-suite, no vitest summary, shell reports exit 124/SIGTERM |
timeout kill → raise step timeout + test_timeout |
process completes, vitest prints FAIL / Test Files N failed, exit 1 |
genuine test failure → fix code/artifacts (here: regen) |
Even with a raised timeout, tier1 can still fail on release-gate-matrix > generated-appendix-differs-from-register. The matrix test compares a committed register against a freshly generated appendix. When the board regen output was produced locally but not committed, the settled tree the judge checks out is stale, so the generated appendix "differs from register." This is a staleness class, not a flaky test.
Fix ordering matters: regen → commit artifacts → retry. Retrying first tests the stale tree; raising the timeout without committing regen output just waits longer for the same assertion.
gitreins judge <id> retry re-runs the same pipeline against current HEAD. Once both knobs are raised and regen artifacts are committed, the retry is deterministic: same config, same settled tree, same result every time. No judge-side cleanup needed.
grep -nE 'test_timeout|timeout' .gitreins/config.yaml
# expected hits:
# <N>:test_timeout: 600
# <M>: timeout: 600 # inside pipeline.stages.tier1.steps -> tests
600 -> 1200--- a/.gitreins/config.yaml
+++ b/.gitreins/config.yaml
@@
-test_timeout: 600
+test_timeout: 1200
@@
pipeline:
stages:
tier1:
steps:
- name: lint
run: pnpm -r lint
- name: tests
run: pnpm -r test
- timeout: 600
+ timeout: 1200
YAML-aware alternative (avoids clobbering an unrelated 600):
yq -i '.test_timeout = 1200' .gitreins/config.yaml
yq -i '.pipeline.stages.tier1.steps[] |=
(select(.name == "tests") | .timeout) = 1200' .gitreins/config.yaml
grep -nE 'test_timeout|timeout' .gitreins/config.yaml
pnpm -r --if-present run board:regen 2>&1 | tee /tmp/board-regen.log
git status --porcelain # confirm only regen artifacts changed
git add -A # or add the specific generated paths
git commit -m "chore(board): regen release-gate-matrix artifacts for MOB-037"
git status --porcelain # must be EMPTY before retry — settled tree
( cd apps/api && pnpm test ) 2>&1 | tee /tmp/api-tests.log
grep -nE 'Test Files|Tests |Duration|FAIL|timed out|SIGTERM' /tmp/api-tests.log
( cd apps/web && pnpm test ) 2>&1 | tee /tmp/web-tests.log
grep -nE 'Test Files|Tests |Duration|FAIL|timed out|SIGTERM' /tmp/web-tests.log
time ( pnpm -r test ) 2>&1 | tee /tmp/all-tests.log
# timeout kill artifacts
grep -nE 'signal: SIGTERM|exit code: 124|Command timed out|test_timeout' /tmp/*-tests.log
# genuine failure artifacts (the staleness class)
grep -nE 'release-gate-matrix|generated-appendix-differs-from-register' /tmp/*-tests.log
gitreins judge <id> retry # safe to run more than once; deterministic
bash
grep -nE 'test_timeout|timeout' .gitreins/config.yaml
# expect: test_timeout: 1200 AND the tier1 tests step timeout: 1200
bash
python3 - <<'PY'
import yaml
c = yaml.safe_load(open('.gitreins/config.yaml'))
assert c['test_timeout'] == 1200, c['test_timeout']
steps = c['pipeline']['stages']['tier1']['steps']
tests = next(s for s in steps if s.get('name') == 'tests')
assert tests['timeout'] == 1200, tests
print('OK: test_timeout=1200, tier1.steps.tests.timeout=1200')
PY
(Adapt the steps accessor if it uses a mapping keyed by step name: c['pipeline']['stages']['tier1']['steps']['tests']['timeout'].)
bash
git status --porcelain # must print nothing
git log -1 --stat # shows regen artifacts in the commit
Standalone suites pass and finish well under 1200s — every lane log ends with a vitest summary, no generated-appendix-differs-from-register line.
Full-suite wall time < 1200s: time ( pnpm -r test ) → ~750s.
Judge retry passes and is idempotent: gitreins judge <id> retry twice → same PASS.
Negative control (optional): scratch copy with test_timeout: 1200 but step timeout: 600 still dies at 600s — proves the step-level knob binds.
git revert <config-commit> (1200 → 600).pnpm -r test measures > 600s.Commit message
fix(gitreins): raise test_timeout and tier1 tests step timeout 600->1200
Full pnpm -r suite is ~750s after MOB-037 added 52 web load-sim tests.
Under the explicit pipeline block the step timeout binds, so both knobs
move (precedent: t298 120->600, t720 600->1200). Board regen artifacts
committed first so tier1 tests the settled tree; judge retry idempotent.
Note: no repo was mounted at ~ (only /workspace/problem.json), so the document is written from the supplied diagnosis; the commands/diff are directly applicable once run from the repo root.
# Evidence - Problem class: gitreins-judge-tier1-tests-step-timeout-suite-growth - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-18T12:22:52.498Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Judge tier1 tests leg fails after the test suite grows past the configured step timeout. The t298-era fix set test_timeout AND the step-level timeout (line under pipeline.stages.tier1.steps tests) to 600s; that covered api ~270s. After apps/web grew to ~440s wall (52 heavy load-simulation tests added by task MOB-037), the full pnpm -r suite needs ~750s and the step dies. Two pitfalls: (1) under an explicit pipeline block the STEP-level timeout is the knob that binds - test_timeout alone is not enough, check BOTH locations; (2) the judge summary truncates the test output so the timeout is not narrated - run the failing suite standalone (the sibling lane pattern: cd apps/api and pnpm test to a log file, read the vitest summary) to separate a genuine test failure (e.g. release-gate-matrix generated-appendix-differs-from-register staleness class) from a timeout kill. Fix: raise both knobs one rung (600->1200) in the same commit, then gitreins judge <id> retry is idempotent. Commit the regen artifacts BEFORE the retry so the settled tree is what tier1 tests.", "environment": "eduos pnpm monorepo (apps/api, apps/web, packages/shared) judged by gitreins tier1 with an explicit pipeline block in .gitreins/config.yaml", "language": "yaml", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "gitreins-judge-tier1-tests-step-timeout-suite-growth", "provider": "openrouter", "solved_at": "2026-09-18T12:22:52.499Z", "version": "Beta a858acc6"}