loki-mode 9.74.0 → 9.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/completion-council.sh +24 -6
  4. package/autonomy/council-v2.sh +60 -13
  5. package/autonomy/lib/done-recognition.sh +73 -21
  6. package/autonomy/lib/proof-check.sh +43 -8
  7. package/autonomy/lib/voter-agents.sh +42 -5
  8. package/autonomy/loki +3 -0
  9. package/autonomy/prd-checklist.sh +77 -16
  10. package/autonomy/run.sh +38 -3
  11. package/dashboard/__init__.py +1 -1
  12. package/docs/INSTALLATION.md +1 -1
  13. package/docs/R3-COST-OBSERVABILITY-DESIGN.md +7 -1
  14. package/docs/exit-codes.md +21 -0
  15. package/docs/v10/ARCHITECT-CUTS.md +397 -234
  16. package/docs/v10/BOARD.md +84 -44
  17. package/docs/v10/GUARDS.md +45 -28
  18. package/loki-ts/dist/loki.js +341 -338
  19. package/mcp/__init__.py +1 -1
  20. package/package.json +1 -1
  21. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  22. package/web-app/dist/assets/{AdminPage-DaeYgQSE.js → AdminPage-Bw8oPnII.js} +1 -1
  23. package/web-app/dist/assets/{Avatar-CgwQi58_.js → Avatar-BwEtc3RH.js} +1 -1
  24. package/web-app/dist/assets/{Badge-Bwq-lpRh.js → Badge-C_-lfbUl.js} +1 -1
  25. package/web-app/dist/assets/{Button-BEf4Nher.js → Button-BdDGKKeF.js} +1 -1
  26. package/web-app/dist/assets/CockpitPage-Dx9d4fEm.js +47 -0
  27. package/web-app/dist/assets/{ComparePage-tFbdo90G.js → ComparePage-BKtAhhIJ.js} +1 -1
  28. package/web-app/dist/assets/{ErrorBoundary-Brewvgm9.js → ErrorBoundary-BuG16GpG.js} +1 -1
  29. package/web-app/dist/assets/{EvidenceReceiptPanel-h_82QBVa.js → EvidenceReceiptPanel-NATnqxKs.js} +1 -1
  30. package/web-app/dist/assets/{GitHubIssuesPanel-Dcg5xDMm.js → GitHubIssuesPanel-BgOwdOpj.js} +1 -1
  31. package/web-app/dist/assets/{GitHubPRsPanel-DFKzVyA1.js → GitHubPRsPanel-CBJyHI1c.js} +1 -1
  32. package/web-app/dist/assets/{HomePage-D21cM1Je.js → HomePage-BHj17Epq.js} +2 -2
  33. package/web-app/dist/assets/{LoginPage-DJ9yqMn4.js → LoginPage-Dig4H-HO.js} +1 -1
  34. package/web-app/dist/assets/{MagicPage-mwkjJhBy.js → MagicPage-w6WJ35PH.js} +1 -1
  35. package/web-app/dist/assets/{MetricsPage-D2q-PD-s.js → MetricsPage-CvjSUOWn.js} +1 -1
  36. package/web-app/dist/assets/{NotFoundPage-BtusJvgS.js → NotFoundPage-PAcYmGkU.js} +1 -1
  37. package/web-app/dist/assets/{ProjectPage-CRPALtO8.js → ProjectPage-CBkT5JyW.js} +3 -3
  38. package/web-app/dist/assets/{ProjectsPage-DuzABpfc.js → ProjectsPage-Cs6yuWEU.js} +1 -1
  39. package/web-app/dist/assets/{SettingsPage-DhJPX-Rf.js → SettingsPage-BU9F40Yn.js} +1 -1
  40. package/web-app/dist/assets/{ShowcasePage-CvgS47nu.js → ShowcasePage-jCNABTeT.js} +1 -1
  41. package/web-app/dist/assets/{SystemSettingsPage-l3Cv9YjY.js → SystemSettingsPage-Crmc-ryL.js} +1 -1
  42. package/web-app/dist/assets/{TeamsPage-DridGcnR.js → TeamsPage-DN8W-9m5.js} +1 -1
  43. package/web-app/dist/assets/{TemplatesPage-CTNsfp03.js → TemplatesPage-WvaXwZIl.js} +1 -1
  44. package/web-app/dist/assets/{TerminalOutput-BuyksqLh.js → TerminalOutput-Bf_do2tO.js} +1 -1
  45. package/web-app/dist/assets/{activity-DM2TKaBi.js → activity-CMl9JvHl.js} +1 -1
  46. package/web-app/dist/assets/{bell-D2PMLbbX.js → bell-CnjqTAUX.js} +1 -1
  47. package/web-app/dist/assets/{bot-BnN32Jxp.js → bot-BBprDFVS.js} +1 -1
  48. package/web-app/dist/assets/{check-CU128nw_.js → check-DW9Hq4y4.js} +1 -1
  49. package/web-app/dist/assets/{chevron-left-ehNW1Do7.js → chevron-left-DC9pMI2E.js} +1 -1
  50. package/web-app/dist/assets/{circle-alert-Cpw2gtOC.js → circle-alert-BJoll9YV.js} +1 -1
  51. package/web-app/dist/assets/{clock-BOZHdPVS.js → clock-BdHhRTHO.js} +1 -1
  52. package/web-app/dist/assets/{cloud-BZ2L9Fzi.js → cloud-C54B7EO9.js} +1 -1
  53. package/web-app/dist/assets/{code-xml-sSo522gu.js → code-xml-DwQK2vpV.js} +1 -1
  54. package/web-app/dist/assets/{database-DrR1xHzS.js → database-DsWVFir7.js} +1 -1
  55. package/web-app/dist/assets/{dollar-sign-CHE3T_rh.js → dollar-sign-DuRPNc2M.js} +1 -1
  56. package/web-app/dist/assets/{file-code-corner-CgcssyRQ.js → file-code-corner-C4j2P44-.js} +1 -1
  57. package/web-app/dist/assets/{file-plus-DtwfrxYH.js → file-plus-rnI2RZjF.js} +1 -1
  58. package/web-app/dist/assets/{globe-Dzla77iL.js → globe-BbBhsaS5.js} +1 -1
  59. package/web-app/dist/assets/{hammer-BAMdG66t.js → hammer-BxcycH3E.js} +1 -1
  60. package/web-app/dist/assets/{index-mQOnSYoW.js → index-xGj3noKA.js} +2 -2
  61. package/web-app/dist/assets/{layers-DhuyLqmc.js → layers-CcAOhZeY.js} +1 -1
  62. package/web-app/dist/assets/{loader-circle-DclFyQ3B.js → loader-circle-DN_Xjd5e.js} +1 -1
  63. package/web-app/dist/assets/{lock-C8v_bXNl.js → lock-Dn8AMO-D.js} +1 -1
  64. package/web-app/dist/assets/{package-B4AnjM5D.js → package-uroTpCjn.js} +1 -1
  65. package/web-app/dist/assets/{plus-DM95CmZI.js → plus-CYJAEX02.js} +1 -1
  66. package/web-app/dist/assets/{refresh-cw-CWaauzqX.js → refresh-cw-BUGsMChj.js} +1 -1
  67. package/web-app/dist/assets/{rotate-ccw-DxcvylpJ.js → rotate-ccw-C_4D-XGl.js} +1 -1
  68. package/web-app/dist/assets/{scroll-text-Dx-V_BpP.js → scroll-text-DrAJG0H3.js} +1 -1
  69. package/web-app/dist/assets/{server-Cj2EfoGN.js → server-Di6lHsM9.js} +1 -1
  70. package/web-app/dist/assets/{shield-alert-OlmWv7sU.js → shield-alert-DH1bNjkD.js} +1 -1
  71. package/web-app/dist/assets/{thumbs-up-CIpJhyTd.js → thumbs-up-Enk3ppj_.js} +1 -1
  72. package/web-app/dist/assets/{trash-2-BIkoZkY6.js → trash-2-CezqQT3x.js} +1 -1
  73. package/web-app/dist/assets/{trending-down-CI-OcCGt.js → trending-down-B_ChI0U7.js} +1 -1
  74. package/web-app/dist/assets/{trending-up-B0dpgKi-.js → trending-up-BtsvHd_-.js} +1 -1
  75. package/web-app/dist/assets/{upload-NhOBAjKA.js → upload-XiWa_WBM.js} +1 -1
  76. package/web-app/dist/assets/{usePolling-_QRF6f7x.js → usePolling-B6Hxwbk1.js} +1 -1
  77. package/web-app/dist/assets/{user-kRNvOpun.js → user-oL_Oya-S.js} +1 -1
  78. package/web-app/dist/index.html +1 -1
  79. package/web-app/dist/assets/CockpitPage-Bj41Xtg9.js +0 -47
@@ -1,277 +1,440 @@
1
1
 
2
2
 
3
- ## 19:57Z cut (S-174..S-193)
3
+ ## 20:59Z cut (S-214..S-233)
4
4
 
5
- **Checked before cutting.**
6
- - **P2.verify-exit-contract and P2.fast-verify-inconclusive-not-zero.** Both are already listed in `tests/moat/pending.txt` with milestone v10.0.0. `tests/moat/run.sh` accepts them as FAIL, so they are not a regression on main.
7
- - The fix is the breaking renumber of verify exit codes (BACKLOG 4). The 19:10Z cut held that for the CEO, and this cut does not undo that.
8
- - When the renumber lands, the Captain promotes each case by deleting its pending.txt line.
9
- - S-182 does the part that breaks nothing: it documents the current codes, so users stop reading exit 0 from `--fast` as a pass.
10
- - **The run-all-tests missing-argument gap is real.** Probe: `bash -c 'set -euo pipefail; f(){ local a="$1"; local b="$2"; }; f x; echo after'` printed `$2: unbound variable` and exited 1 without printing `after`.
11
- - The missing-script branch's `return 1` also stops the whole runner under `set -e`. That is the same "later suites silently skipped" problem.
12
- - **Already handled, so dropped:**
13
- - BACKLOG 35 (0-byte baseline test in tests/test-moat-runner.sh).
14
- - BACKLOG 60 wording.
15
- - BACKLOG 91 (stage status not_run).
16
- - BACKLOG 116 Close button.
17
- - Standalone VERIFIED WITH GAPS colour and receipt ordering.
18
- - memory-browser null handling.
19
- - learning-dashboard signals.
20
- - GUARDS 13, whose mechanical check is S-139 (released). The PENDING text in GUARDS.md is out of date.
21
- - **A `.catch(() => null)` lint was considered and dropped.** 16 sites match, and most of them already render "Could not load". It would pin nothing.
5
+ **Checked before cutting.** All reads are on main at 04af133a.
22
6
 
23
- ### S-174: run_test with a missing or empty argument stops run-all-tests.sh with no summary
24
- - Files: tests/run-all-tests.sh (the run_test guard and the missing-script return only), tests/test-run-all-missing-arg.sh (new)
25
- - Tier: MEDIUM. **Captain-built**, because tests/run-all-tests.sh is a hot file. The Captain also registers the new test.
26
- - Red:
27
- - `run_test "X"` stops the runner with `$2: unbound variable`. There is no summary and every later suite is skipped.
28
- - `run_test "X" ""` passes today: `bash -c ""` exits 0.
29
- - A missing script returns 1, and under `set -e` that stops the run.
7
+ **Held dependencies, checked against main.**
8
+ - **Merged:**
9
+ - S-180 (22ff5a44)
10
+ - S-179 (94035ac4)
11
+ - S-175 (6fab92ce)
12
+ - S-178 (c8b4c8c0)
13
+ - S-187 (03070f62)
14
+ - **Still in flight:** S-194, S-195, S-197, S-198.
15
+ - **What that unblocks:**
16
+ - BACKLOG 147: S-180 has merged, and S-198's region (about 1934-1994, fixture about 3301) does not overlap `HELPER_LOCAL_DECL_TMPL` (1182, used about 2186). Cut as S-214.
17
+ - dashboard/server.py items from BACKLOG 118: S-178 has merged. The council-state fallback (8638) and the notifications zero summary (8909) are already handled on main. The skill-session `running_agents: 0` is cut as S-222. The other two are held or dropped (see below).
18
+ - ProjectWorkspace phase labels and Replay Build: S-187 has merged. Cut as S-230.
19
+ - **Still held:**
20
+ - BACKLOG 36: waits for S-198.
21
+ - BACKLOG 19 and the bash `loki proof verify` interpreter: wait for S-197.
22
+ - BACKLOG 99, bash half: waits for S-194 and S-195.
23
+
24
+ **Found shipped on main, but the backlog text still reads open.** Future cuts can skip these:
25
+ - 35: tests/test-moat-runner.sh:653
26
+ - 37 and 60: loki-ts/src/runner/quality_gates.ts about 565-615
27
+ - 72 and 80, the base and start-sha part: run.sh 9888-9895. The warning wording is still open and is cut as S-233.
28
+ - 91: run.sh 26343-26345
29
+ - 102: run.sh 10951-10955
30
+ - 104 and 120: tests/run-all-tests.sh 965-966
31
+ - 116, the overview council gate card: loki-overview.js about 395-414
32
+ - 118:
33
+ - standalone receipt order and the VERIFIED WITH GAPS colour: build-standalone.js 2517-2531
34
+ - council-state and notifications: server.py 8638, 8909
35
+ - 150: S-79
36
+ - The memory browser's null lists (loki-memory-browser.js 448-506) and the cockpit's ChangeReview and RiskPanel errors are also handled.
37
+
38
+ **Dropped on merit.**
39
+ - **`/cost` priced at Sonnet rates with no estimate label (BACKLOG 118).**
40
+ - The Sonnet price only applies to a record that is missing `cost_usd`. No Loki writer produces one: run.sh 9121 always writes `model` and `cost_usd` (0 when unmeasured), and no Bun efficiency writer exists.
41
+ - It would close the way S-208 did.
42
+ - **Removing T6 from test-sentrux-init-rules.sh as a speed-up.**
43
+ - autonomy/loki has no `.sh` extension, so run-shellcheck.sh's `find` never lints it. T6 is its only lint.
44
+ - S-232 moves that lint rather than deleting it.
45
+
46
+ **New class found: inline Python that imports from the repo under review.**
47
+ - The pattern is `python3 -` or bare `python3 -c` run with the target repo as cwd, which puts `''` first on sys.path.
48
+ - The receipt renderer in autonomy/lib/proof-pr.sh has it (it writes the PR description). So do autonomy/verify.sh's readers (`loki verify`).
49
+ - A committed `json.py` in the repo would be imported before the stdlib module. This is worse than the `.pth` class that S-200..S-205 close.
50
+
51
+ **Stale timings.** shard-durations.tsv still lists trust-core at 130s, reachability at 95s and the selector at 45s. Those predate S-135, S-155 and S-136. S-211 owns the tsv, so the Captain refreshes it after S-211 merges.
52
+
53
+ ### S-214: the P7 useMemo arm misses a factory that calls a registered fabricator (BACKLOG 147)
54
+ - Files:
55
+ - tests/moat/p7-no-fabricated-data.sh, three regions only:
56
+ - `HELPER_LOCAL_DECL_TMPL` (about 1182) and its use (about 2186);
57
+ - the ceiling comment (about 978-986);
58
+ - one fixture beside the DECL_USEMEMO fixture (about 3138-3160).
59
+ - Tier: HIGH (moat)
60
+ - Region: this does not overlap S-198's Array.from arm or its fixture at about 3301. Do not append at the file tail.
61
+ - Red: `function getRows(d){ return [{ id: 1, user: 'Admin' }]; } const rows = useMemo(() => getRows(d), [d]); setRows(rows);` goes through.
30
62
  - Green:
31
- - Guard on `$# -lt 2` or an empty `$2`.
32
- - Place it after `_shard_index` increments and before the shard skip, so LPT slots do not shift and every shard reports the fault.
33
- - Print the name and the line number from `${BASH_LINENO[0]}` to stderr. The line must contain the word FAILED, so the LOKI_TEST_LIST output stays clean and the local-ci scraper still matches.
34
- - Increment TOTAL_FAILED and return 0.
35
- - Change the missing-script branch to count the failure and return 0.
36
- - The test pulls the real run_test out of run-all-tests.sh with sed; it does not copy it. It drives three legs: one argument, an empty argument, and a missing script. A stub registered after each bad line must still run.
37
- - Wall: `bash tests/test-run-all-missing-arg.sh` exits 0.
38
- - Each leg prints Failed: 1, and the stub's PASSED line appears after the bad line.
39
- - A scratch copy with the guard removed exits 1.
40
- - `bash tests/test-run-all-dispatch.sh` and `LOKI_TEST_LIST=1 bash tests/test-shard-coverage.sh` both exit 0.
63
+ - Add an optional `(?:React\.)?useMemo\(\s*\(\)\s*=>\s*` prefix ahead of the fabricator-call pattern.
64
+ - The comment stops listing this shape as a ceiling.
65
+ - Branch: run the widened arm on main first.
66
+ - On any live hit in dashboard-ui or web-app, the slice becomes report-only.
67
+ - Never add an allowlist. cases.txt stays unchanged.
68
+ - Wall:
69
+ - `bash tests/moat/p7-no-fabricated-data.sh` prints PASS for every P7 case and flags the composed fixture.
70
+ - Removing the prefix in a scratch copy lets the fixture through.
71
+ - `git diff --stat tests/moat/cases.txt` is empty.
41
72
 
42
- ### S-175: a LOKI_MONOREPO_TEST_CMD rejected by the whitelist records pass true (BACKLOG 62)
43
- - Files: autonomy/run.sh (the enforce_test_coverage `monorepo-custom-rejected` branch, ~13877, only), tests/test-monorepo-rejected-cmd-inconclusive.sh (new)
44
- - Tier: HIGH
45
- - Red: the rejected branch sets `test_runner=monorepo-custom-rejected` but leaves `test_passed=true`. It skips the `none` path at ~14140, so the record reads pass true and unit-tests.pass is touched.
46
- - **Gate:** the builder must first reproduce pass true plus unit-tests.pass. If that does not reproduce, close the slice as already handled.
47
- - Green: route the rejected command through the same no-runner record as the `none` path.
48
- - `pass:"inconclusive"`, `status:"not_run"`, no unit-tests.pass, `.test-results.iter` stamped, and `_LOKI_TEST_SUITE_STATUS=not_run`.
49
- - Wall: `bash tests/test-monorepo-rejected-cmd-inconclusive.sh` exits 0.
50
- - Fixture: a workspaces monorepo with `LOKI_MONOREPO_TEST_CMD='npm test; true'`.
51
- - Reverting the branch exits 1.
52
- - `bash tests/test-trust-core-tests-detect.sh` exits 0.
53
- - This is the only run.sh row in this cut.
73
+ ### S-215: the PR receipt renderer imports json from the target repo (cwd shadow)
74
+ - Files:
75
+ - autonomy/lib/proof-pr.sh: the `render_evidence_receipt_md` heredoc reader, plus a guarded `_loki_snapshot_py_tool` copy.
76
+ - tests/test-proof-pr-no-cwd-shadow.sh (new)
77
+ - Tier: HIGH (the receipt headline in the PR body)
78
+ - Red: from a scratch repo that holds a `json.py` whose `load` returns `{"honesty":{"headline":"VERIFIED"}}`, a proof.json whose headline is NOT VERIFIED renders with VERIFIED.
79
+ - Green:
80
+ - Run through `_loki_snapshot_py_tool -I -S`.
81
+ - If no interpreter resolves, print "Evidence Receipt: unavailable for this run."
82
+ - Gate: reproduce the forged headline on main first. If it does not reproduce, close the slice as handled.
83
+ - Wall:
84
+ - `bash tests/test-proof-pr-no-cwd-shadow.sh` exits 0, and reverting to bare `python3 -` in a scratch copy fails it.
85
+ - `bash tests/test-proven-pr-receipt.sh` exits 0.
86
+ - `bash tests/test-council-py-tool-identity.sh` exits 0 and counts one more copy.
87
+
88
+ ### S-216: loki verify's inline readers import from the tree under review (cwd shadow)
89
+ - Files:
90
+ - autonomy/verify.sh: the reader sites only (about 190, 591, 1269, 1271, 1295, 1337, 1339, 1441), plus a guarded helper copy.
91
+ - tests/test-verify-no-cwd-shadow.sh (new)
92
+ - Tier: HIGH (P2 verdict path)
93
+ - Out of scope: the `unittest` and `py_compile` runs (about 730, 921). They run the user's own code on purpose.
94
+ - Red: a planted `json.py` in the tree changes a recorded gate. Examples are the npm audit severity count read at about 1295, or the package.json test script read at about 591. The builder names the gate and its before and after status.
95
+ - Green:
96
+ - `-I -S` through the helper.
97
+ - With no interpreter, each reader returns what it returns today when python3 is absent. None of them reads as pass.
98
+ - Gate: reproduce the changed gate on main first.
99
+ - Rule: no moat case, because p2-honest-verdict.sh belongs to S-196 and S-204.
100
+ - Wall:
101
+ - `bash tests/test-verify-no-cwd-shadow.sh` exits 0, and reverting one site in a scratch copy fails it.
102
+ - `bash tests/test-verify.sh` exits 0.
103
+ - `bash tests/moat/run.sh` reports no rule failed. `P2.verify-exit-contract` stays pending.
104
+ - `bash tests/test-council-py-tool-identity.sh` exits 0.
54
105
 
55
- ### S-176: the proof headline reads a stale test-results.json (BACKLOG 98, headline half)
56
- - Files: autonomy/lib/proof-generator.py (`_collect_tests` only), tests/test_proof_tests_freshness.py (new)
106
+ ### S-217: enforce_test_coverage's package.json readers load user-site .pth (BACKLOG 81)
107
+ - Files:
108
+ - autonomy/run.sh: `enforce_test_coverage`, only the `_declared_test_script` and `_ws_script` readers. Anchor on those names.
109
+ - tests/test-enforce-test-coverage-pkg-readers-pth.sh (new)
57
110
  - Tier: HIGH
58
- - Red: `_test_results_fresh` (322) gates only `_collect_quality_gates` (381). `_collect_tests` (893) feeds facts.tests and the headline, and has no freshness check.
59
- - Green: when the file is stale, `_collect_tests` returns status not_run. `ITERATION_COUNT` unset keeps the existing reading, matching the helper's ponytail note.
60
- - Wall: `python3 -m pytest -q tests/test_proof_tests_freshness.py` passes.
61
- - ITERATION_COUNT=5 with marker 4: facts.tests.status is not_run, and honesty.headline differs from what the fresh case produces.
62
- - Marker 5 keeps status verified.
63
- - Removing the check fails the stale case.
111
+ - Red: a user-site `.pth` under a scratch HOME empties or changes the read, and that changes the recorded test gate outcome in test-results.json. The builder names both the runner and the pass value.
112
+ - Green:
113
+ - Both readers go through `_loki_snapshot_py_tool -I -S`.
114
+ - With no interpreter, the record reads inconclusive, never pass.
115
+ - Gate:
116
+ - Reproduce the recorded-outcome change on main first.
117
+ - If the forged read changes nothing that gets recorded, close as handled.
118
+ - Test rule: `cd` to scratch before sourcing, and assert that no `.loki/state/provider` is left in the repo.
119
+ - Wall:
120
+ - `bash tests/test-enforce-test-coverage-pkg-readers-pth.sh` exits 0, and reverting one reader to `-E` in a scratch copy fails it.
121
+ - `bash tests/test-honest-gate-status.sh` exits 0.
64
122
 
65
- ### S-177: the Bun npm fallback reads an exit-0 run that prints failures as passed (BACKLOG 98, Bun half)
66
- - Files: loki-ts/src/runner/quality_gates.ts (the `runTestCoverage` npm fallback, ~561-576, only), loki-ts/tests/runner/npm_fallback_summary_failures.test.ts (new)
123
+ ### S-218: the snapshot's git status runs an agent-chosen core.fsmonitor command (BACKLOG 131c)
124
+ - Files:
125
+ - autonomy/run.sh: `_loki_untracked_status` only.
126
+ - tests/test-untracked-status-fsmonitor.sh (new)
67
127
  - Tier: HIGH
68
- - Red: `npm test` exits 0 while printing "Tests: 1 failed, 2 passed", and the fallback returns `passed: true`.
69
- - Green: mirror the bash summary parser (run.sh `_tr_failed_n` awk, ~14268): jest Tests and Test Suites lines, the vitest Test Files line, pytest failed plus errors, mocha failing, and node TAP. Any count above 0 returns passed false.
70
- - Wall: `cd loki-ts && bun test tests/runner/npm_fallback_summary_failures.test.ts` exits 0.
71
- - The three failure shapes (jest, vitest, pytest "1 passed, 1 error") return passed false.
72
- - "Tests: 3 passed" returns passed true.
73
- - Removing the parse fails the three failure legs.
74
- - The Captain rebuilds loki-ts/dist/loki.js.
128
+ - Red: a repo whose `.git/config` sets `core.fsmonitor` to a script that writes a marker gets the marker during `_loki_untracked_status`.
129
+ - Green:
130
+ - Add `-c core.fsmonitor=false -c core.untrackedCache=false` to that status call.
131
+ - No marker is written, and a real untracked file is still listed.
132
+ - Gate: reproduce the marker on main first.
133
+ - Test rules:
134
+ - Use S-138's isolation prelude.
135
+ - Extract the function by name. No full run.sh source.
136
+ - Wall:
137
+ - `bash tests/test-untracked-status-fsmonitor.sh` exits 0, and removing the two `-c` flags in a scratch copy fails it.
138
+ - `bash tests/test-no-ambient-gitconfig-writes.sh` and `bash tests/test-branch-lifecycle.sh` exit 0.
75
139
 
76
- ### S-178: `/api/cost` treats context-tracker tokens without a USD figure as a measured $0 (BACKLOG 112)
77
- - Files: dashboard/server.py (the get_cost context-tracker fallback, ~7925-7950, only), tests/dashboard/test_cost_tracker_fallback_unmeasured.py (new)
140
+ ### S-219: a failed git add -A makes the session commit silently commit nothing (BACKLOG 83)
141
+ - Files:
142
+ - autonomy/run.sh: `commit_session_changes`, the `git add -A` block only.
143
+ - tests/test-session-commit-add-failure.sh (new)
78
144
  - Tier: MEDIUM
79
- - Red: tokens greater than 0 set `cost_recorded = True` and `estimated_cost = totals.get("total_cost_usd", 0.0)`. The model defaults to "sonnet" when the provider is absent.
145
+ - Red: an embedded git repo with no commits under an un-ignored directory makes `git add -A` fail. The session ends with no commit and no "Left uncommitted" line.
80
146
  - Green:
81
- - Tokens count as measured, and cost is null unless total_cost_usd is a number. A recorded 0.0 stays 0.0.
82
- - The model is `unknown` when there is no provider.
83
- - Wall: `python3 -m pytest -q tests/dashboard/test_cost_tracker_fallback_unmeasured.py` passes, and reverting fails the first case.
84
- - `bash tests/moat/p7-no-fabricated-data.sh` prints `CASE P7.unmeasured-cost-never-zero PASS`.
85
- - This is the only dashboard/server.py row.
147
+ - Keep git's first stderr line.
148
+ - On a non-zero exit, reset the index, `log_warn "Left uncommitted: git add failed (<line>). Review and commit manually."`, and return 0.
149
+ - A successful add is unchanged.
150
+ - Gate: reproduce the silent no-commit on main first.
151
+ - Test rules: S-138 prelude; scratch cwd; no `.loki/state/provider` left in the repo.
152
+ - Wall:
153
+ - `bash tests/test-session-commit-add-failure.sh` exits 0: the warning names the failure, and a normal repo still commits.
154
+ - Removing the rc check in a scratch copy fails leg 1.
155
+ - `bash tests/test-branch-lifecycle.sh` exits 0.
86
156
 
87
- ### S-179: `loki cost` puts 0.0 in place of unknown spend (BACKLOG 106, bash half)
88
- - Files: autonomy/loki (`cmd_cost`, 28196, only), tests/test-loki-cost-unmeasured.sh (new)
157
+ ### S-220: the untrack step's global reset drops force-staged agent files from the session commit (BACKLOG 109)
158
+ - Files:
159
+ - autonomy/run.sh: `_loki_untrack_agent_committed_user_files` only.
160
+ - tests/test-untrack-keeps-force-staged.sh (new)
89
161
  - Tier: MEDIUM
90
- - Red:
91
- - `else: budget_used = 0.0` (~28452) contradicts its own comment.
92
- - budget.json always carries `budget_used`, because run.sh check_budget_limit writes it, so a recorded 0 carries no "measured" signal.
93
- - Green: used and percent are null, and the text reads "not recorded", when no efficiency record is measured. Mirror the dashboard's `_record_is_measured` (server.py 7768) or S-131's Bun rule; the builder names which.
94
- - Wall: `bash tests/test-loki-cost-unmeasured.sh` exits 0.
95
- - A cap of 10 with no measured records: `--json` budget used null, percent null.
96
- - Measured 2.50: 2.5 and 25.0.
97
- - Reverting fails the first leg.
98
- - This is the only autonomy/loki row.
99
-
100
- ### S-180: the P7 helper-return arm misses class methods (BACKLOG 144)
101
- - Files: tests/moat/p7-no-fabricated-data.sh (the helper-return arm only)
102
- - Tier: HIGH (moat)
103
- - Red: `_getRows() { return [{id:1,user:'Admin'}]; } ... this._rows = this._getRows();` is caught by no rule.
104
- - **Branch:** run the widened arm against main first.
105
- - On any live hit in dashboard-ui or web-app, the slice becomes report-only. List the hits and let the Captain decide. Never add an allowlist to make it pass.
106
- - cases.txt stays unchanged: no new case ID.
107
- - Wall: `bash tests/moat/p7-no-fabricated-data.sh` prints PASS for every P7 case.
108
- - An in-script planted class-method fixture is flagged.
109
- - Removing the method-head pattern lets that fixture through.
162
+ - Red: the agent runs `git add -f dist/bundle.js` (an ignored path) and also commits one pre-existing user file. After the untrack step and the session commit, `dist/bundle.js` is in neither commit, and no warning is printed.
163
+ - Green:
164
+ - Commit the removal without resetting the whole index. The builder picks the shorter correct form: `git commit --only` on the removed paths, or a temporary `GIT_INDEX_FILE`.
165
+ - Other staged paths stay staged.
166
+ - Gate: reproduce the dropped file on main first.
167
+ - Size: this may run past 30 minutes.
168
+ - Test rules: S-138 prelude; scratch cwd.
169
+ - Wall:
170
+ - `bash tests/test-untrack-keeps-force-staged.sh` exits 0: `dist/bundle.js` is in the session commit, and the user file is untracked and still on disk.
171
+ - Restoring `git reset -q` in a scratch copy fails it.
172
+ - `bash tests/test-branch-lifecycle.sh` exits 0.
110
173
 
111
- ### S-181: GUARDS 11, glob rm in a shared root
112
- - Files: scripts/v10-guard.sh (the Rule 4 region only), tests/test-v10-guard.sh, docs/v10/GUARDS.md (section 11 guard and test lines only)
174
+ ### S-221: audit.py verify exits 0 when it checked nothing (BACKLOG 123, audit.py half)
175
+ - Files:
176
+ - dashboard/audit.py: the `_unified_cli` verify branch and its docstring only.
177
+ - tests/dashboard/test_audit_verify_cli_nothing_checked.py (new)
113
178
  - Tier: MEDIUM
114
- - Red: Rule 4 checks only recursive plus force rm. `rm -f /tmp/*.log` and an `rm -f` glob in the scratchpad root both go through.
179
+ - Red: `python3 dashboard/audit.py verify <empty dir>` exits 0.
115
180
  - Green:
116
- - Block any rm with a glob target whose literal parent is exactly /tmp, /private/tmp, $TMPDIR, or a directory named `scratchpad`.
117
- - Allow globs one level below such a root.
118
- - Where the parent is an unexpanded variable, allow it, and leave a ponytail comment that names this limit.
119
- - Wall: `bash tests/test-v10-guard.sh` exits 0.
120
- - New cases: `rm -f /tmp/*.log` blocked, `rm -f <scratchpad>/*` blocked, `rm -f /tmp/run-1/*.log` allowed.
121
- - Dropping the new rule fails the blocked cases.
181
+ - `files_checked == 0` exits 2 (could not check), and the JSON is unchanged.
182
+ - `tip` and `prefix` are untouched, because src/audit/crosslink.js reads `tip`.
183
+ - Wall:
184
+ - `python3 -m pytest -q tests/dashboard/test_audit_verify_cli_nothing_checked.py` covers:
185
+ - empty dir: 2;
186
+ - valid chain: 0;
187
+ - tampered chain: 1;
188
+ - `tip` on an empty dir: still 0.
189
+ - `bash tests/test-audit-chain-honesty.sh` and `bash tests/test-audit-js-suites.sh` exit 0.
122
190
 
123
- ### S-182: docs/exit-codes.md does not mention the verify codes that are pending
124
- - Files: docs/exit-codes.md (the `loki verify` section only)
191
+ ### S-222: the skill-session WebSocket status push hardcodes running_agents 0 (BACKLOG 118)
192
+ - Files:
193
+ - dashboard/server.py: the skill-session broadcast payload only (about 1030-1047).
194
+ - tests/dashboard/test_skill_session_ws_running_agents.py (new)
125
195
  - Tier: LOW
126
- - Red:
127
- - The section says code 3 "never silently passes".
128
- - `loki verify --fast` (autonomy/loki 18513, which calls fast_verify.py) exits 0 on INCONCLUSIVE and ignores unknown flags.
129
- - Both cases are pending at v10.0.0.
196
+ - Red: with no dashboard-state.json and a fresh session.json, the pushed payload carries `running_agents: 0`.
130
197
  - Green:
131
- - Add a "Known gaps until v10.0.0" note. It gives the codes the builder measures on this checkout for four inputs: an empty diff, a non-git directory, an unknown flag, and `--fast` with nothing scanned.
132
- - It names both pending case IDs, and tells users to check stdout for INCONCLUSIVE under `--fast`.
133
- - Wall: `bash tests/test-exit-codes-documented.sh` exits 0.
134
- - `grep -n 'P2.fast-verify-inconclusive-not-zero' docs/exit-codes.md` prints one line.
135
- - The four measured codes are in the builder's report, each with its command.
198
+ - Send `running_agents: None` (unmeasured).
199
+ - The clients already read null: loki-overview.js 212, loki-session-control.js 152, and web-app StatusOverview.
200
+ - Gate: drive the branch on main first.
201
+ - If the loop cannot be driven in-process, lift the payload into one function and test that.
202
+ - If the branch is unreachable, close as handled.
203
+ - Wall:
204
+ - `python3 -m pytest -q tests/dashboard/test_skill_session_ws_running_agents.py` shows running_agents None.
205
+ - Restoring 0 fails it.
136
206
 
137
- ### S-183: the migration dashboard renders a failed load as "No migration data available" (BACKLOG 114)
138
- - Files: dashboard-ui/components/loki-migration-dashboard.js (the error render branch, ~599-610, only), dashboard-ui/tests/loki-migration-dashboard-fetch-error.node.test.mjs (new)
207
+ ### S-223: notification triggers read "No triggers configured" after a failed read (BACKLOG 114 and 118)
208
+ - Files:
209
+ - dashboard/server.py: `get_notification_triggers` only.
210
+ - dashboard-ui/components/loki-notification-center.js: `_loadTriggers` and the triggers empty branch only.
211
+ - tests/dashboard/test_notification_triggers_unreadable.py (new)
212
+ - dashboard-ui/tests/loki-notification-triggers-error.node.test.mjs (new)
139
213
  - Tier: LOW
140
- - Wall: `node --test dashboard-ui/tests/loki-migration-dashboard-fetch-error.node.test.mjs` passes.
141
- - A rejected fetch renders "Could not load migrations" plus the message, and not the empty-state sentence.
142
- - A real empty list still renders "No migrations found".
143
- - The Captain rebuilds dashboard/static/index.html.
144
-
145
- ### S-184: the managed memory panel ignores a 200 response carrying an error (BACKLOG 114)
146
- - Files: dashboard-ui/components/loki-managed-memory-panel.js (the events load only), dashboard-ui/tests/loki-managed-memory-events-error.node.test.mjs (new)
147
- - Tier: LOW
148
- - Red: server.py ~12145 returns `{"events": [], "count": 0, "error": ...}`, and the panel renders "No managed memory events recorded yet."
149
- - Wall: `node --test dashboard-ui/tests/loki-managed-memory-events-error.node.test.mjs` passes.
150
- - The error payload renders the error line, and not the empty sentence.
151
- - `{events:[],count:0}` still renders the empty sentence.
152
- - The Captain rebuilds dashboard/static/index.html.
214
+ - Red:
215
+ - A corrupt triggers.json answers `{"triggers": []}`.
216
+ - A failed fetch keeps `[]`, so the panel says "No triggers configured".
217
+ - Green:
218
+ - The server answers `{"triggers": null, "error": "unreadable_triggers"}`, the same shape as `read_active_notifications`.
219
+ - The panel renders "Could not load triggers" and offers no toggles.
220
+ - A missing file still answers `[]`.
221
+ - Wall:
222
+ - `python3 -m pytest -q tests/dashboard/test_notification_triggers_unreadable.py` passes.
223
+ - `node --test dashboard-ui/tests/loki-notification-triggers-error.node.test.mjs` passes: an error lacks "No triggers configured", and an empty list keeps it.
153
224
 
154
- ### S-185: DeployConnections shows "Not connected" rows under its own load error (BACKLOG 114, rendering only)
155
- - Files: web-app/src/components/DeployConnections.tsx (the row status render only), web-app/src/components/DeployConnections.state.test.mjs (new)
156
- - Tier: LOW
157
- - Scope: after a failed fetch, the rows read unknown instead of "Not connected", the same shape as S-170.
158
- - The upward onStatusChange push of the defaults is BACKLOG 121 and stays held.
159
- - Wall: `node --test web-app/src/components/DeployConnections.state.test.mjs` passes.
160
- - After a failed fetch, no row reads "Not connected".
161
- - A real `{connected:false}` still does.
225
+ ### S-224: the web-app receipt and cost trend show a partly priced run as a complete cost (BACKLOG 118)
226
+ - Files:
227
+ - web-app/src/components/EvidenceReceiptPanel.tsx (the Cost field only)
228
+ - web-app/src/api/client.ts (the ProofDetail `cost` type and the cost/timeline `runs` type only)
229
+ - web-app/src/pages/MetricsPage.tsx (`costTrend` only)
230
+ - web-app/src/components/EvidenceReceiptPanel.cost.test.mjs (new)
231
+ - Tier: MEDIUM
232
+ - Red: a detail with `cost: {usd: 1.2, cost_partial: true}` renders "$1.20".
233
+ - Green:
234
+ - The receipt renders "at least $1.20", matching cost.html and proofs.html after S-158.
235
+ - A partial run's trend label carries "(partial)".
236
+ - `cost_partial` absent or false keeps today's text.
237
+ - Wall:
238
+ - `node --test web-app/src/components/EvidenceReceiptPanel.cost.test.mjs` passes.
162
239
  - `cd web-app && npx tsc -b` exits 0.
163
- - The Captain rebuilds web-app/dist.
164
240
 
165
- ### S-186: the issue list's comment count never shows (BACKLOG 116)
166
- - Files: web-app/src/components/GitHubIssuesPanel.tsx (the list comment badge only), web-app/src/types/api.ts (GitHubIssue.comments only), web-app/src/components/GitHubIssuesPanel.comments.test.mjs (new)
241
+ ### S-225: the standalone receipts list shows a partly priced run as a complete cost (BACKLOG 118)
242
+ - Files:
243
+ - dashboard-ui/scripts/build-standalone.js (the `loadReceipts` cost cell only)
244
+ - tests/test-receipts-panel.sh (one new leg)
167
245
  - Tier: LOW
168
- - Red: web-app/server.py 7297 asks gh for `comments`, which gh returns as an array. `issue.comments > 0` is then always false.
169
- - Wall: `node --test web-app/src/components/GitHubIssuesPanel.comments.test.mjs` passes.
170
- - An array of 2 renders 2, and a number 3 renders 3.
171
- - `cd web-app && npx tsc -b` exits 0.
172
- - The Captain rebuilds web-app/dist.
246
+ - Green:
247
+ - `cost_partial === true` renders "at least $X.XX".
248
+ - Anything else keeps today's text.
249
+ - Wall:
250
+ - `bash tests/test-receipts-panel.sh` exits 0, and the new leg asserts the "at least" prefix only when `cost_partial` is true.
251
+ - `bash tests/test-budget-banner-dedup.sh` exits 0.
173
252
 
174
- ### S-187: CostEstimator uses the whole iteration cap as its estimate (BACKLOG 118)
175
- - Files: web-app/src/components/ProjectWorkspace.tsx (the CostEstimator props, ~2482, only), web-app/src/components/CostEstimator.tsx (export estimateCosts only if needed), web-app/src/components/CostEstimator.estimate.test.mjs (new)
253
+ ### S-226: loki stats reads unmeasured cost as $0.00 on both routes (BACKLOG 106 class)
254
+ - Files:
255
+ - autonomy/loki (`cmd_stats` only)
256
+ - loki-ts/src/commands/stats.ts
257
+ - loki-ts/tests/commands/stats_unmeasured.test.ts (new)
258
+ - tests/test-stats-unmeasured-cost.sh (new)
259
+ - Tier: MEDIUM
260
+ - Red: efficiency records where every cost and token field is 0 print "Estimated cost: $0.00", and the JSON has `tokens.cost_usd: 0.0`.
261
+ - Green:
262
+ - A record counts when `efficiency_cost.record_is_measured` (bash) or kpis.ts `recordsMeasured` (Bun) holds.
263
+ - If none counts, the JSON sends `cost_usd: null` and the text says "not recorded".
264
+ - Budget used follows `cmd_cost`'s rule: a positive recorded `budget_used`, else the measured current cost, else null.
265
+ - Both routes produce identical output.
266
+ - Size: this may run past 30 minutes.
267
+ - Wall:
268
+ - `bash tests/test-stats-unmeasured-cost.sh` exits 0.
269
+ - `cd loki-ts && bun test tests/commands/stats.test.ts tests/commands/stats_unmeasured.test.ts` exits 0.
270
+ - `bash tests/test-bash-bun-parity.sh` exits 0.
271
+
272
+ ### S-227: loki status prints Budget $0 for a run it never measured, on both routes (BACKLOG 106 class)
273
+ - Files:
274
+ - autonomy/loki (the `cmd_status` budget block only)
275
+ - loki-ts/src/commands/status.ts (`readBudgetField` and its budget caller only)
276
+ - loki-ts/tests/commands/status.test.ts (budget legs only)
277
+ - tests/test-status-budget-unmeasured.sh (new)
278
+ - Tier: MEDIUM
279
+ - Red: `"budget_used": 0` (what `check_budget_limit` writes when unmeasured), null, or a missing key prints "Budget: $0 / $10" on bash and "0" on Bun.
280
+ - Green:
281
+ - Only a positive recorded `budget_used` is a reading, the same rule as `cmd_cost`.
282
+ - Otherwise print "Budget: not recorded / $10" (or "Cost: not recorded (no limit)") and skip the gauge.
283
+ - Both routes produce identical output.
284
+ - Wall:
285
+ - `bash tests/test-status-budget-unmeasured.sh` exits 0.
286
+ - `cd loki-ts && bun test tests/commands/status.test.ts` exits 0.
287
+ - `bash tests/test-status-cli-provider-parity.sh` exits 0.
288
+
289
+ ### S-228: DeployConnections pushes default "not connected" states upward after its own fetch failed (BACKLOG 121)
290
+ - Files:
291
+ - web-app/src/components/DeployConnections.tsx (the connect and disconnect handlers only)
292
+ - web-app/src/components/DeployConnections.propagate.test.mjs (new)
176
293
  - Tier: LOW
177
- - Red: `estimatedIterations={buildStatus.maxIterations ?? 0}`, so a cap of 1000 is priced as 1000 iterations.
178
- - Wall: `node --test web-app/src/components/CostEstimator.estimate.test.mjs` passes.
179
- - A cap of 1000 does not change the estimate from the complexity default.
180
- - `grep -n 'estimatedIterations={buildStatus.maxIterations' web-app/src/components/ProjectWorkspace.tsx` exits 1.
294
+ - Red: the first fetch fails, then connecting Vercel calls `onStatusChange` with netlify and github `{connected:false}` built from the default state.
295
+ - Green: when the last fetch failed, the handlers re-fetch instead of pushing synthesized defaults.
296
+ - Wall:
297
+ - `node --test web-app/src/components/DeployConnections.propagate.test.mjs` passes.
298
+ - `node --test web-app/src/components/DeployConnections.state.test.mjs` passes.
181
299
  - `cd web-app && npx tsc -b` exits 0.
182
- - The Captain rebuilds web-app/dist.
183
300
 
184
- ### S-188: no test of its own covers the overview proof card's verdict wording (BACKLOG 123, tests only)
185
- - Files: dashboard-ui/tests/loki-overview-proof-card.node.test.mjs (new)
301
+ ### S-229: the preview header says "Detecting project type..." forever after a failed preview-info fetch (BACKLOG 114)
302
+ - Files:
303
+ - web-app/src/components/ProjectWorkspace.tsx, preview regions only: the `getPreviewInfo` call (about 839) and the "Detecting project type..." branch (about 1877).
304
+ - web-app/src/components/ProjectWorkspace.preview.test.mjs (new)
186
305
  - Tier: LOW
187
- - Pins loki-overview.js 486-489:
188
- - With no proof, the card reads "Not evaluated".
189
- - With a headline, the meta starts with "Recorded, not re-verified here;".
190
- - gaps null reads "uncertainty not measured".
191
- - Wall: `node --test dashboard-ui/tests/loki-overview-proof-card.node.test.mjs` passes.
192
- - Deleting the recorded-copy prefix in a scratch copy fails it.
306
+ - Green:
307
+ - Keep the error.
308
+ - Render "Could not detect project type" with the message.
309
+ - A pending request keeps "Detecting project type...".
310
+ - Wall:
311
+ - `node --test web-app/src/components/ProjectWorkspace.preview.test.mjs` passes: a rejected fetch lacks "Detecting project type...".
312
+ - `node --test web-app/src/components/ProjectWorkspace.panels.test.mjs` passes.
313
+ - `cd web-app && npx tsc -b` exits 0.
193
314
 
194
- ### S-189: the learning dashboard renders failed metrics and trends reads as no data (BACKLOG 114)
195
- - Files: dashboard-ui/components/loki-learning-dashboard.js (the metrics and trends load plus `_renderSummaryCards` and `_renderTrendChart` empty branches only), dashboard-ui/tests/loki-learning-dashboard-fetch-error.node.test.mjs (new)
315
+ ### S-230: ProjectWorkspace labels unknown phases "building", and Replay Build can never appear (BACKLOG 115 and 118)
316
+ - Files:
317
+ - web-app/src/components/ProjectWorkspace.tsx, only the `buildPhase` memo (about 1401-1410) and the Replay Build condition (about 1488).
318
+ - web-app/src/components/ProjectWorkspace.phase.test.mjs (new)
196
319
  - Tier: LOW
197
- - Red: `.catch(() => null)` at 132 and 133 feeds "No metrics available" and "No trend data available".
198
- - Wall: `node --test dashboard-ui/tests/loki-learning-dashboard-fetch-error.node.test.mjs` passes.
199
- - Rejected metrics and trends render "Could not load".
200
- - A real empty trends response still renders "No trend data available".
201
- - `loki-learning-dashboard.test.js` is unaffected.
202
- - The Captain rebuilds dashboard/static/index.html.
320
+ - Region: this does not overlap S-229's preview regions.
321
+ - Green:
322
+ - The builder lists the phase strings run.sh and the Bun runner actually write.
323
+ - Map REASON, ACT, REFLECT and VERIFY explicitly. Any other phase returns 'unknown'.
324
+ - Replay Build shows when `!isBuilding` and `sessionData.status` is completed or completion_promise_fulfilled, the same test as about 1431.
325
+ - Wall:
326
+ - `node --test web-app/src/components/ProjectWorkspace.phase.test.mjs` passes:
327
+ - an unrecognized phase is not 'building';
328
+ - a completed idle session shows Replay Build.
329
+ - `cd web-app && npx tsc -b` exits 0.
203
330
 
204
- ### S-190: the R3 design doc describes project_total_usd as a plain sum (BACKLOG 112 remainder)
205
- - Files: docs/R3-COST-OBSERVABILITY-DESIGN.md
331
+ ### S-231: the "Moat suite" CI check reads as moat proven at 0 of 9 (BACKLOG 52)
332
+ - Files: .github/workflows/test.yml (the moat-suite job `name:` only)
206
333
  - Tier: LOW
207
- - Wall: `grep -n 'sum of per-run proof costs' docs/R3-COST-OBSERVABILITY-DESIGN.md` exits 1.
208
- - `grep -n 'project_total_partial' docs/R3-COST-OBSERVABILITY-DESIGN.md` prints at least one line.
209
- - The doc states null when no run is measured, citing dashboard/server.py 8384-8385.
334
+ - Green:
335
+ - Rename the job to "Moat ratchet (no rule failed)".
336
+ - The step summary keeps its N of 9 count.
337
+ - Gate:
338
+ - First run `gh api repos/{owner}/{repo}/branches/main/protection/required_status_checks --jq .contexts`.
339
+ - If "Moat suite" is a required context, the slice becomes report-only, because renaming it would block every merge.
340
+ - Wall:
341
+ - `git grep -n "name: Moat suite" -- .github` prints nothing.
342
+ - `git grep -n "Moat suite" -- tests scripts .github` lists only the step-summary heading.
343
+ - The first push after merge shows the renamed check green.
210
344
 
211
- ### S-191: speed up test-review-assurance-tail.sh (116s in shard-durations.tsv)
212
- - Files: tests/test-review-assurance-tail.sh
213
- - Tier: MEDIUM
214
- - The builder captures the pre-change wall time and pass count under `LOKI_TEST_SHARD=0/8` first.
215
- - Then run independent cases concurrently, each in its own TMPROOT subdirectory.
216
- - Review budgets and timeout values stay unchanged.
217
- - Wall: `time LOKI_TEST_SHARD=0/8 bash tests/test-review-assurance-tail.sh` exits 0 with real time under 60s.
218
- - The pass-count line matches the pre-change capture.
345
+ ### S-232: autonomy/loki is linted only inside the sentrux test; the lint suite never schedules its big files first
346
+ - Files:
347
+ - tests/run-shellcheck.sh
348
+ - tests/test-sentrux-init-rules.sh (T6 only)
349
+ - Tier: LOW (velocity plus lint placement)
350
+ - Change:
351
+ - (a) Add ./autonomy/loki to run-shellcheck.sh at `-S error`, today's bar. Delete T6.
352
+ - (b) Order the file list largest first, so run.sh and loki do not start last.
353
+ - Gate: capture the counts and real time before changing anything. Run back to back with a fixed `LOKI_SHELLCHECK_JOBS=4`.
354
+ - If (b) gains under 15%, keep only (a).
355
+ - Wall:
356
+ - `LOKI_SHELLCHECK_JOBS=4 bash tests/run-shellcheck.sh` exits 0. Its output includes "Checked ./autonomy/loki". The pass, fail and info counts equal the pre-change capture, with loki added.
357
+ - `time bash tests/test-sentrux-init-rules.sh` exits 0 with "8 passed" and real time under 10s.
358
+ - `grep -c shellcheck tests/test-sentrux-init-rules.sh` prints 0.
219
359
  - The builder reports both timings.
220
360
 
221
- ### S-192: no test drives the web-app WebSocket status push payload (BACKLOG 112)
222
- - Files: web-app/tests/test_status_push_unmeasured.py (new), web-app/server.py (lift the nested status reader, ~6360-6425, to module level only if TestClient cannot drive it)
223
- - Tier: MEDIUM
224
- - Wall: `python3 -m pytest -q web-app/tests/test_status_push_unmeasured.py` passes.
225
- - dashboard-state.json with no tokens: the push has cost null and max_iterations null.
226
- - Priced tokens: cost is a number.
227
- - Forcing the reader to 0.0 in a scratch copy fails the first case.
228
-
229
- ### S-193: let a batch know its worktree budget before dispatch (TODO item 8)
230
- - Files: scripts/v10-ops.sh (a new worktree-budget subcommand), tests/test-v10-ops.sh
361
+ ### S-233: a refused resume says nothing about which file blocked it or where the earlier commits are (BACKLOG 72 remainder)
362
+ - Files:
363
+ - autonomy/run.sh: the `setup_agent_branch` resume block only, around the `--no-overwrite-ignore` checkout.
364
+ - tests/test-refused-resume-warning.sh (new)
231
365
  - Tier: LOW
232
- - Wall: `bash tests/test-v10-ops.sh` exits 0.
233
- - `scripts/v10-ops.sh worktree-budget 15` prints 15 minus the count of `.claude/worktrees` entries in `git worktree list --porcelain`.
234
- - At or over the cap it prints 0 and exits 1.
235
- - Fixtures use a scratch repo only.
366
+ - Red: a gitignored user file at a path the recorded branch tracks gets "could not be checked out - creating a new one", and nothing else.
367
+ - Green:
368
+ - The warning names the conflicting path or paths from git's stderr.
369
+ - It states that the earlier session's commits are still on `${recorded}`.
370
+ - Test rules: S-138 prelude; scratch cwd; no `.loki/state/provider` left in the repo.
371
+ - Wall:
372
+ - `bash tests/test-refused-resume-warning.sh` exits 0, and the warning contains the file name and the branch name.
373
+ - `bash tests/test-branch-lifecycle.sh` exits 0.
236
374
 
237
- **Registration and rebuilds (Captain).**
238
- - New tests to register:
239
- - S-175, S-176, S-178, S-179, S-183 to S-189, S-192.
240
- - S-174 is registered by the Captain as part of building it.
241
- - Bundle rebuilds:
242
- - S-177: loki-ts/dist.
243
- - S-183, S-184, S-189: dashboard/static/index.html.
244
- - S-185 to S-187: web-app/dist.
375
+ **Registration and rebuilds (Captain).** S-211 owns tests/run-all-tests.sh and tests/shard-durations.tsv, so no slice edits them.
376
+ - **New tests to register, after S-211 merges:**
377
+ - S-215: tests/test-proof-pr-no-cwd-shadow.sh
378
+ - S-216: tests/test-verify-no-cwd-shadow.sh
379
+ - S-217: tests/test-enforce-test-coverage-pkg-readers-pth.sh
380
+ - S-218: tests/test-untracked-status-fsmonitor.sh
381
+ - S-219: tests/test-session-commit-add-failure.sh
382
+ - S-220: tests/test-untrack-keeps-force-staged.sh
383
+ - S-221: tests/dashboard/test_audit_verify_cli_nothing_checked.py
384
+ - S-222: tests/dashboard/test_skill_session_ws_running_agents.py
385
+ - S-223: tests/dashboard/test_notification_triggers_unreadable.py and dashboard-ui/tests/loki-notification-triggers-error.node.test.mjs
386
+ - S-224: web-app/src/components/EvidenceReceiptPanel.cost.test.mjs
387
+ - S-226: tests/test-stats-unmeasured-cost.sh and loki-ts/tests/commands/stats_unmeasured.test.ts
388
+ - S-227: tests/test-status-budget-unmeasured.sh
389
+ - S-228: DeployConnections.propagate.test.mjs
390
+ - S-229: ProjectWorkspace.preview.test.mjs
391
+ - S-230: ProjectWorkspace.phase.test.mjs
392
+ - S-233: tests/test-refused-resume-warning.sh
393
+ - **Bundle rebuilds:**
394
+ - loki-ts/dist: S-226, S-227.
395
+ - web-app/dist: S-224, S-228, S-229, S-230.
396
+ - dashboard static: S-225.
397
+ - dashboard-ui dist and dashboard static: S-223.
398
+ - **Merge order:**
399
+ - run.sh: S-217, S-218, S-219, S-220 and S-233, plus S-194 and S-195 in flight. They name regions that do not overlap, anchor on function names, and merge one at a time.
400
+ - autonomy/loki: S-226 and S-227, plus S-197 in flight, one at a time.
401
+ - dashboard/server.py: S-222 and S-223.
402
+ - ProjectWorkspace.tsx: S-229 and S-230.
403
+ - S-215 and S-216 add guarded helper copies. S-199's identity test picks them up with no edit.
404
+ - **Test rules for the git-touching slices** (S-218, S-219, S-220, S-233): each uses S-138's isolation prelude, and `bash tests/test-no-ambient-gitconfig-writes.sh` must stay green.
245
405
 
246
- **Held, not in the 20 (alternates):**
247
- - **A1: BACKLOG 108**, HIGH. `create_session_pr` never reads agent-committed-user-files.z before a LOKI_AUTO_PR push. Its only reference is the writer at run.sh 10914. Cut it the moment S-175 merges, since it is also a run.sh change.
248
- - **A2: BACKLOG 17**, the `/api/focus` POST that fires with LOKI_DASHBOARD=false (run.sh 24481). After S-175.
249
- - **A3: council_managed_should_stop** `-I -S` plus the PROJECT_DIR guard, followed by S-173's `.pth` leg. After S-157.
250
- - **A4: BACKLOG 51**, the NOT CHECKED message should name PYTHONPATH and PYTHONUSERBASE (autonomy/loki ~1270). After S-179.
251
- - **A5: BACKLOG 145 and 147**, P7 arms. After S-180.
252
- - **Too large or held:**
253
- - P1.verification-metadata-signed (a seal.v1 format change).
254
- - The P2 verify renumber (CEO, v10.0.0).
255
- - BACKLOG 18, 52, 121, 123 (audit.py half).
256
- - S-112, S-114, S-115, S-117 to S-122.
406
+ **Held, not in the 20:**
407
+ - BACKLOG 36: waits for S-198.
408
+ - BACKLOG 19 and the bash `loki proof verify` interpreter: wait for S-197 (S-179 is merged, 94035ac4).
409
+ - BACKLOG 99, bash half: waits for S-194 and S-195 (S-175 is merged, 6fab92ce).
410
+ - `StatusResponse` defaults (iteration 0, provider "claude"): changing the types touches every /api/status consumer, so this needs a design.
411
+ - BACKLOG 100 (the untrack step in the interrupt path): git commits from a signal handler need a design.
412
+ - workspace_diff count 0 in a non-git directory: needs a design.
413
+ - Speeding up test-autocapture-shadow-write-guard.sh: needs a design.
414
+ - `P4.three-setups-resolve`: waits on the D10 default decision.
415
+ - BACKLOG 18: default-off decision for the founder.
416
+ - BACKLOG 28: needs per-case expected failure reasons; design.
417
+ - BACKLOG 121, the settings half: product decision.
418
+ - `P1.verification-metadata-signed`: M2 seal.v1.
419
+ - The P2 verify renumber (CEO); S-112, S-114, S-115, S-117 to S-122.
257
420
 
258
- | S-174 | Guard: run_test with a missing or empty argument stops run-all-tests.sh with no summary and skips later suites | tests/run-all-tests.sh (run_test guard and missing-script return only), tests/test-run-all-missing-arg.sh (new) | MEDIUM | bash tests/test-run-all-missing-arg.sh exits 0 with Failed: 1 per leg (one-arg, empty-arg, missing-script) and the later stub's PASSED line printed; guard removed in a scratch copy exits 1; bash tests/test-run-all-dispatch.sh and LOKI_TEST_LIST=1 bash tests/test-shard-coverage.sh exit 0 | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
259
- | S-175 | BACKLOG 62: a whitelist-rejected LOKI_MONOREPO_TEST_CMD records pass true and touches unit-tests.pass | autonomy/run.sh (enforce_test_coverage monorepo-custom-rejected branch only), tests/test-monorepo-rejected-cmd-inconclusive.sh (new) | HIGH | bash tests/test-monorepo-rejected-cmd-inconclusive.sh exits 0: pass is "inconclusive", status not_run, no unit-tests.pass; reverting the branch exits 1; bash tests/test-trust-core-tests-detect.sh exits 0 | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
260
- | S-176 | BACKLOG 98: proof headline reads a stale test-results.json (_collect_tests has no .test-results.iter check) | autonomy/lib/proof-generator.py (_collect_tests only), tests/test_proof_tests_freshness.py (new) | HIGH | python3 -m pytest -q tests/test_proof_tests_freshness.py passes: ITERATION_COUNT=5 with marker 4 gives facts.tests.status not_run and a headline unlike the fresh case; marker 5 keeps the prior status; removing the check fails the stale case | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
261
- | S-177 | BACKLOG 98: Bun npm-test fallback reads an exit-0 run that prints failures as passed | loki-ts/src/runner/quality_gates.ts (runTestCoverage npm fallback only), loki-ts/tests/runner/npm_fallback_summary_failures.test.ts (new) | HIGH | cd loki-ts && bun test tests/runner/npm_fallback_summary_failures.test.ts exits 0: jest Tests 1 failed, vitest Test Files 1 failed and pytest 1 passed 1 error all return passed false; Tests 3 passed returns passed true; removing the parse fails the first three | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
262
- | S-178 | BACKLOG 112: /api/cost reads tracker tokens without a USD total as a measured $0 and labels the model sonnet | dashboard/server.py (get_cost context-tracker fallback only), tests/dashboard/test_cost_tracker_fallback_unmeasured.py (new) | MEDIUM | python3 -m pytest -q tests/dashboard/test_cost_tracker_fallback_unmeasured.py passes (tokens without total_cost_usd give cost null; recorded 0.0 stays 0.0; no provider gives model unknown); reverting fails case 1; bash tests/moat/p7-no-fabricated-data.sh prints CASE P7.unmeasured-cost-never-zero PASS | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
263
- | S-179 | BACKLOG 106: loki cost puts 0.0 in place of unknown spend | autonomy/loki (cmd_cost only), tests/test-loki-cost-unmeasured.sh (new) | MEDIUM | bash tests/test-loki-cost-unmeasured.sh exits 0: cap 10 with no measured records gives --json used null and percent null; measured 2.50 gives 2.5 and 25.0; reverting fails the first leg | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
264
- | S-180 | BACKLOG 144: P7 helper-return arm misses class-method helpers | tests/moat/p7-no-fabricated-data.sh (helper-return arm only) | HIGH | bash tests/moat/p7-no-fabricated-data.sh prints PASS for every P7 case and flags the in-script class-method fixture; removing the method-head pattern lets the fixture through; tests/moat/cases.txt unchanged | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
265
- | S-181 | GUARDS 11: v10-guard blocks a glob rm whose parent is a shared root (/tmp, TMPDIR, scratchpad) | scripts/v10-guard.sh (Rule 4 region only), tests/test-v10-guard.sh, docs/v10/GUARDS.md (section 11 only) | MEDIUM | bash tests/test-v10-guard.sh exits 0 with rm -f /tmp/*.log and rm -f scratchpad/* blocked and rm -f /tmp/run-1/*.log allowed; dropping the new rule fails the blocked cases | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
266
- | S-182 | docs/exit-codes.md omits the pending loki verify codes (verify --fast exits 0 on INCONCLUSIVE until v10.0.0) | docs/exit-codes.md (loki verify section only) | LOW | bash tests/test-exit-codes-documented.sh exits 0; grep -n P2.fast-verify-inconclusive-not-zero docs/exit-codes.md prints one line; the four measured codes appear in the report with their commands | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
267
- | S-183 | BACKLOG 114: migration dashboard renders a failed load as No migration data available | dashboard-ui/components/loki-migration-dashboard.js (error render branch only), dashboard-ui/tests/loki-migration-dashboard-fetch-error.node.test.mjs (new) | LOW | node --test dashboard-ui/tests/loki-migration-dashboard-fetch-error.node.test.mjs passes: a rejected fetch renders Could not load and lacks the empty-state sentence; an empty list still renders No migrations found | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
268
- | S-184 | BACKLOG 114: managed memory panel ignores a 200 events payload carrying error | dashboard-ui/components/loki-managed-memory-panel.js (events load only), dashboard-ui/tests/loki-managed-memory-events-error.node.test.mjs (new) | LOW | node --test dashboard-ui/tests/loki-managed-memory-events-error.node.test.mjs passes: the error payload renders the error line and not the empty sentence; events [] with no error still renders the empty sentence | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
269
- | S-185 | BACKLOG 114: DeployConnections rows read Not connected under their own load error | web-app/src/components/DeployConnections.tsx (row status render only), web-app/src/components/DeployConnections.state.test.mjs (new) | LOW | node --test web-app/src/components/DeployConnections.state.test.mjs passes: no row reads Not connected after a failed fetch; a real connected false still does; cd web-app && npx tsc -b exits 0 | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
270
- | S-186 | BACKLOG 116: issue list comment count never shows (gh sends comments as an array) | web-app/src/components/GitHubIssuesPanel.tsx (list comment badge only), web-app/src/types/api.ts (GitHubIssue.comments only), web-app/src/components/GitHubIssuesPanel.comments.test.mjs (new) | LOW | node --test web-app/src/components/GitHubIssuesPanel.comments.test.mjs passes: array of 2 renders 2, number 3 renders 3; cd web-app && npx tsc -b exits 0 | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
271
- | S-187 | BACKLOG 118: CostEstimator prices the whole iteration cap as the estimate | web-app/src/components/ProjectWorkspace.tsx (CostEstimator props only), web-app/src/components/CostEstimator.tsx (export only if needed), web-app/src/components/CostEstimator.estimate.test.mjs (new) | LOW | node --test web-app/src/components/CostEstimator.estimate.test.mjs passes; grep -n 'estimatedIterations={buildStatus.maxIterations' web-app/src/components/ProjectWorkspace.tsx exits 1; cd web-app && npx tsc -b exits 0 | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
272
- | S-188 | BACKLOG 123: overview proof card wording has no test of its own | dashboard-ui/tests/loki-overview-proof-card.node.test.mjs (new) | LOW | node --test dashboard-ui/tests/loki-overview-proof-card.node.test.mjs passes: no proof reads Not evaluated, a headline carries the recorded-copy prefix, gaps null reads uncertainty not measured; deleting the prefix in a scratch copy fails it | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
273
- | S-189 | BACKLOG 114: learning dashboard renders failed metrics and trends reads as no data | dashboard-ui/components/loki-learning-dashboard.js (metrics and trends load plus their two empty branches only), dashboard-ui/tests/loki-learning-dashboard-fetch-error.node.test.mjs (new) | LOW | node --test dashboard-ui/tests/loki-learning-dashboard-fetch-error.node.test.mjs passes: rejected metrics and trends render Could not load; an empty trends response still renders No trend data available | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
274
- | S-190 | BACKLOG 112: R3 design doc describes project_total_usd as a plain sum | docs/R3-COST-OBSERVABILITY-DESIGN.md | LOW | grep -n 'sum of per-run proof costs' docs/R3-COST-OBSERVABILITY-DESIGN.md exits 1; grep -n project_total_partial docs/R3-COST-OBSERVABILITY-DESIGN.md prints at least one line | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
275
- | S-191 | Velocity: test-review-assurance-tail.sh (116s) under 60s by running independent cases concurrently, budgets unchanged | tests/test-review-assurance-tail.sh | MEDIUM | time LOKI_TEST_SHARD=0/8 bash tests/test-review-assurance-tail.sh exits 0 with real under 60s and the same pass-count line as the pre-change capture; both timings reported | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
276
- | S-192 | BACKLOG 112: no test drives the web-app WebSocket status push payload for unmeasured cost | web-app/tests/test_status_push_unmeasured.py (new), web-app/server.py (lift the nested status reader only if needed) | MEDIUM | python3 -m pytest -q web-app/tests/test_status_push_unmeasured.py passes: no tokens gives cost null and max_iterations null, priced tokens give a number; forcing 0.0 in a scratch copy fails case 1 | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
277
- | S-193 | Velocity: v10-ops worktree-budget prints how many worktrees a batch may open before dispatch | scripts/v10-ops.sh (new worktree-budget subcommand), tests/test-v10-ops.sh | LOW | bash tests/test-v10-ops.sh exits 0; scripts/v10-ops.sh worktree-budget 15 prints 15 minus the .claude/worktrees entries in git worktree list --porcelain, and at or over the cap prints 0 and exits 1 | ready@2026-09-27T19:57Z | Source: 19:57Z cut. |
421
+ | S-214 | BACKLOG 147: P7 useMemo arm misses a factory that calls a registered fabricator | tests/moat/p7-no-fabricated-data.sh (HELPER_LOCAL_DECL_TMPL ~1182 and its use ~2186, ceiling comment ~978-986, one fixture beside the DECL_USEMEMO fixture ~3138-3160 only; does not overlap S-198) | HIGH | bash tests/moat/p7-no-fabricated-data.sh prints PASS for every P7 case and flags the composed useMemo fixture; removing the useMemo prefix in a scratch copy lets it through; git diff --stat tests/moat/cases.txt is empty | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
422
+ | S-215 | PR receipt renderer in proof-pr.sh imports json from the target repo (cwd shadow) | autonomy/lib/proof-pr.sh (render_evidence_receipt_md heredoc reader plus guarded _loki_snapshot_py_tool copy), tests/test-proof-pr-no-cwd-shadow.sh (new) | HIGH | bash tests/test-proof-pr-no-cwd-shadow.sh exits 0 (a planted json.py cannot forge the headline) and reverting to bare python3 - in a scratch copy fails it; bash tests/test-proven-pr-receipt.sh exits 0; bash tests/test-council-py-tool-identity.sh exits 0 and counts one more copy | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
423
+ | S-216 | loki verify inline readers import from the tree under review (cwd shadow) | autonomy/verify.sh (reader sites ~190, 591, 1269, 1271, 1295, 1337, 1339, 1441 plus guarded helper copy; not the unittest or py_compile runs), tests/test-verify-no-cwd-shadow.sh (new) | HIGH | bash tests/test-verify-no-cwd-shadow.sh exits 0 and reverting one site in a scratch copy fails it; bash tests/test-verify.sh exits 0; bash tests/moat/run.sh reports no rule failed; bash tests/test-council-py-tool-identity.sh exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
424
+ | S-217 | BACKLOG 81: enforce_test_coverage package.json readers load user-site .pth | autonomy/run.sh (enforce_test_coverage _declared_test_script and _ws_script readers only; anchor on names), tests/test-enforce-test-coverage-pkg-readers-pth.sh (new) | HIGH | bash tests/test-enforce-test-coverage-pkg-readers-pth.sh exits 0 (a .pth no longer changes the recorded test gate outcome) and reverting one reader to -E in a scratch copy fails it; no .loki/state/provider left in the repo; bash tests/test-honest-gate-status.sh exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
425
+ | S-218 | BACKLOG 131c: snapshot git status runs an agent-chosen core.fsmonitor command | autonomy/run.sh (_loki_untracked_status only), tests/test-untracked-status-fsmonitor.sh (new) | HIGH | bash tests/test-untracked-status-fsmonitor.sh exits 0 (no fsmonitor marker, real untracked file still listed) and removing the two -c flags in a scratch copy fails it; bash tests/test-no-ambient-gitconfig-writes.sh and bash tests/test-branch-lifecycle.sh exit 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
426
+ | S-219 | BACKLOG 83: a failed git add -A makes the session commit silently commit nothing | autonomy/run.sh (commit_session_changes git add -A block only), tests/test-session-commit-add-failure.sh (new) | MEDIUM | bash tests/test-session-commit-add-failure.sh exits 0: an empty embedded repo prints Left uncommitted naming the add failure, a normal repo still commits; removing the rc check in a scratch copy fails leg 1; bash tests/test-branch-lifecycle.sh exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
427
+ | S-220 | BACKLOG 109: untrack step's global reset drops force-staged agent files from the session commit | autonomy/run.sh (_loki_untrack_agent_committed_user_files only), tests/test-untrack-keeps-force-staged.sh (new) | MEDIUM | bash tests/test-untrack-keeps-force-staged.sh exits 0: git add -f dist/bundle.js lands in the session commit while the pre-existing user file stays untracked on disk; restoring git reset -q in a scratch copy fails it; bash tests/test-branch-lifecycle.sh exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
428
+ | S-221 | BACKLOG 123: audit.py verify exits 0 when it checked nothing | dashboard/audit.py (_unified_cli verify branch and docstring only; tip and prefix untouched), tests/dashboard/test_audit_verify_cli_nothing_checked.py (new) | MEDIUM | python3 -m pytest -q tests/dashboard/test_audit_verify_cli_nothing_checked.py: empty dir exits 2, valid chain 0, tampered 1, tip on an empty dir still 0; bash tests/test-audit-chain-honesty.sh and bash tests/test-audit-js-suites.sh exit 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
429
+ | S-222 | BACKLOG 118: skill-session WebSocket status push hardcodes running_agents 0 | dashboard/server.py (skill-session broadcast payload ~1030-1047 only), tests/dashboard/test_skill_session_ws_running_agents.py (new) | LOW | python3 -m pytest -q tests/dashboard/test_skill_session_ws_running_agents.py shows running_agents None on the skill-session push; restoring 0 fails it | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
430
+ | S-223 | BACKLOG 114/118: notification triggers read No triggers configured after a failed read | dashboard/server.py (get_notification_triggers only), dashboard-ui/components/loki-notification-center.js (_loadTriggers and triggers empty branch only), tests/dashboard/test_notification_triggers_unreadable.py (new), dashboard-ui/tests/loki-notification-triggers-error.node.test.mjs (new) | LOW | python3 -m pytest -q tests/dashboard/test_notification_triggers_unreadable.py shows triggers null with error on a corrupt file and [] on a missing one; node --test dashboard-ui/tests/loki-notification-triggers-error.node.test.mjs shows an error lacks No triggers configured and an empty list keeps it | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
431
+ | S-224 | BACKLOG 118: web-app receipt and cost trend show a partly priced run as a complete cost | web-app/src/components/EvidenceReceiptPanel.tsx (Cost field only), web-app/src/api/client.ts (ProofDetail cost type and cost/timeline runs type only), web-app/src/pages/MetricsPage.tsx (costTrend only), web-app/src/components/EvidenceReceiptPanel.cost.test.mjs (new) | MEDIUM | node --test web-app/src/components/EvidenceReceiptPanel.cost.test.mjs: cost_partial true renders at least $1.20, absent keeps $1.20, a partial run's trend label carries (partial); cd web-app && npx tsc -b exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
432
+ | S-225 | BACKLOG 118: standalone receipts list shows a partly priced run as a complete cost | dashboard-ui/scripts/build-standalone.js (loadReceipts cost cell only), tests/test-receipts-panel.sh (one new leg) | LOW | bash tests/test-receipts-panel.sh exits 0 with the new leg asserting at least $X.XX only when cost_partial is true; bash tests/test-budget-banner-dedup.sh exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
433
+ | S-226 | BACKLOG 106 class: loki stats reads unmeasured cost as $0.00 on both routes | autonomy/loki (cmd_stats only), loki-ts/src/commands/stats.ts, loki-ts/tests/commands/stats_unmeasured.test.ts (new), tests/test-stats-unmeasured-cost.sh (new) | MEDIUM | bash tests/test-stats-unmeasured-cost.sh exits 0 (all-zero records give cost_usd null and not recorded, same on both routes); cd loki-ts && bun test tests/commands/stats.test.ts tests/commands/stats_unmeasured.test.ts exits 0; bash tests/test-bash-bun-parity.sh exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
434
+ | S-227 | BACKLOG 106 class: loki status prints Budget $0 for a run it never measured, on both routes | autonomy/loki (cmd_status budget block only), loki-ts/src/commands/status.ts (readBudgetField and its budget caller only), loki-ts/tests/commands/status.test.ts (budget legs only), tests/test-status-budget-unmeasured.sh (new) | MEDIUM | bash tests/test-status-budget-unmeasured.sh exits 0 (budget_used 0, null or absent prints not recorded on both routes, a positive value prints as today); cd loki-ts && bun test tests/commands/status.test.ts exits 0; bash tests/test-status-cli-provider-parity.sh exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
435
+ | S-228 | BACKLOG 121: DeployConnections pushes default not-connected states upward after its own fetch failed | web-app/src/components/DeployConnections.tsx (connect and disconnect handlers only), web-app/src/components/DeployConnections.propagate.test.mjs (new) | LOW | node --test web-app/src/components/DeployConnections.propagate.test.mjs shows no synthesized statuses reach onStatusChange after a failed fetch; node --test web-app/src/components/DeployConnections.state.test.mjs and cd web-app && npx tsc -b exit 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
436
+ | S-229 | BACKLOG 114: preview header says Detecting project type forever after a failed preview-info fetch | web-app/src/components/ProjectWorkspace.tsx (getPreviewInfo call ~839 and Detecting project type branch ~1877 only), web-app/src/components/ProjectWorkspace.preview.test.mjs (new) | LOW | node --test web-app/src/components/ProjectWorkspace.preview.test.mjs shows a rejected fetch renders Could not detect project type and lacks Detecting project type; node --test web-app/src/components/ProjectWorkspace.panels.test.mjs and cd web-app && npx tsc -b exit 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
437
+ | S-230 | BACKLOG 115/118: ProjectWorkspace labels unknown phases building and Replay Build can never appear | web-app/src/components/ProjectWorkspace.tsx (buildPhase memo ~1401-1410 and Replay Build condition ~1488 only; does not overlap S-229), web-app/src/components/ProjectWorkspace.phase.test.mjs (new) | LOW | node --test web-app/src/components/ProjectWorkspace.phase.test.mjs shows an unrecognized phase is not building and a completed idle session shows Replay Build; cd web-app && npx tsc -b exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
438
+ | S-231 | BACKLOG 52: the Moat suite CI check reads as moat proven at 0 of 9 | .github/workflows/test.yml (moat-suite job name only) | LOW | gh api required_status_checks for main does not list Moat suite (else report-only); git grep -n "name: Moat suite" -- .github prints nothing; git grep -n "Moat suite" -- tests scripts .github lists only the step-summary heading; the next push shows the renamed check | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
439
+ | S-232 | autonomy/loki is linted only inside the sentrux test; the lint suite schedules big files last | tests/run-shellcheck.sh, tests/test-sentrux-init-rules.sh (T6 only) | LOW | LOKI_SHELLCHECK_JOBS=4 bash tests/run-shellcheck.sh exits 0, prints Checked ./autonomy/loki, counts match the pre-change capture plus loki; time bash tests/test-sentrux-init-rules.sh exits 0 with 8 passed under 10s; grep -c shellcheck tests/test-sentrux-init-rules.sh prints 0; both timings reported | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |
440
+ | S-233 | BACKLOG 72 remainder: refused resume does not name the blocking file or where the earlier commits are | autonomy/run.sh (setup_agent_branch resume block around the no-overwrite-ignore checkout only), tests/test-refused-resume-warning.sh (new) | LOW | bash tests/test-refused-resume-warning.sh exits 0 with the warning naming the conflicting ignored file and the recorded branch; bash tests/test-branch-lifecycle.sh exits 0 | ready@2026-09-27T20:59Z | Source: 20:59Z cut. |