loki-mode 10.3.0 → 10.4.1

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 (71) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/bin/loki +28 -0
  4. package/dashboard/__init__.py +1 -1
  5. package/docs/INSTALLATION.md +1 -1
  6. package/docs/v10/BOARD.md +22 -11
  7. package/docs/v10/GUARDS.md +45 -2
  8. package/docs/v10/GUIDE-MODERNIZE.md +93 -0
  9. package/docs/v10/MEDIUM-ANALYSIS.md +181 -0
  10. package/docs/v10/PROGRESS.md +19 -0
  11. package/loki-ts/dist/loki.js +2 -2
  12. package/mcp/__init__.py +1 -1
  13. package/package.json +1 -1
  14. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  15. package/web-app/dist/assets/{AdminPage-CunIYKsu.js → AdminPage-DXFriVML.js} +1 -1
  16. package/web-app/dist/assets/{Avatar-Dpl2qVf5.js → Avatar-p9ksx_eu.js} +1 -1
  17. package/web-app/dist/assets/{Badge-DDZcQ4uC.js → Badge-LNKA1VAh.js} +1 -1
  18. package/web-app/dist/assets/{Button-Ccuh5Ouj.js → Button-BubeNlVF.js} +1 -1
  19. package/web-app/dist/assets/{CockpitPage-Dgakdozm.js → CockpitPage-Vmnn1kk_.js} +1 -1
  20. package/web-app/dist/assets/{ComparePage-9-Zcu9Gf.js → ComparePage-y4DEGPAX.js} +1 -1
  21. package/web-app/dist/assets/{ErrorBoundary-CI756a2c.js → ErrorBoundary-DiuMh-ej.js} +1 -1
  22. package/web-app/dist/assets/{EvidenceReceiptPanel-BC3TA-vV.js → EvidenceReceiptPanel-BTg9fL9S.js} +1 -1
  23. package/web-app/dist/assets/{GitHubIssuesPanel-BdCsjPq2.js → GitHubIssuesPanel-C4fuMrPb.js} +1 -1
  24. package/web-app/dist/assets/{GitHubPRsPanel-DgXyzC-S.js → GitHubPRsPanel-BdQsKH8b.js} +1 -1
  25. package/web-app/dist/assets/{HomePage-Cijve3Mw.js → HomePage-E0Dp3m6N.js} +2 -2
  26. package/web-app/dist/assets/{LoginPage-3exGWWVo.js → LoginPage-BsbNsjYW.js} +1 -1
  27. package/web-app/dist/assets/{MagicPage-Bjy-pGNt.js → MagicPage-DGrIIo5Z.js} +1 -1
  28. package/web-app/dist/assets/{MetricsPage-CpJIaU8q.js → MetricsPage-DLvKrowx.js} +1 -1
  29. package/web-app/dist/assets/{NotFoundPage-fpgcK9hA.js → NotFoundPage-B6jgGGXs.js} +1 -1
  30. package/web-app/dist/assets/{ProjectPage-O7UQyFey.js → ProjectPage-iu7achd2.js} +3 -3
  31. package/web-app/dist/assets/{ProjectsPage-DdOZUQGM.js → ProjectsPage-zWcn06b3.js} +1 -1
  32. package/web-app/dist/assets/{SettingsPage-D3lNwNFK.js → SettingsPage-_HQ0UqwR.js} +1 -1
  33. package/web-app/dist/assets/{ShowcasePage-DBeFTDWM.js → ShowcasePage-yAsWHQEg.js} +1 -1
  34. package/web-app/dist/assets/{SystemSettingsPage-CJhMBNIO.js → SystemSettingsPage-DtZVxTJ2.js} +1 -1
  35. package/web-app/dist/assets/{TeamsPage-C6mmPl9W.js → TeamsPage-DDpGebPt.js} +1 -1
  36. package/web-app/dist/assets/{TemplatesPage-Brej2rqO.js → TemplatesPage-BlOcIhIE.js} +1 -1
  37. package/web-app/dist/assets/{TerminalOutput-C__6qBqv.js → TerminalOutput-EiD6R33t.js} +1 -1
  38. package/web-app/dist/assets/{activity-CrVuKK_W.js → activity-DbmttG_6.js} +1 -1
  39. package/web-app/dist/assets/{bell-26fqzcLm.js → bell-BVZdHdS9.js} +1 -1
  40. package/web-app/dist/assets/{bot-DmykFcjH.js → bot-CBpm5F9l.js} +1 -1
  41. package/web-app/dist/assets/{check-CzSi5Vci.js → check-NZElkYN9.js} +1 -1
  42. package/web-app/dist/assets/{chevron-left-NsdJXeCD.js → chevron-left-Bsj7g0Lx.js} +1 -1
  43. package/web-app/dist/assets/{circle-alert-BuKEAV8n.js → circle-alert--R-03UOi.js} +1 -1
  44. package/web-app/dist/assets/{clock-DPpOjTHt.js → clock-DxURKFW-.js} +1 -1
  45. package/web-app/dist/assets/{cloud-BPy4rC85.js → cloud-CwgZnGFX.js} +1 -1
  46. package/web-app/dist/assets/{code-xml-CUdET1iT.js → code-xml-DbI4aSEX.js} +1 -1
  47. package/web-app/dist/assets/{database-DS_5uXW_.js → database-DyH1aJKS.js} +1 -1
  48. package/web-app/dist/assets/{dollar-sign-CgSGxJa7.js → dollar-sign-DcirTDYQ.js} +1 -1
  49. package/web-app/dist/assets/{file-code-corner-B7iTiGB-.js → file-code-corner-D25VLaas.js} +1 -1
  50. package/web-app/dist/assets/{file-plus-rxLXNljV.js → file-plus-CXZAUQHR.js} +1 -1
  51. package/web-app/dist/assets/{globe-CVJMaRaH.js → globe-fb7DDJvp.js} +1 -1
  52. package/web-app/dist/assets/{hammer-C9KdE6y9.js → hammer-B0CgWTnB.js} +1 -1
  53. package/web-app/dist/assets/{index-B21YEJCf.js → index-h49hpHj_.js} +2 -2
  54. package/web-app/dist/assets/{layers-DNIDOX7S.js → layers-D7e5s5oV.js} +1 -1
  55. package/web-app/dist/assets/{loader-circle-HrXWSqei.js → loader-circle-CuJseaIc.js} +1 -1
  56. package/web-app/dist/assets/{lock-SfmCbb4w.js → lock-AWuJecY0.js} +1 -1
  57. package/web-app/dist/assets/{package-CwpZESj_.js → package-FOl48t3g.js} +1 -1
  58. package/web-app/dist/assets/{plus-DLh1-x2y.js → plus-B0rvkQ0K.js} +1 -1
  59. package/web-app/dist/assets/{refresh-cw-DxJsH1dQ.js → refresh-cw-9k6QfjLX.js} +1 -1
  60. package/web-app/dist/assets/{rotate-ccw-Dkny920M.js → rotate-ccw-BKfPqp6g.js} +1 -1
  61. package/web-app/dist/assets/{scroll-text-CsPrAnD5.js → scroll-text-VliGSgXD.js} +1 -1
  62. package/web-app/dist/assets/{server-E6pPKQNp.js → server-CDRRtXH3.js} +1 -1
  63. package/web-app/dist/assets/{shield-alert-C0Xh-M1C.js → shield-alert-BudxBT3Y.js} +1 -1
  64. package/web-app/dist/assets/{thumbs-up-oWNeyoZv.js → thumbs-up-DG8YD2t0.js} +1 -1
  65. package/web-app/dist/assets/{trash-2-BMv5WQCZ.js → trash-2-C3OCq0ib.js} +1 -1
  66. package/web-app/dist/assets/{trending-down-CUoz-SBV.js → trending-down-DdhqjRcI.js} +1 -1
  67. package/web-app/dist/assets/{trending-up-CI1-zKRQ.js → trending-up-DeiXF7_i.js} +1 -1
  68. package/web-app/dist/assets/{upload-CBtBD85L.js → upload-TsptvdQm.js} +1 -1
  69. package/web-app/dist/assets/{usePolling-CxtCw8cL.js → usePolling-CtO3JeYc.js} +1 -1
  70. package/web-app/dist/assets/{user-cDtPlp5V.js → user-LzUg4eFF.js} +1 -1
  71. package/web-app/dist/index.html +1 -1
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v10.3.0
6
+ # Loki Mode v10.4.1
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
470
470
 
471
471
  ---
472
472
 
473
- **v10.3.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
473
+ **v10.4.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 10.3.0
1
+ 10.4.1
package/bin/loki CHANGED
@@ -243,6 +243,34 @@ if [ "${LOKI_LEGACY_BASH:-0}" = "1" ] || [ "${LOKI_LEGACY_BASH:-}" = "true" ]; t
243
243
  exec "$BASH_CLI" "$@"
244
244
  fi
245
245
 
246
+ # M-08 (docs/v10/MODERNIZE.md section 2): the NEW `loki modernize <repo> --to
247
+ # <target>` form always reaches the Loki 10 (Bun) modernize CLI, regardless of
248
+ # LOKI_ENGINE or the default engine flip. Ahead of the v10 block below so
249
+ # tonight's legacy default never blocks it; $1 is already "modernize" so "$@"
250
+ # reproduces it as the router's own first argument without a shift.
251
+ #
252
+ # `loki modernize` is ALSO an existing legacy noun (autonomy/loki cmd_modernize,
253
+ # `heal`/`migrate` subcommands, documented in README.md and
254
+ # wiki/CLI-Reference.md): a plain catch-all here broke `loki heal`/`loki
255
+ # migrate` forwarding parity and `modernize bogus`'s error-channel contract
256
+ # (tests/cli/test-alias-forwarding.sh). --to is the one flag every valid
257
+ # engine10 invocation requires (modernize/cli.ts: "missing --to" otherwise), so
258
+ # it is the routing signal: only args containing --to go to engine10; bare
259
+ # `modernize`, `--help`/`-h`/`help`, `heal`, `migrate`, and any other token
260
+ # fall through unchanged to the existing dispatch below, which already sends
261
+ # them to the legacy CLI today. (`--help`'s own content -- whether it should
262
+ # also mention heal/migrate -- is modernize/cli.ts's USAGE text, outside this
263
+ # arm's file set; left unchanged.)
264
+ if [ "${1:-}" = "modernize" ]; then
265
+ for _loki_mod_a in "$@"; do
266
+ if [ "$_loki_mod_a" = "--to" ]; then
267
+ command -v bun >/dev/null 2>&1 || { echo "Error: loki modernize needs bun." >&2; exit 1; }
268
+ exec bun "$BUN_CLI" engine10 "$@"
269
+ fi
270
+ done
271
+ unset _loki_mod_a
272
+ fi
273
+
246
274
  # Loki 10 engine (D29): additive; skipped entirely unless LOKI_ENGINE=v10.
247
275
  if [ "${LOKI_ENGINE:-}" = "v10" ]; then
248
276
  _e10=0
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "10.3.0"
10
+ __version__ = "10.4.1"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v10.3.0
5
+ **Version:** v10.4.1
6
6
 
7
7
  ---
8
8
 
package/docs/v10/BOARD.md CHANGED
@@ -350,7 +350,7 @@ set is declared to avoid overlap with those and with each other.
350
350
  | E-64 | Lean small path and model cascade (D31): small tasks get one sonnet implement session with the cached repo map, impacted tests, PR; no plan or Wall unless no relevant tests; opus only on a test failure, reason logged; cost per call type | loki-ts/src/engine10 (implement, fix, plan, wall, sizing, session) | HIGH | cd loki-ts && bun test tests/engine10/; then EV-8 5-task measurement | merged@2026-09-28T04:15Z | Source: D30, D31. Opus REJECT (47f0d33a): a non-escalated fix round still runs on the top model while the event says no escalation; does not merge onto main. Rework dispatched. Rework APPROVE (branch worktree-wf_4601e7b3-4d8-1: 70bae9be, db2c104f, 01ff7737): non-escalated fix rounds run on the cheap model and the event records the real model. Not merged; must be re-measured (full small arm) before it becomes the default. Merged c9c15f38 (trainE18), session.ts conflict with E-68 resolved to the 30s heartbeat; `bun test tests/engine10/` 444 pass. Still behind the gate: re-measure before default. |
351
351
  | E-65 | Session token diet: find and cut what makes one v10 session cost more than raw claude -p on the same task and model | loki-ts/src/engine10, engine10-only flag in loki-ts/src/runner if needed | HIGH | before/after token table on one task, then the EV-8 5 tasks | merged@2026-09-28T02:38Z | Source: EV-8 variant C (a sonnet session $0.155 to $0.32 vs raw opus $0.216 per whole task). Built 92e3c06c: engine sessions 6 tools, no legacy append, no MCP, settingSources project; prefix 20.4k -> 7.1k tokens; 5 tasks on claude-sonnet-5 v10 4/5 $0.1523 per completed vs raw 4/5 $0.2113. Opus CONCERN: M5 (tools spread removed) and M6 (noAppend ignored) survive 1345 tests; rework sent (query()-level assertion, rebase). Opus APPROVE on rework c9a90cce (M5, M6, M7, M8 all red; runner plus engine10 1347 pass 0 fail, also without claude on PATH). Merged 8b76fd9a with dist rebuilt. EV-8 D (opus, lean, no plan or Wall) 4/5 $0.1571 per completed p50 28s; E (sonnet, lean) 4/5 $0.1519 p50 27.5s; raw opus on the same 5 tasks 5/5 $0.2161 p50 41s (~/loki-ci-logs/ev8r-{D,E}/results.jsonl). |
352
352
  | EV-11 | Medium eval tier: 15 multi-file tasks with hidden tests, tier field and --tier selection | eval/loki10/tasks/, eval/loki10/harness.py, run.sh | HIGH | python3 eval/loki10/harness.py validate; no-op baseline grades 15 not completed, 0 invalid | merged@2026-09-28T15:35Z | Source: D30. Opus CONCERN: 3 of 15 medium tasks verified (ea04f1e0). Rework dispatched to finish the 15. Rework (branch worktree-wf_4601e7b3-4d8-2, head 5718225a): 4 of 15 medium tasks verified (pub-attrs-1313, pub-click-2869, pub-faker-1817, pub-jinja-1413). Opus CONCERN: 11 tasks still missing; leads in eval/loki10/tasks/INDEX.md. Wave E18 rework: 11 missing medium tasks, branch slice-EV-11-medium-15. Opus REJECT: pub-werkzeug-3121 hidden test not verbatim as claimed; pub-werkzeug-3105 grades a feature deletion as completed. Rework wave E19. Rework r2 f7cf7b58 (branch slice-EV-11-r2). Opus REJECT (reproduced): pub-faker-1817 grades a feature deletion (uniqueness tracking removed) as completed. Next: per-task deletion-mutant audit. Wave E21 (wf_39ab3f7d-8f3). Split EV-11a/EV-11b by task, per-task deletion-mutant audit. EV-11a (02e68591, Opus APPROVE) merged into train E22 (9042e964): `bun test tests/engine10/` 547 pass 0 fail, tsc 0, `bash tests/test-v10-pulse.sh` 107 passed, `bash eval/loki10/test-harness.sh` 108 passed. EV-11b (39ee810b, Opus APPROVE) conflicts with EV-11a in harness.py and test-harness.sh (each resolved the EV-11-r2 merge separately); rebase onto main next. EV-11b r2 0d601f64 Opus APPROVE, merged with E-62-r3; gitleaks v8.30.0 dir scan of eval/loki10/tasks finds only the known pub-werkzeug-3271 pin. |
353
- | EV-12 | Large eval tier: 10 feature or legacy tasks with hidden tests, including augmentiq-style issues | eval/loki10/tasks/ | HIGH | validate plus no-op baseline over 10 | building@2026-09-28T16:45Z | Source: D30. Opus REJECT (fbd32234): 3 legacy tasks point at fixtures absent before merge (prepare_failed); spec items missing. Rework dispatched. Rework (branch worktree-wf_4601e7b3-4d8-3, head 0b9a2d91: 10 large tasks, repo-relative fixture sources). Opus REJECT: the repo-relative sources, .. rejection and fixture fixes are reproduced, but the large tasks are still smaller than the medium ones (task-size finding open). Next: rework with genuinely feature-sized tasks. Wave E18 rework: feature-sized large tasks, branch slice-EV-12-large-tasks. Opus REJECT: only lg-rbac reworked (1 of 10 feature-sized); fixture files outside the set. Rework wave E19 (fixtures now in set). Rework r2 237daa65 (branch slice-EV-12-r2). Opus REJECT: large tasks still not all feature-sized (engineer report agrees). Next: split across engineers, a few tasks each. Wave E21 (wf_39ab3f7d-8f3). Split EV-12a/b/c by task. Round 4: EV-12a CONCERN (size bar met by deleted docstrings, about 93-106 added lines), EV-12b REJECT (bundles built by an uncommitted script; no legacy code left), EV-12c REJECT (storage.validate counted but untested). Sent to the CTO for a tier ruling before any further rework. D34 (CTO): synthetic lg-* tasks closed, not merged; replaced by EV-12S (size gate) and EV-12A/B/C (real upstream PRs, 5 needed), then EV-12D (INDEX). Legacy moves to M-27. Wave E24 (wf_55378a48-585): EV-12S approved (rebase onto main pending), large tasks passing review 2 of 5 (lg-werkzeug-1513, lg-werkzeug-1680); EV-12A 1769 fix, EV-12B fresh search, EV-12C hardening building. D38 (CTO): upstream-first hidden tests plus requirements map; EV-12S approved (8ef877e8, merge pending); EV-12E, EV-12F, EV-12G cut. Reviewer shortcut patches saved to ~/loki-ci-logs/ev12-shortcuts/. |
353
+ | EV-12 | Large eval tier: 10 feature or legacy tasks with hidden tests, including augmentiq-style issues | eval/loki10/tasks/ | HIGH | validate plus no-op baseline over 10 | parked@2026-09-28T18:58Z | Source: D30. Opus REJECT (fbd32234): 3 legacy tasks point at fixtures absent before merge (prepare_failed); spec items missing. Rework dispatched. Rework (branch worktree-wf_4601e7b3-4d8-3, head 0b9a2d91: 10 large tasks, repo-relative fixture sources). Opus REJECT: the repo-relative sources, .. rejection and fixture fixes are reproduced, but the large tasks are still smaller than the medium ones (task-size finding open). Next: rework with genuinely feature-sized tasks. Wave E18 rework: feature-sized large tasks, branch slice-EV-12-large-tasks. Opus REJECT: only lg-rbac reworked (1 of 10 feature-sized); fixture files outside the set. Rework wave E19 (fixtures now in set). Rework r2 237daa65 (branch slice-EV-12-r2). Opus REJECT: large tasks still not all feature-sized (engineer report agrees). Next: split across engineers, a few tasks each. Wave E21 (wf_39ab3f7d-8f3). Split EV-12a/b/c by task. Round 4: EV-12a CONCERN (size bar met by deleted docstrings, about 93-106 added lines), EV-12b REJECT (bundles built by an uncommitted script; no legacy code left), EV-12c REJECT (storage.validate counted but untested). Sent to the CTO for a tier ruling before any further rework. D34 (CTO): synthetic lg-* tasks closed, not merged; replaced by EV-12S (size gate) and EV-12A/B/C (real upstream PRs, 5 needed), then EV-12D (INDEX). Legacy moves to M-27. Wave E24 (wf_55378a48-585): EV-12S approved (rebase onto main pending), large tasks passing review 2 of 5 (lg-werkzeug-1513, lg-werkzeug-1680); EV-12A 1769 fix, EV-12B fresh search, EV-12C hardening building. D38 (CTO): upstream-first hidden tests plus requirements map; EV-12S approved (8ef877e8, merge pending); EV-12E, EV-12F, EV-12G cut. Reviewer shortcut patches saved to ~/loki-ci-logs/ev12-shortcuts/. Parked 18:58Z per D40 (fix medium before large; EV-12F/G deprioritized); branches kept. |
354
354
  | M-00 | MODERNIZE.md design (CTO and Architect) and the Part 2 slice table M-01.. | docs/v10/MODERNIZE.md | HIGH | doc under 400 lines with a 20 to 30 slice plan | merged@2026-09-28T02:50Z | Source: D30 Part 2. ETA 02:45Z. Built 17e97855 (399 lines, 30 slices); merges in train E17 (b2ad73ce). |
355
355
  | M-01 | Modernize event types, log wrapper and state paths | loki-ts/src/engine10/modernize/types.ts, loki-ts/src/engine10/modernize/log.ts, loki-ts/tests/engine10/modernize/log.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/modernize/log.test.ts | released@2026-09-28T05:00Z | Source: MODERNIZE.md (D30). Depends on none. Built on branch worktree-wf_4601e7b3-4d8-4 (777f6cdd M-01, 212a7404 M-02, 6b00c05c M-05, 3d8edb5d M-06). TL CONCERN: cluster.ts tarjanSCC recursion overflows the stack on dependency chains of about 20-50k nodes (the M-28/M-29 scale); needs an iterative SCC. Wave E18 (wf_5063e58d-7a5) carries it with the M-05 iterative SCC rework, branch slice-M-05-iterative-scc. Merged f4d98c0b with M-05. Released in v10.1.0 (npm publish 2026-09-28T05:00Z; every cited commit is an ancestor of the v10.1.0 tag; `git merge-base --is-ancestor`). |
356
356
  | M-02 | Inventory core: files, languages, build, entry points, tests | loki-ts/src/engine10/modernize/inventory.ts, loki-ts/tests/engine10/modernize/inventory.test.ts, loki-ts/tests/engine10/modernize/fixtures/inv/ | MEDIUM | cd loki-ts && bun test tests/engine10/modernize/inventory.test.ts | released@2026-09-28T05:00Z | Source: MODERNIZE.md (D30). Depends on M-01. Built on branch worktree-wf_4601e7b3-4d8-4 (777f6cdd M-01, 212a7404 M-02, 6b00c05c M-05, 3d8edb5d M-06). TL CONCERN: cluster.ts tarjanSCC recursion overflows the stack on dependency chains of about 20-50k nodes (the M-28/M-29 scale); needs an iterative SCC. Wave E18 with M-05, branch slice-M-05-iterative-scc. Merged f4d98c0b with M-05. Released in v10.1.0 (npm publish 2026-09-28T05:00Z; every cited commit is an ancestor of the v10.1.0 tag; `git merge-base --is-ancestor`). |
@@ -359,7 +359,7 @@ set is declared to avoid overlap with those and with each other.
359
359
  | M-05 | SCC clustering, 1,500-line unit cap, topological waves | loki-ts/src/engine10/modernize/cluster.ts, loki-ts/tests/engine10/modernize/cluster.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/modernize/cluster.test.ts | released@2026-09-28T05:00Z | Source: MODERNIZE.md (D30). Depends on M-02. Built on branch worktree-wf_4601e7b3-4d8-4 (777f6cdd M-01, 212a7404 M-02, 6b00c05c M-05, 3d8edb5d M-06). TL CONCERN: cluster.ts tarjanSCC recursion overflows the stack on dependency chains of about 20-50k nodes (the M-28/M-29 scale); needs an iterative SCC. Wave E18 rework: iterative Tarjan, branch slice-M-05-iterative-scc. TL APPROVE (sonnet): iterative Tarjan 372ebe11, red on recursive (RangeError), 2000/2000 fuzz identical; merged f4d98c0b, `bun test tests/engine10/modernize/` 28 pass 0 fail. Released in v10.1.0 (npm publish 2026-09-28T05:00Z; every cited commit is an ancestor of the v10.1.0 tag; `git merge-base --is-ancestor`). |
360
360
  | M-06 | Up-front estimate (cost, time, risk), --budget math, --dry-run print | loki-ts/src/engine10/modernize/estimate.ts, loki-ts/tests/engine10/modernize/estimate.test.ts | LOW | cd loki-ts && bun test tests/engine10/modernize/estimate.test.ts | released@2026-09-28T05:00Z | Source: MODERNIZE.md (D30). Depends on M-05. Built on branch worktree-wf_4601e7b3-4d8-4 (777f6cdd M-01, 212a7404 M-02, 6b00c05c M-05, 3d8edb5d M-06). TL CONCERN: cluster.ts tarjanSCC recursion overflows the stack on dependency chains of about 20-50k nodes (the M-28/M-29 scale); needs an iterative SCC. Wave E18 with M-05, branch slice-M-05-iterative-scc. Merged f4d98c0b with M-05. Released in v10.1.0 (npm publish 2026-09-28T05:00Z; every cited commit is an ancestor of the v10.1.0 tag; `git merge-base --is-ancestor`). |
361
361
  | M-07 | modernize CLI and flag parsing; TABLE route in engine10 cli | loki-ts/src/engine10/modernize/cli.ts, loki-ts/src/engine10/cli.ts (TABLE and USAGE line only), loki-ts/tests/engine10/modernize/cli.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/modernize/cli.test.ts | merged@2026-09-28T18:25Z | Source: MODERNIZE.md (D30). Depends on M-06, E-31 merged or parked. Wave E21 (wf_39ab3f7d-8f3). TL APPROVE of 13848b53, but merged after E-66/E-61/M-24 core reads exactly 5,000 (cap is under 5,000). Next: net core delta at most -1 (offset in cli.ts or dead core code), then merge. r2 TL REJECT (reproduced): modernize/cli.ts TABLE-routed but not in registry.ts (registry.test.ts red when merged); report claimed 40/0 but 39/1; --help lost its modernize line. Next: register it, keep the USAGE line, offset core elsewhere. Wave E26 (wf_9ba5fcaf-75a). Round 4. r4 3c73b6cb honest (unsquashed) version; its only blocking finding (core 5,000) no longer reproduces after E-67 removed escalate.ts: merged 02c30314, core 4,977, budget/registry/cli tests 41 pass 0 fail, `bun test tests/engine10/` 654 pass (1 load-timeout, 35/0 alone), dist 18 passed. |
362
- | M-08 | bin/loki modernize arm to engine10 regardless of default | bin/loki (modernize arm only), tests/test-modernize-dispatch.sh | MEDIUM | bash tests/test-modernize-dispatch.sh | ready@2026-09-28T02:45Z | Source: MODERNIZE.md (D30). Depends on M-07. |
362
+ | M-08 | bin/loki modernize arm to engine10 regardless of default | bin/loki (modernize arm only), tests/test-modernize-dispatch.sh | MEDIUM | bash tests/test-modernize-dispatch.sh | merged@2026-09-28T19:13Z | Source: MODERNIZE.md (D30). Depends on M-07. Dispatched 18:58Z, sonnet engineer. Tech Lead REJECT r1 (engine10-dispatch count) and r2 (shadowed legacy modernize heal/migrate: alias-forwarding 204/9); APPROVE r3 766a493b (engine10 only when --to present). Merged; modernize-dispatch 18/0, engine10-dispatch 35/0, alias-forwarding 213/0 (main baseline), shard coverage 19/0, drift 6/0. |
363
363
  | M-09 | py2/3 capture tracer with type-tagged JSON and branch coverage | autonomy/lib/modernize/py_capture.py, tests/test-modernize-py-capture.sh, tests/fixtures/modernize/py2/ | HIGH | bash tests/test-modernize-py-capture.sh | released@2026-09-28T14:26Z | Source: MODERNIZE.md (D30). Depends on M-01. Built a4fbf034 (branch worktree-wf_4601e7b3-4d8-5). Opus REJECT (reproduced): unsupported types (sets, Decimal, datetime, bytearray, custom classes) record as equal with no not_proven entry, so the oracle could certify unproven equivalence. Next: rework. Wave E18 rework: unsupported types yield not_proven, branch slice-M-09-not-proven-types. Opus REJECT of 3594eee5: subclasses of supported types (namedtuple, IntEnum, OrderedDict) tag as the base type with no not_proven. Rework wave E19. Rework 085bc2e0 Opus APPROVE; merged b8d40a34; `bash tests/test-modernize-py-capture.sh` Passed 50 Failed 0 Skipped 1 (no python2). Released in v10.1.1 (npm publish 2026-09-28T14:26Z; every cited commit is an ancestor of the v10.1.1 tag; `git merge-base --is-ancestor`). |
364
364
  | M-10 | Coverage-guided input search (read-only session, plateau stop) | loki-ts/src/engine10/modernize/oracle/search.ts, loki-ts/tests/engine10/modernize/search.test.ts | HIGH | cd loki-ts && bun test tests/engine10/modernize/search.test.ts | merged@2026-09-28T17:20Z | Source: MODERNIZE.md (D30). Depends on M-09. Opus REJECT (reproduced): a failed seed capture is reported as a plateau. Next: rework. r2 d7db4fb1 Opus APPROVE; merged dc827b80 (on top of v10.2.2): full `cd loki-ts && bun test` 2277 pass 0 fail, `bash tests/test-engine10-dist.sh` 18 passed, `bash tests/test-v10-pulse.sh` 117 passed. |
365
365
  | M-11 | Java capture: JUnit under JDK 8 with JaCoCo plus Randoop | autonomy/lib/modernize/java_capture.sh, loki-ts/src/engine10/modernize/oracle/java.ts, loki-ts/tests/engine10/modernize/java_capture.test.ts | HIGH | cd loki-ts && bun test tests/engine10/modernize/java_capture.test.ts | merged@2026-09-28T18:25Z | Source: MODERNIZE.md (D30). Depends on M-04. Opus REJECT (reproduced): multi-line java -version breaks status.json (json_escape skips newlines). Next: rework. Wave E26 (wf_9ba5fcaf-75a). Round 3. r3 e476435b opus APPROVE (every C0 byte escaped as \u00XX; malformed status.json reported as its own reason); merged locally. |
@@ -381,7 +381,7 @@ set is declared to avoid overlap with those and with each other.
381
381
  | M-27 | Legacy-Bench pilot harness; confirm public set; calibrate cap | eval/modernize/pilot.py, eval/modernize/test-pilot.sh | HIGH | bash eval/modernize/test-pilot.sh | ready@2026-09-28T02:45Z | Source: MODERNIZE.md (D30). Depends on M-26. D34: absorbs the D30 large-tier legacy coverage. |
382
382
  | M-28 | 200K scale run (Mercurial 4.x, measured first, fallback Calibre) | eval/modernize/scale.py, eval/modernize/SCALE.md | HIGH | python3 eval/modernize/scale.py --target hg --dry-run-first | ready@2026-09-28T02:45Z | Source: MODERNIZE.md (D30). Depends on M-27. |
383
383
  | M-29 | 1M scale run (Hadoop 2.x Java 8 to 21, measured first) | eval/modernize/scale_1m.py, eval/modernize/SCALE-1M.md | HIGH | python3 eval/modernize/scale_1m.py --dry-run-first | ready@2026-09-28T02:45Z | Source: MODERNIZE.md (D30). Depends on M-28, M-11. |
384
- | M-30 | User docs for loki modernize, no dashes, commands match USAGE | docs/v10/GUIDE-MODERNIZE.md, tests/test-modernize-docs.sh | LOW | bash tests/test-modernize-docs.sh | ready@2026-09-28T02:45Z | Source: MODERNIZE.md (D30). Depends on M-07. |
384
+ | M-30 | User docs for loki modernize, no dashes, commands match USAGE | docs/v10/GUIDE-MODERNIZE.md, tests/test-modernize-docs.sh | LOW | bash tests/test-modernize-docs.sh | merged@2026-09-28T19:05Z | Source: MODERNIZE.md (D30). Depends on M-07. Dispatched 18:58Z, sonnet engineer. Tech Lead REJECT r1 (--resume id failed MID_RE), APPROVE r2 5035984d; merged 8d568c66; test-modernize-docs.sh 25/0, shard coverage 19/0, durations drift 6/0. |
385
385
  | E-66 | "Already implemented" outcome: evidence search in code, tests, docs, CHANGELOG; no change needed verdict, receipt, issue comment, no PR | loki-ts/src/engine10 (intake or plan, implement marker path, seal, pr) | HIGH | fixture with the feature ends no change needed, no implement session; fixture without proceeds | released@2026-09-28T16:03Z | Source: D32 (augmentiq #52). Opus REJECT (reproduced): no test that ALREADY_SATISFIED opens no PR; evidence search matched 652 hits for an unrelated task on this repo; confirmation need not cite files. Rework dispatched. Rework 1c7e1b09 (branch worktree-wf_b707f4ab-24f-1): all 3 blockers fixed (no-PR test F5, 0 hits for both review sentences on this repo, citation must name an existing code or test hit; evidence in receipt). Opus CONCERN: the real-repo test uses listRepoFiles capped at 2000 of 4784 files, so removing STOP_WORDS still passes; the existsSync branch of the citation check is untested. Next: small fix (full file list in that test, one existsSync test). Wave E18 small fix (uncapped file list, existsSync test), branch slice-E-66-test-fixes. Opus APPROVE of 0a64ea98 (uncapped list, existsSync test). Merge onto main conflicts in seal.ts, supervisor.ts, types.ts, rule_of_two.test.ts after E-68/E-69; rebase dispatched (wave E19). D33: states its net core line delta; core must stay under 5,000 (92 lines of headroom shared by E-67, E-66, E-61, M-14, merge order E-67, E-66, E-61); offset any excess by deleting dead core code. Rework 135ba06b Opus APPROVE, but merged it takes core to 5,189 (D33 cap 5,000; `bun test tests/engine10/budget.test.ts`). Not merged. Next: offset about 190 core lines in the same slice (dead or duplicated core code), then merge. Wave E21 (wf_39ab3f7d-8f3). r3: D33 offset. Rework r3 605f33b0 Opus APPROVE (core under 5,000 after offset); merged into train E22 (9042e964): `bun test tests/engine10/` 547 pass 0 fail, tsc 0, `bash tests/test-v10-pulse.sh` 107 passed, `bash eval/loki10/test-harness.sh` 108 passed. Released in v10.2.1 (npm publish 2026-09-28T16:03Z; every cited commit is an ancestor of the v10.2.1 tag; `git merge-base --is-ancestor`). |
386
386
  | EV-13 | Eval expected_outcome no_change_needed; aiq-52 set to it | eval/loki10/harness.py, eval/loki10/tasks/aiq-52-searchbar, test-harness.sh | HIGH | bash eval/loki10/test-harness.sh | released@2026-09-28T05:00Z | Source: D32. Opus CONCERN: a correct v10 no-change run on aiq-52 is graded as a source change. Rework dispatched. Rework APPROVE (branch worktree-wf_b707f4ab-24f-5: 19224201, e0264724): v10 Wall side effect excluded from the diff check. Not merged yet. Merged c9c15f38 (trainE18); `bash eval/loki10/test-harness.sh` 103 passed 0 failed. Released in v10.1.0 (npm publish 2026-09-28T05:00Z; every cited commit is an ancestor of the v10.1.0 tag; `git merge-base --is-ancestor`). |
387
387
  | E-67 | No pause state: unfinishable runs end as a draft PR or an issue comment with the reason within the cap; stdin never read | loki-ts/src/engine10 (machine, supervisor, worker, escalate, session) | HIGH | a stub provider that asks for input ends within the cap with a draft-PR or comment argv | merged@2026-09-28T18:25Z | Source: D32. Opus REJECT (reproduced): a hung worker ended FAILED with no draft PR and no comment, after the cap. Rework dispatched. Rework ba679f4e (branch worktree-wf_b707f4ab-24f-2). Opus REJECT: at the default cap the supervisor backstop fires before the worker cap can seal; concern: the diff check misses untracked files and uncommitted work never reaches a PR. Next: rework. Held, no builder since 03:20Z (row was stale, not running). Dispatch after E-61 (session.ts) and the E-66 rebase (supervisor.ts) merge, from rework ba679f4e plus the Opus findings above. D33: states its net core line delta; core must stay under 5,000 (92 lines of headroom shared by E-67, E-66, E-61, M-14, merge order E-67, E-66, E-61); offset any excess by deleting dead core code. D33 update 14:50Z: E-66 and E-61 merged first, core is 4,998 (1 line of headroom); E-67 must be net core negative. r3 Opus REJECT (reproduced): backstopMs = max(0, capS-30)*1000 is 0 when capS <= 30, so the worker is killed at spawn. Next: rework. Wave E26 (wf_9ba5fcaf-75a). Round 5. r5 3e38cd13 opus CONCERN with no blocking: file set widened by the CoS to include autonomy/lib/engine10-push.sh, tests/test-engine10-push.sh and loki-ts/src/engine10/types.ts (earlier opus-reviewed rounds); behaviour note: caps under about 24.8s now go straight to commit, seal and PR. Merged d4a2c620: `bun test tests/engine10/` 632 pass 0 fail, tsc 0, dist 18 passed, push 40 passed; core 4,976 (escalate.ts deleted). |
@@ -426,20 +426,31 @@ set is declared to avoid overlap with those and with each other.
426
426
  | E-94 | Guard for red main df7dc134 (a test passed locally only because gh was authenticated): local-ci fast tier re-runs every changed test file under a stripped environment (no GH_TOKEN, gh or network credentials) and fails on a difference | scripts/local-ci.sh (one check), tests/test-local-ci-hermetic.sh, docs/v10/GUARDS.md | MEDIUM | a fixture test that calls gh fails the check; the pre-E-92 dep-inventory.py is caught | merged@2026-09-28T18:42Z | Source: founder 17:22Z (each red main becomes a pre-merge guard). Wave E27 (wf_bcacb1d1-e76). Wave E27 stopped 18:37Z (founder: over budget, load 50). TL APPROVE; merged locally; `bash tests/test-local-ci-hermetic.sh` 18 passed 0 failed. |
427
427
  | E-95 | Guard for red main 8f2179cd (App Runner Watchdog Health fixture server never came up; rerun 36453069628 passed): free port by binding 0, readiness poll up to 10s with a clear message; 20/20 under parallel load | tests/test-app-runner-watchdog-health.sh, docs/v10/GUARDS.md | LOW | 20 consecutive passes while 4 parallel pulse suites run | merged@2026-09-28T18:42Z | Source: founder 17:22Z. Wave E27 (wf_bcacb1d1-e76). Wave E27 stopped 18:37Z (founder: over budget, load 50). TL APPROVE; merged locally; `bash tests/test-app-runner-watchdog-health.sh` 12 passed 0 failed. |
428
428
  | E-86 | Pre-push gitleaks for eval task fixtures (founder 15:16Z): pinned v8.30.0 with hardcoded checksums, every pushed commit scanned in dir mode from the pushed commit (not the working tree), refusal names file, line and rule, never the secret | .githooks/pre-push, scripts/install-gitleaks.sh, tests/test-pre-push-gitleaks.sh, .gitleaksignore | HIGH | real-push fixtures: a sourcegraph URL plus 40-hex pin is refused; opus security review | merged@2026-09-28T18:05Z | Source: v10.2.0 blocked by gitleaks. Rounds 1-3 opus REJECT with reproduced fail-opens (non-ASCII dirs, unfetched force-push, working-tree scan, checksum bypass; intermediate commits; root commits, history leak, case collisions). Round 4 building as one squashed commit off main. Round 4 8f9baace opus APPROVE (every earlier reproduction refuses; fresh-clone Security Audit gitleaks rc=0 with the branch merged); merged on main; `bash tests/test-pre-push-gitleaks.sh` 40 passed 0 failed. Follow-ups in E-99. |
429
- | E-96 | Safe worktree pruning: scripts/prune-worktrees.sh removes a .claude/worktrees entry only when it is not locked, has no process with a cwd inside it (lsof), and its branch has no commit or file change in the last 30 minutes measured with git and stat (never find -newermt), refusing when any check cannot run; the pulse WORKTREE_COUNT NEXT ACTION names the script | scripts/prune-worktrees.sh, tests/test-prune-worktrees.sh, scripts/v10-pulse.sh (NEXT ACTION text only) | MEDIUM | fixture: a worktree with a live process inside is kept; an idle one is removed; an unsupported check refuses | ready@2026-09-28T17:40Z | Source: 17:36Z incident: the Chief of Staff pruned by `find -newermt "-25 minutes"` (unsupported on BSD find, matched nothing) and force-removed 7 live builder worktrees (M-07 r4, M-11 r3, EV-14, EV-12F-a, EV-12G, E-95, E-87); every branch had its work committed, uncommitted edits since the last commit were lost. |
429
+ | E-96 | Safe worktree pruning: scripts/prune-worktrees.sh removes a .claude/worktrees entry only when it is not locked, has no process with a cwd inside it (lsof), and its branch has no commit or file change in the last 30 minutes measured with git and stat (never find -newermt), refusing when any check cannot run; the pulse WORKTREE_COUNT NEXT ACTION names the script | scripts/prune-worktrees.sh, tests/test-prune-worktrees.sh, scripts/v10-pulse.sh (NEXT ACTION text only) | MEDIUM | fixture: a worktree with a live process inside is kept; an idle one is removed; an unsupported check refuses | parked@2026-09-28T18:58Z | Source: 17:36Z incident: the Chief of Staff pruned by `find -newermt "-25 minutes"` (unsupported on BSD find, matched nothing) and force-removed 7 live builder worktrees (M-07 r4, M-11 r3, EV-14, EV-12F-a, EV-12G, E-95, E-87); every branch had its work committed, uncommitted edits since the last commit were lost. Superseded by E-101 (same prune-worktrees.sh scope). |
430
430
  | DEP-05 | npm/bun patch and minor batch from docs/v10/DEPS.md (web-app, dashboard-ui, vscode-extension, root; lockfiles regenerated and committed; 0.x packages excluded) | the package.json and lockfiles DEPS.md names for patch/minor only | LOW | npm audit: no new high or critical; hallucinated-dependency guard rc=0; full Tier B plus the moat suite on a PR run | ready@2026-09-28T17:45Z | Source: DEP-01 inventory (D35). |
431
431
  | DEP-06 | Python patch and minor batch from docs/v10/DEPS.md (dashboard, mcp, web-app requirements, sdk/python pyproject; 0.x excluded) | those requirements*.txt and pyproject.toml | LOW | pip-audit: no new high or critical; guard rc=0; PR run of Tests conclusion success (run id cited) | ready@2026-09-28T17:45Z | Source: DEP-01 (D35). |
432
432
  | DEP-07 | SHA-pin every remaining tag-pinned action already on its latest major (anchore/sbom-action, anthropics/claude-code-action, contributor-assistant/github-action, oven-sh/setup-bun) with a version comment | .github/workflows/*.yml (those uses: lines only) | LOW | every uses: is a full SHA with a vX comment; actionlint rc=0; PR run | ready@2026-09-28T17:45Z | Source: DEP-01 (D35). Serialize after DEP-02/DEP-03 merge (same files). |
433
- | G-01 | Usage governor (D39): scripts/usage-governor.py sums usage (output, input, cache read, cache write) from ~/.claude/projects/**/*.jsonl per model, role (from workflow labels and agent types where recorded) and hour; stores founder plan-percentage readings (docs/v10/usage-readings.tsv) and fits tokens-per-percent as a labelled estimate; projects 5-hour window and weekly usage; outputs max engineers for the next hour; checks and records whether Claude Code exposes plan usage directly (statusline input rate-limit fields, /usage) and uses it when it does | scripts/usage-governor.py, docs/v10/usage-readings.tsv, tests/test-usage-governor.sh | HIGH | fixture jsonl plus readings gives a stated projection and max-engineer number; missing readings reads "uncalibrated", never a number presented as fact | building@2026-09-28T17:50Z | Source: founder 17:44Z. First in the queue; everything obeys it. |
434
- | G-02 | Pulse BUDGET_BURN and OPUS_SHARE violations plus an hourly METRICS.md usage section (tokens per role and model, cost per merged slice, window and weekly projections, max engineers, releases per hour, merged slices per hour and per million tokens), all from G-01 | scripts/v10-pulse.sh (two checks), tests/test-v10-pulse.sh, docs/v10/METRICS.md (section header only) | MEDIUM | fixtures: opus 31% fires OPUS_SHARE; a projection of 86% fires BUDGET_BURN; uncalibrated reads UNKNOWN | ready@2026-09-28T17:50Z | Source: founder 17:44Z. Depends on G-01. Serialize after E-89..E-91 (same file). |
435
- | G-03 | docs/v10/SCALE.md: what the Max 20x plan sustains around the clock (from G-01 measurements and calibration), what 50 parallel engineers need (API pay-as-you-go with a rate-limit tier, or Team/Enterprise), cost per day estimates labelled as estimates, and the ramp gates (governor allows, merged slices per hour rising, merged work per token not falling) | docs/v10/SCALE.md | HIGH | every number cites a measurement or is labelled an estimate with its basis | building@2026-09-28T17:50Z | Source: founder 17:44Z. CTO (opus) authors. Billing is the founder decision. |
433
+ | G-01 | Usage governor (D39): scripts/usage-governor.py sums usage (output, input, cache read, cache write) from ~/.claude/projects/**/*.jsonl per model, role (from workflow labels and agent types where recorded) and hour; stores founder plan-percentage readings (docs/v10/usage-readings.tsv) and fits tokens-per-percent as a labelled estimate; projects 5-hour window and weekly usage; outputs max engineers for the next hour; checks and records whether Claude Code exposes plan usage directly (statusline input rate-limit fields, /usage) and uses it when it does | scripts/usage-governor.py, docs/v10/usage-readings.tsv, tests/test-usage-governor.sh | HIGH | fixture jsonl plus readings gives a stated projection and max-engineer number; missing readings reads "uncalibrated", never a number presented as fact | merged@2026-09-28T19:09Z | Source: founder 17:44Z. First in the queue; everything obeys it. r2 de8e1f76 opus REJECT: weekly reset 1h off across DST; fixes 2 and 4 unguarded. r3 dispatched 19:00Z. r3 fa279532 opus APPROVE (DST reset fixed; fixes 2 and 4 mutation-guarded by T14/T15); merged c2ae4347; governor 25/0, logger 16/0, run-shellcheck.sh passes, shard coverage 19/0, drift 6/0. Open non-blocking: weekly tokens counted from computed Wednesday not live resets_at-7d; no test for live-reset preference; "uncalibrated" label when idle. |
434
+ | G-02 | Pulse BUDGET_BURN and OPUS_SHARE violations plus an hourly METRICS.md usage section (tokens per role and model, cost per merged slice, window and weekly projections, max engineers, releases per hour, merged slices per hour and per million tokens), all from G-01 | scripts/v10-pulse.sh (two checks), tests/test-v10-pulse.sh, docs/v10/METRICS.md (section header only) | MEDIUM | fixtures: opus 31% fires OPUS_SHARE; a projection of 86% fires BUDGET_BURN; uncalibrated reads UNKNOWN | building@2026-09-28T19:09Z | Source: founder 17:44Z. Depends on G-01. Serialize after E-89..E-91 (same file). Dispatched 19:09Z, sonnet engineer (G-01 merged; goes before E-90/E-91, which rebase after). |
435
+ | G-03 | docs/v10/SCALE.md: what the Max 20x plan sustains around the clock (from G-01 measurements and calibration), what 50 parallel engineers need (API pay-as-you-go with a rate-limit tier, or Team/Enterprise), cost per day estimates labelled as estimates, and the ramp gates (governor allows, merged slices per hour rising, merged work per token not falling) | docs/v10/SCALE.md | HIGH | every number cites a measurement or is labelled an estimate with its basis | merged@2026-09-28T19:09Z | Source: founder 17:44Z. CTO (opus) authors. Billing is the founder decision. Merged as 4708cee1 (row status was stale). |
436
436
  | G-04 | Cloud fan-out (HIGH, CTO-owned): dispatch ready slices with no file overlap with in-flight work as Claude Code cloud sessions that open PRs from their own branches; the Release Manager merges PRs whose checks concluded success with gh pr merge; every dispatch recorded in BOARD.md with its cloud session id; ramp 25 to 50 only when the governor allows and merged slices per hour rose | scripts/cloud-dispatch.sh, docs/v10/SWARM.md (one section), tests/test-cloud-dispatch.sh | HIGH | dry-run dispatch prints the exact command and the BOARD row it would write; refuses when the governor max is reached or file sets overlap | ready@2026-09-28T17:50Z | Source: founder 17:44Z. Depends on G-01 (governor) and G-03 (plan ceiling). Verify the real cloud-session CLI syntax before building. |
437
437
  | G-05 | The same fan-out as loki modernize remote-worker mode (POST /jobs kind unit, Helm worker.engine v10): align G-04 with M-23 | (design note in docs/v10/MODERNIZE.md, one section) | MEDIUM | the note maps G-04 dispatch fields to the M-23 job schema | ready@2026-09-28T17:50Z | Source: founder 17:44Z. Depends on G-04 and M-17. |
438
- | EV-15 | Re-run the medium tier (7 tasks, raw and v10, 2 runs each, same model) with every result file written under ~/loki-ci-logs/eval/ev15-<arm>-r<n>/ (outside any worktree) and a per-task table of which runs failed and why (hidden-test failure, timeout, no PR, cost) | eval/loki10 results (outside the repo), docs/v10/METRICS.md (one section) | HIGH | 28 rows, 0 arm_unavailable; per-task failure reasons cited from the result files | building@2026-09-28T18:42Z | Source: EV-14 evidence lost (17:36Z incident) and v10 lost on all three medium axes. Governor-gated (paid run). D40 priority 1: running (wf_4af22d00-9fb), results under ~/loki-ci-logs/eval. |
439
- | E-98 | Diagnose why v10 loses to raw on medium (EV-15 per-task failures): for each task v10 failed and raw completed, read the v10 run log and name the stage and cause (plan, Wall, implement, verify, fix rounds, cap), then cut fix slices | docs/v10/ENGINE.md (findings section) | HIGH | each finding cites a result file path and a log line | building@2026-09-28T18:42Z | Source: EV-14. Depends on EV-15. CTO (opus) analysis. D40 priority 1: CTO analysis runs after EV-15 in the same workflow. |
440
- | E-99 | E-86 follow-ups (opus non-blocking): scan every pushed commit with the pushed tip's .gitleaksignore (what CI does) so a self-suppressing line added and removed in one push is refused; unset GITLEAKS_CONFIG and GITLEAKS_CONFIG_TOML in the hook; refuse a .gitleaks.toml change in any push (not only eval-touching ones) without LOKI_ALLOW_GITLEAKS_CONFIG_CHANGE=1; pin the installed binary sha256 in the hook | .githooks/pre-push, tests/test-pre-push-gitleaks.sh | MEDIUM | real-push fixtures for each case, failing first | ready@2026-09-28T18:05Z | Source: E-86 round-4 review C1-C3 and the forged-sidecar boundary. |
438
+ | EV-15 | Re-run the medium tier (7 tasks, raw and v10, 2 runs each, same model) with every result file written under ~/loki-ci-logs/eval/ev15-<arm>-r<n>/ (outside any worktree) and a per-task table of which runs failed and why (hidden-test failure, timeout, no PR, cost) | eval/loki10 results (outside the repo), docs/v10/METRICS.md (one section) | HIGH | 28 rows, 0 arm_unavailable; per-task failure reasons cited from the result files | merged@2026-09-28T19:40Z | Source: EV-14 evidence lost (17:36Z incident) and v10 lost on all three medium axes. Governor-gated (paid run). D40 priority 1: running (wf_4af22d00-9fb), results under ~/loki-ci-logs/eval. Done 19:19Z: raw 10/14 $0.5085 p50 56s; v10 9/14, cost at least $0.788 (E-98 correction) p50 128s. Files durable under ~/loki-ci-logs/eval/ev15-*. |
439
+ | E-98 | Diagnose why v10 loses to raw on medium (EV-15 per-task failures): for each task v10 failed and raw completed, read the v10 run log and name the stage and cause (plan, Wall, implement, verify, fix rounds, cap), then cut fix slices | docs/v10/ENGINE.md (findings section) | HIGH | each finding cites a result file path and a log line | merged@2026-09-28T19:40Z | Source: EV-14. Depends on EV-15. CTO (opus) analysis. D40 priority 1: CTO analysis runs after EV-15 in the same workflow. docs/v10/MEDIUM-ANALYSIS.md merged d496db89. Top cause: verify hard-codes python, so 27/27 pytest checks were not_run and no fix round ever fired. Cards E-98a..f below. |
440
+ | E-98a | verify uses the project interpreter (.venv, venv, $VIRTUAL_ENV, python3, python); a check on a system interpreter adds a not_proven line | loki-ts/src/engine10/stages/verify.ts, loki-ts/tests/engine10/verify*.test.ts | HIGH | fixture red then green (.venv shim, no python on PATH); core +12 max | building@2026-09-28T19:40Z | Source: MEDIUM-ANALYSIS.md. Dispatched 19:40Z sonnet; opus review. |
441
+ | E-98b | a spec_conflict implement exit still runs verify and fix; receipt keeps SPEC_CONFLICT | loki-ts/src/engine10/machine.ts, loki-ts/tests/engine10/machine*.test.ts | HIGH | fake-stage test red on main; core +3 max | building@2026-09-28T19:40Z | Source: MEDIUM-ANALYSIS.md. Dispatched 19:40Z sonnet; opus review. |
442
+ | E-98c | existing test files append-only in the implement brief; impactedTests falls back to named files when relevant_files is empty | loki-ts/src/engine10/stages/implement.ts, its test | MEDIUM | unit test red then green; core +2 max | building@2026-09-28T19:40Z | Source: MEDIUM-ANALYSIS.md. Dispatched 19:40Z sonnet. |
443
+ | E-98d | repo map extracts Python top-level def and class names | loki-ts/src/engine10/repomap.ts, loki-ts/tests/engine10/repomap*.test.ts | MEDIUM | unit test red then green; core +4 max | building@2026-09-28T19:40Z | Source: MEDIUM-ANALYSIS.md. Dispatched 19:40Z sonnet. Offline 7-repo check runs after merge. |
444
+ | E-98e | a session killed at its stage limit writes a partial-stream cost record, never cost_usd null | loki-ts/src/engine10/session.ts, loki-ts/src/engine10/cost.ts, a test | MEDIUM | fake killed stream test red then green; core +10 max | building@2026-09-28T19:40Z | Source: MEDIUM-ANALYSIS.md. Dispatched 19:40Z sonnet. |
445
+ | E-98f | A/B eval of Wall and cascade on medium (default, WALL=0, CASCADE=0, n=3 each), then a sizing default only if a knob wins on completions without losing on cost | eval run; loki-ts/src/engine10/sizing.ts | HIGH | chosen default at or above raw 71.4% and below $0.5085 per completed; after table published in MEDIUM-ANALYSIS.md | ready@2026-09-28T19:40Z | Source: MEDIUM-ANALYSIS.md. Depends on E-98a..e merged. One combined re-run replaces the per-card re-runs (D40 cost). |
446
+ | E-99 | E-86 follow-ups (opus non-blocking): scan every pushed commit with the pushed tip's .gitleaksignore (what CI does) so a self-suppressing line added and removed in one push is refused; unset GITLEAKS_CONFIG and GITLEAKS_CONFIG_TOML in the hook; refuse a .gitleaks.toml change in any push (not only eval-touching ones) without LOKI_ALLOW_GITLEAKS_CONFIG_CHANGE=1; pin the installed binary sha256 in the hook | .githooks/pre-push, tests/test-pre-push-gitleaks.sh | MEDIUM | real-push fixtures for each case, failing first | merged@2026-09-28T18:58Z | Source: E-86 round-4 review C1-C3 and the forged-sidecar boundary. Opus APPROVE; merged 5ee5a630 (conflict with E-100 case 20 resolved: guard kept, E-99 message taken; gitleaks test 43/0 with binary, 19/0/24 skipped without; pre-push hook 13/0). |
441
447
  | E-100 | P0: main Tests red on cc4992ed (run 36465466283): tests/test-pre-push-gitleaks.sh case 20 asserted a pass without the pinned gitleaks binary, which the CI runner does not have | tests/test-pre-push-gitleaks.sh | HIGH | `HOME=<empty> bash tests/test-pre-push-gitleaks.sh` 18 passed 0 failed 22 skipped; with the binary 40 passed | merged@2026-09-28T18:42Z | Built 91a47f52; the class is guarded by E-94 (changed tests re-run with an empty HOME). |
442
- | E-101 | Eval results durable (D40 priority 4): run.sh and harness.py write results.jsonl to ~/loki-ci-logs/eval/<run> and a redacted copy to eval/loki10/archive/; scripts/prune-worktrees.sh never removes a worktree with a live process, a commit in the last 30 minutes, or un-archived eval results | eval/loki10/run.sh, eval/loki10/harness.py, scripts/prune-worktrees.sh, tests/test-eval-archive.sh, tests/test-prune-worktrees.sh | HIGH | fixtures: live-process and un-archived worktrees kept; a planted token never reaches the in-repo archive | building@2026-09-28T18:42Z | Source: EV-14 results lost 17:36Z. Supersedes E-96. |
448
+ | E-101 | Eval results durable (D40 priority 4): run.sh and harness.py write results.jsonl to ~/loki-ci-logs/eval/<run> and a redacted copy to eval/loki10/archive/; scripts/prune-worktrees.sh never removes a worktree with a live process, a commit in the last 30 minutes, or un-archived eval results | eval/loki10/run.sh, eval/loki10/harness.py, scripts/prune-worktrees.sh, tests/test-eval-archive.sh, tests/test-prune-worktrees.sh | HIGH | fixtures: live-process and un-archived worktrees kept; a planted token never reaches the in-repo archive | merged@2026-09-28T19:40Z | Source: EV-14 results lost 17:36Z. Supersedes E-96. Reviewer APPROVE bbe83c7a (mutation-checked all 3 prune checks and redact_row); merged 21df7d4a; prune-worktrees 26/0, eval-archive 5/0. Used at 19:40Z to prune 6 finished worktrees. |
449
+ | E-102 | release.sh --bump-only must never leave a tree without its tracked dist: if the loki-ts build fails (for example no node_modules in a fresh worktree), exit non-zero and restore loki-ts/dist from HEAD; when the only source change is VERSION, patch the version literal in dist instead of rebuilding (no debugId or source-map path churn) | scripts/release.sh, tests/test-release-bump-dist.sh | MEDIUM | fixture: a worktree with no node_modules gives a non-zero exit with dist unchanged; a VERSION-only bump changes exactly the version literal in dist/loki.js | merged@2026-09-28T19:29Z | Source: 19:20 cut of v10.3.1: in a fresh worktree the build failed (@anthropic-ai/sdk unresolved) and deleted 4 tracked dist files; a node_modules symlink then rewrote source-map paths. Shipped by hand-patching the version literal (d811e5c3). Tech Lead APPROVE c83a07e2; merged c35d3fa7; bump-dist 7/0 (red first 3/4), bump-only 8/0, release-sh 29/0, shard coverage 19/0, drift 6/0. |
450
+ | E-103 | release.sh --bump-only: when the build exits 0 but dist/loki.js does not embed the new version (release.sh:475-479), restore loki-ts/dist from HEAD and exit non-zero, as the build-failure path already does | scripts/release.sh, tests/test-release-bump-dist.sh | LOW | fixture: a stub build that exits 0 without writing the version gives a non-zero exit with dist byte-identical to HEAD | merged@2026-09-28T19:31Z | Source: E-102 Tech Lead review (non-blocking note). Tech Lead APPROVE 1150af81 (shared release_bump_only_fail, no duplicated restore); bump-dist 10/0 (red 9/10 first), bump-only 8/0, release-sh 29/0. |
451
+ | E-104 | tests/test-verify.sh scenario 3 plants AKIAIOSFODNN7EXAMPLE, which gitleaks (8.30.1 on a dev Mac) allowlists as the AWS doc example, so the test goes VERIFIED/0 wherever gitleaks is installed and passes only where loki verify falls back to its regex scanner (CI). Plant a non-example secret shape and assert BLOCKED on both scanner paths | tests/test-verify.sh | LOW | run with gitleaks on PATH and with PATH stripped of it: BLOCKED/2 both ways | ready@2026-09-28T19:45Z | Source: 19:40 train fast tier: FAIL planted secret -> expected BLOCKED/2, got VERIFIED/0, reproduced on origin/main (CI green there). Env-conditional assertion class. |
452
+ | E-105 | tests/check-heredoc-dollar-digit.sh flags autonomy/run.sh:5548 (`local _var="$1" _had="$2" _val="$3"`), a function body, not a python3 -c body: false positive that keeps the fast tier red on main | tests/check-heredoc-dollar-digit.sh | LOW | the run.sh:5548 shape passes; a real $1 inside python3 -c "..." still fails (red first) | ready@2026-09-28T19:45Z | Source: 19:40 train fast tier; line unchanged for 27h, identical on origin/main. |
453
+ | E-106 | P0: claude-agent-sdk version drift. loki-ts/package.json is 0.3.283 (9db2a4ed) but root package.json and package-lock.json pin 0.3.267 and Dockerfile:160 installs 0.3.208, so the published package resolves an SDK older than the one the engine was evaluated on. Align all pins; add tests/test-sdk-version-sync.sh so CI (not only local-ci.sh) catches drift | package.json, package-lock.json, Dockerfile, tests/test-sdk-version-sync.sh, tests/run-all-tests.sh, tests/shard-durations.tsv | MEDIUM | new test red on main (3 mismatches) then green; npm pack --dry-run succeeds | building@2026-09-28T19:45Z | Source: 19:40 train fast tier FAIL "Agent SDK is a resolvable root dependency"; reproduced on origin/main (root 0.3.267 vs loki-ts 0.3.283). Dispatched 19:45Z sonnet. |
443
454
  | E-58 | Issue-ref runs: supervisor creates runDir before the fetch child writes issue.json; makes E-47 green | loki-ts/src/engine10/supervisor.ts (one line before fetchIssueToFile), E-47 test files from 544348a7 | MEDIUM | cd loki-ts && bun test tests/engine10/issue_ref_e2e.test.ts (3 pass) | released@2026-09-28T02:38Z | Source: E-47 finding (TL reproduced). Merged 646a6cd7 (train E13): engine10 388 pass 0 fail, tsc exit 0, test-engine10-dist 18/0, test-engine10-docs 26 passed, test-harness 82/0. APPROVE (6384fff9); issue_ref_e2e 3 pass. Released v9.81.0 (npm view loki-mode time: 2026-09-28T02:38:54Z). |
444
455
  | E-59 | Receipt model and summary tokens match the provider: cost.ts takes model from the result-cost file; events.ts fold sums cache read and creation tokens; makes E-50 green | loki-ts/src/engine10/cost.ts, loki-ts/src/engine10/events.ts, E-50 test files from 716618d4 | HIGH | cd loki-ts && bun test tests/engine10/model_report.test.ts tests/engine10/output.test.ts | released@2026-09-28T02:38Z | Source: E-50 finding. Reconcile with E-44 (output.ts already folds cache tokens at render). Opus reviewer (cost numbers feed the gate). Opus CONCERN: writeResultCost writes no model, so real records still use the caller model; summary tokens at supervisor.ts still exclude cache. Rework dispatched. Merged 3ab2a8fa (train E14, rebased on main): engine10 404 pass 0 fail (402 pass 0 fail with claude removed from PATH), tsc exit 0, test-harness 86/0, test-local-ci-gitleaks 6/0, test-engine10-dist 18/0. Released v9.81.0 (npm view loki-mode time: 2026-09-28T02:38:54Z). |
445
456
  | EV-8 | v10 cost check on 5 tasks before the full arm (CEO 23:31Z): v10 arm, same model, after E-42 and E-45 merge | eval/loki10 results (gitignored) plus docs/v10/METRICS.md block | HIGH | eval/loki10/run.sh --arm v10 --tasks <5 ids> reports completed, time to PR and provider cost per task | released@2026-09-28T02:38Z | Target cost per completed task at or below $0.2363 (raw claude -p full arm). Depends on E-42, E-45, E-38 (--tasks). Incident 01:38Z: first run 0/5 on both variants measured the wrong code. The harness default arm binary is the global loki (loki --version: v9.78.0), and the main checkout node_modules still had agent SDK 0.3.267 (package.json pins 0.3.283), whose bundled Claude Code 2.1.267 rejects claude-opus-5-5, so every session exited "error" in about 1s with 0 tokens. Fixed in 7c3dea3d: bun install (node_modules 0.3.283), repro with the harness arm_env and arm_auth now completes on claude-opus-5-5 ($0.11, 13s); dist rebuilt. Rerun started with LOKI_EVAL_LOKI_BIN=<repo>/bin/loki. Guards E-61, E-62. Rerun measured (not a code slice): A 4/5 $0.5954, B 5/5 $0.3976, C (all sonnet, no plan, no Wall) 4/5 $0.294, raw 5/5 $0.2161 (~/loki-ci-logs/ev8r-{A,B,C}/results.jsonl). Gate not met on cost; D31 and E-64, E-65 follow. Released v9.81.0 (npm view loki-mode time: 2026-09-28T02:38:54Z). |
@@ -615,7 +615,7 @@ previously mismarked two merged guards (S-16, S-74) as PENDING.
615
615
  restore) and a clean rerun showed `Results: 6 passed, 0 failed`, exit 0.
616
616
  Run: `bash tests/test-dep-inventory.sh`.
617
617
 
618
- ## 17. Hardcoded fixture ports raced concurrent runs of the same test (E-95)
618
+ ## 18. Hardcoded fixture ports raced concurrent runs of the same test (E-95)
619
619
 
620
620
  - **Incident:** commit `8f2179cd`, Tests run `36453069628`,
621
621
  `tests/test-app-runner-watchdog-health.sh` failed with "healthy fixture
@@ -657,7 +657,7 @@ previously mismarked two merged guards (S-16, S-74) as PENDING.
657
657
  concurrent `test-v10-pulse.sh` copies completed clean, exit 0, over the
658
658
  same window). `bash -n` and `shellcheck` both clean on the file.
659
659
 
660
- ## 17. A local pass depended on `gh` being authenticated on the dev Mac (E-94)
660
+ ## 19. A local pass depended on `gh` being authenticated on the dev Mac (E-94)
661
661
 
662
662
  - **Incident:** `tests/test-dep-inventory.sh` passed locally and failed on
663
663
  the CI runner. Root-caused to `scripts/dep-inventory.py`'s `self_test()`:
@@ -754,3 +754,46 @@ previously mismarked two merged guards (S-16, S-74) as PENDING.
754
754
  directly against this worktree, found the one real in-scope change and
755
755
  returned `hermetic-clean` in 5.6s, well inside the 60s budget. Run:
756
756
  `bash tests/test-local-ci-hermetic.sh`.
757
+
758
+ ## 20. Eval results lost when a worktree was force-removed (E-96/EV-14, E-101)
759
+
760
+ - **Incident:** `eval/loki10/results/*/results.jsonl` is gitignored
761
+ (`eval/loki10/.gitignore`), so it exists only inside the worktree that ran
762
+ the eval. The 17:36Z pruning incident (guard 5's family, PROGRESS.md)
763
+ force-removed 7 live builder worktrees including EV-14's; that eval's
764
+ per-run results were destroyed with it (METRICS.md 18:00Z note) and could
765
+ not be re-audited.
766
+ - **Root cause with evidence:** nothing ever copied `results.jsonl` outside
767
+ the worktree that produced it, and no existing prune tool checked for
768
+ un-copied results before removing a worktree.
769
+ - **The guard:** `eval/loki10/harness.py` `cmd_run` now writes a redacted
770
+ copy of every row (`redact_row`: drops the `arm_stdout`/`arm_stderr`/etc.
771
+ log paths and any secret-shaped string) to both
772
+ `${LOKI_EVAL_ARCHIVE:-$HOME/loki-ci-logs/eval}/<run-name>/results.jsonl`
773
+ (outside the repo) and the committed `eval/loki10/archive/<run-name>.results.jsonl`,
774
+ per row inside the same lock that writes the worktree-local copy, so a
775
+ killed run keeps what it already archived. `scripts/prune-worktrees.sh`
776
+ refuses to remove a worktree that has a `results.jsonl` whose `run_id`s
777
+ are not all present in an archived copy, and separately refuses to remove
778
+ one with a live process inside it (`lsof -d cwd -Fn`) or a branch commit
779
+ less than 30 minutes old (`git log -1 --format=%ct`) -- any check that
780
+ cannot run (lsof missing/broken, unparseable JSON) REFUSES rather than
781
+ guessing. No file-age signal (`stat`, `find -newermt`, etc.) is used
782
+ anywhere in it.
783
+ - **The test that proves it fires:** `tests/test-prune-worktrees.sh` keeps a
784
+ worktree with a live process inside it, keeps one whose results are not
785
+ yet archived, removes one whose results ARE archived (positive control),
786
+ and refuses everything when `lsof` is stubbed to fail. Deleting any one of
787
+ the three new checks from `scripts/prune-worktrees.sh` (live-process,
788
+ 30-minute, or archived-results) turns the corresponding case red: 24
789
+ passed / 2 failed each time, vs. 26 passed / 0 failed with the check in
790
+ place. `tests/test-eval-archive.sh` plants a token
791
+ (`sk-ant-plantedTOKEN9999`, a GitHub-token-shaped string, and a
792
+ `KEY=VALUE`-shaped one) in a synthetic row and asserts none of it survives
793
+ `redact_row`, that the log paths are gone, that real fields (`task`,
794
+ `run_id`, `harness_sha`, `cost_usd`) survive intact, and that the redacted
795
+ rows still `summarize_rows()` correctly (an empty/over-stripped archive
796
+ would otherwise pass the secret check too). Replacing `redact_row` with a
797
+ no-op (`return dict(row)`) reproduces the incident directly: the planted
798
+ secret and the log paths both survive.
799
+ Run: `bash tests/test-prune-worktrees.sh && bash tests/test-eval-archive.sh`.
@@ -0,0 +1,93 @@
1
+ # loki modernize guide
2
+
3
+ `loki modernize` converts a legacy codebase to a modern target with no
4
+ human steps, using behavior captured from the old code as proof of
5
+ equivalence. It is a v10 engine subcommand (docs/v10/MODERNIZE.md is the
6
+ design source of truth; this page is the user-facing summary).
7
+
8
+ ## What it does
9
+
10
+ - Inventories the repo, builds a dependency graph, and clusters files into
11
+ units sized to convert in well under an agent's reliable working horizon.
12
+ - Prints a cost, wall-time and risk estimate before any model spend.
13
+ - Captures the old code's behavior (inputs, outputs, exceptions) as a
14
+ sealed oracle, then converts each unit and checks the new code against
15
+ that oracle case by case, held-out cases included.
16
+ - A unit is only ever claimed proven when its equivalence rate is 100% on
17
+ every case. Anything less is reported as NOT PROVEN with the reason; it
18
+ is never rounded up.
19
+ - Ships one pull request per wave of units, with old and new code coexisting
20
+ behind a routing flag until every unit in that wave is proven.
21
+
22
+ ## When to use it
23
+
24
+ Use it to port a legacy codebase (Python 2 to 3 today; Java 8 to 21 next)
25
+ where you want a paper trail of exactly what was proven equivalent and
26
+ what was not, rather than a model's unverified claim that the port works.
27
+ Do not use it for the existing `loki migrate` (a different, agent-judged
28
+ legacy engine); that command is unchanged and out of scope here.
29
+
30
+ Only two targets exist right now: `python3` and `java21`. COBOL-to-Java and
31
+ AngularJS-to-React are planned but not built.
32
+
33
+ ## Commands and flags
34
+
35
+ ```
36
+ loki modernize <repo> --to "<target>" [--budget USD] [--workers N] [--remote URL]
37
+ [--resume <mid>] [--dry-run] [--provider P] [--no-pr]
38
+ ```
39
+
40
+ | Flag | Meaning |
41
+ |---|---|
42
+ | `<repo>` | Required. Path to the repo to convert. |
43
+ | `--to` | Required. Target: `python3` or `java21`. An unrecognized target exits 2 and lists the supported ones. |
44
+ | `--budget` | USD hard cap for the whole run. Dispatch stops once spend plus the in-flight estimate would exceed it. |
45
+ | `--workers` | Concurrent unit workers. Default 4. Max 32 without `--remote`; use `--remote` for more. |
46
+ | `--remote` | Dispatches units to a remote worker cluster at the given URL instead of running them locally. |
47
+ | `--resume` | Resumes a prior run from its modernization id (`mod-<utc>-<short>`), picking up where the event log left off. |
48
+ | `--dry-run` | Runs inventory only: prints the unit count, wave plan and estimate, then exits 0 with zero model spend. |
49
+ | `--provider` | Overrides the model provider used for unit conversion. |
50
+ | `--no-pr` | Keeps everything local; skips opening a pull request. |
51
+
52
+ Running it with no arguments prints the same usage text.
53
+
54
+ ## Worked example
55
+
56
+ Estimate a conversion with no spend, using up to 8 local workers:
57
+
58
+ ```
59
+ loki modernize ./legacy-service --to python3 --dry-run --workers 8
60
+ ```
61
+
62
+ This inventories the repo, clusters it into units, and prints the unit
63
+ count, wave plan, and cost/time/risk estimate, then stops. Nothing is
64
+ converted and no model is called.
65
+
66
+ To actually run it with a budget cap and no pull request:
67
+
68
+ ```
69
+ loki modernize ./legacy-service --to python3 --budget 50 --no-pr
70
+ ```
71
+
72
+ If it is interrupted, resume it with the modernization id it printed:
73
+
74
+ ```
75
+ loki modernize ./legacy-service --to python3 --resume mod-20260928T143022Z-ab12cd
76
+ ```
77
+
78
+ ## Limits
79
+
80
+ - Only `python3` and `java21` targets exist. Passing anything else fails
81
+ with exit 2.
82
+ - Oracle capture, planning and execution beyond the dry-run estimate are
83
+ still landing; a non-dry-run invocation today stops after printing the
84
+ estimate and reports that oracle capture and execution are not built
85
+ yet.
86
+ - The Java target's dependency graph builder is not wired in yet; a
87
+ `java21` run reports that gap honestly instead of clustering on an
88
+ empty graph.
89
+ - A unit is claimed proven only when its captured-case equivalence rate is
90
+ 100%, including held-out cases. Anything short of that stays NOT PROVEN
91
+ with its reason; the tool never claims more than the evidence supports.
92
+ - `--workers` above 32 requires `--remote`; without it, the run fails
93
+ rather than silently capping the value.
@@ -0,0 +1,181 @@
1
+ # E-98: why v10 loses to raw `claude -p` on the medium tier (EV-15)
2
+
3
+ Source data: EV-15 (2026-09-28, harness `cc4992ed`, v10.2.5, `claude-opus-5-5`, 7 `pub-*` medium tasks, 2 runs per arm, 900s cap). The engine10 code this analysis cites is unchanged between `cc4992ed` and `origin/main` `d811e5c3` (`git diff --stat cc4992ed origin/main -- loki-ts/src/engine10` is empty).
4
+ All paths below are relative to `/Users/lokesh/loki-ci-logs/eval/` (called EV below). `EV/ev15-summary.md` and `EV/ev15-stage-detail.md` are the run summaries.
5
+
6
+ The founder's "12/14 vs 10/14" comes from EV-14. Its result files were lost when a worktree was force-removed (E-96/E-101). EV-15 re-ran the tier: raw 10/14, v10 9/14. The numbers here are EV-15's, and every claim cites an EV-15 file.
7
+
8
+ ## 1. Outcome per task-run
9
+
10
+ | task | raw r1 | raw r2 | v10 r1 | v10 r2 | class |
11
+ |---|---|---|---|---|---|
12
+ | pub-jinja-1413 | pass | pass | **miss** | **miss** | **v10 loss (2)** |
13
+ | pub-werkzeug-3105 | miss | miss (hidden_pass, no push) | miss | miss | shared miss |
14
+ | pub-werkzeug-3271 | miss | miss | miss | pass | shared miss, one v10 win |
15
+ | attrs-1313, click-2869, faker-1817, werkzeug-3121 | pass | pass | pass | pass | tie (v10 slower/costlier) |
16
+
17
+ Only two task-runs were completed by raw and missed by v10: pub-jinja-1413 r1 and r2.
18
+ - werkzeug-3105: both arms fail the same hidden test with the same error. `EV/ev15-v10-r{1,2}/logs/pub-werkzeug-3105*/grade_hidden.stdout.log` and `EV/ev15-raw-claude-r1/logs/pub-werkzeug-3105*/grade_hidden.stdout.log` all show `FAILED tests/test_routing.py::test_no_duplicate_head_options - DuplicateRuleError: / -> a`.
19
+ - werkzeug-3271 r1: both arms fail with `FAILED tests/test_wrappers.py::test_user_agent - Failed: DID NOT WARN`.
20
+ - These are task difficulty, not v10 stage losses.
21
+
22
+ ## 2. Failure table (v10 losses, with log citations)
23
+
24
+ Event logs:
25
+ - `EV/ev15-engine/v10-r1/pub-jinja-1413.v10.71372932a4ef/.loki/runs/e10-20260928T185044Z-5451/events.jsonl` (r1)
26
+ - `EV/ev15-engine/v10-r2/pub-jinja-1413.v10.78270c64e4ab/.loki/runs/e10-20260928T190755Z-60df/events.jsonl` (r2)
27
+
28
+ Hidden grade, in both runs (`EV/ev15-v10-r{1,2}/logs/pub-jinja-1413*/grade_hidden.stdout.log`):
29
+ - Result: `2 failed, 12 passed`.
30
+ - The failing tests are `TestSet::test_set_invalid` and `TestSet::test_namespace_redefined`, both `DID NOT RAISE TemplateRuntimeError`.
31
+ - Both tests passed at baseline (`baseline.stdout.log`: only `test_namespace_set_tuple` failed).
32
+ - So v10 broke the namespace runtime check. These are regressions in existing tests, not a missing feature.
33
+ - Raw (opus) kept the check: `EV/ev15-raw-claude-r1/logs/pub-jinja-1413*/grade_hidden.stdout.log` shows `14 passed`.
34
+
35
+ | run | stage that lost it | exact event lines | cause (one sentence) |
36
+ |---|---|---|---|
37
+ | jinja r1 | implement brief, then early exit past verify | seq21 `stage.completed implement {"exit": "spec_conflict", ..., "spec_conflict_reason": "plan step 8 requires adding tests to the existing tests/test_core_tags.py, but the rules make existing test files read-only ...", "impacted_tests": []}`; seq22 `stage.started commit` directly after it (no verify stage); seq25 `receipt.sealed ... "verdict": "SPEC_CONFLICT"` | The brief rule "existing test files are read-only" (implement.ts:33) turned a normal task into `spec_conflict`, and `earlyExit` (machine.ts:55) then skipped verify and the fix loop, so a sonnet diff that regressed two existing tests shipped untested. |
38
+ | jinja r2 | verify (blind), so no fix round | seq32 `stage.completed implement {"exit": "done", ..., "impacted_tests": ["examples/basic/loki_wall_test_namespace_tuple_assign.py"]}`; `test.result verify {"name": "pytest:tests/test_core_tags.py", "cmd": "python -m pytest -q tests/test_core_tags.py", "result": "not_run", "reason": "python not found on PATH"}`; no `fix` event; seq45 `run.completed {"verdict": "PARTIAL", ...}` | Verify picked the right file (`tests/test_core_tags.py` contains both regressed tests), but ran it as `python`. The host has only `python3` (`which python` prints `python not found`), and the task's own `work/.venv` was never tried, so the check was `not_run`, `failures_grouped` stayed empty, and the fix loop never started. |
39
+
40
+ What each session actually ran:
41
+ - jinja r2 (`.loki/logs/bash-audit.jsonl`): the implementer ran only the Wall test, with system `python3` and `PYTHONPATH=src`. It never ran `tests/test_core_tags.py`.
42
+ - Its log (`iteration-e10-20260928T190755Z-60df-impl.log`) says it added new tests "after `test_namespace_macro`". Seal's `weakened test: tests/test_core_tags.py` fires on any modification (seal.ts:176), not only on weakening.
43
+ - The two regressed tests are therefore most likely still intact in the sandbox. A working verify would then have failed them. This is likely, not proven: the EV-15 working trees are gone, so the E-98a/E-98b re-run settles it.
44
+ - jinja r1 needed two fixes to reach a fix round: the interpreter fix, and a verify that still runs after `spec_conflict`.
45
+
46
+ ## 3. Engine-wide facts (all 14 v10 event logs)
47
+
48
+ Commands: the scripts `dump.py`, `sumall.py` and `cost.py` read every `EV/ev15-engine/v10-r*/*/.loki/runs/*/events.jsonl`.
49
+
50
+ - **Verify never ran a test.**
51
+ - 27 of 27 `test.result` pytest checks are `not_run` / `python not found on PATH`.
52
+ - 9 of 9 ruff checks are `not_run` / `ruff not found on PATH`.
53
+ - 0 checks passed and 0 failed.
54
+ - There were 0 `fix` events in 14 runs. The fix loop is gated on `failures_grouped` (machine.ts:54), which can only fill from a `fail`.
55
+ - **Verify was skipped in 5 of 14 runs.** Implement exited `spec_conflict` in jinja r1, werkzeug-3121 r1 and r2, and werkzeug-3271 r1 and r2.
56
+ - 4 of the 5 reasons cite the read-only rule for existing test files.
57
+ - 3121 r1 cites a Wall test that contradicts the plan.
58
+ - 9 verify stages completed, 5 did not start.
59
+ - **The implementer is never told which existing tests to run.**
60
+ - Implement reported `impacted_tests: []` in 9 of 14 runs. The 5 non-empty ones are faker x2 (`tests/test_proxy.py`, lean path) and 3 Wall-test-only lists.
61
+ - Root cause: `repomap.ts` extracts symbols only with a JS `export` regex (`SYMBOL_RE`, repomap.ts:23). Every Python repo gets `entries: []`. For example, jinja r2 `repomap.json` has 118 files and 0 entries.
62
+ - So `selectRelevantFiles` returns `[]` (`"relevant_files": []` in 8 of 8 plan stages).
63
+ - Then `impactedTests` (implement.ts:17) takes `[]` from `??` and never falls back to `namedFiles`.
64
+ - **Implement always ran on sonnet; raw ran on opus.**
65
+ - Every `session.started implement` has `"model": "claude-sonnet-5"`, because of the E-64 cascade (implement.ts:68, sizing.ts:63).
66
+ - Escalation to the run model happens only in a fix round with a test failure (fix.ts:60). That cannot happen while verify is blind.
67
+ - So on this harness the cascade is sonnet-only. This contributes to jinja, but is not proven as a cause: EV-14 v10 passed jinja 2/2.
68
+ - **Wall hit its 90s limit in 5 of 14 runs:** 3105 r1 and r2, 3121 r2, 3271 r2, click r2.
69
+ - Evidence: `stage.failed wall {"reason": "limit"}` and `session.ended wall exit=killed dur=90.0`.
70
+ - Wall sealed at least one test in only 3 of 14 runs (3121 r1, 3271 r1, jinja r2).
71
+ - The one jinja Wall test was written under `examples/basic/`. The implementer reports that it was defective: `test_recursive_loop_matches_bug_report` references an undefined `id`.
72
+
73
+ ## 4. Cost: where v10 spends that raw does not
74
+
75
+ Measured from `cost` events (`usd` non-null) and from raw `arm_stdout.log` usage:
76
+
77
+ | | usd | cache read tokens | cache write tokens | output tokens |
78
+ |---|---|---|---|---|
79
+ | raw, 14 runs | $5.09 | 4.79M | 0.29M | 89k |
80
+ | v10 implement (sonnet), 14 | $4.91 | 9.23M | 0.41M | 137k |
81
+ | v10 wall (sonnet), 8 measured + 4 unmeasured | $1.11 | 0.32M | 0.15M | 40k |
82
+ | v10 plan (opus), 8 | $0.90 | 0.30M | 0.06M | 16k |
83
+ | v10 intake (sonnet, lean path), 2 | $0.17 | 0.08M | 0.03M | 1k |
84
+ | **v10 total measured** | **$7.09** | 9.93M | 0.66M | 195k |
85
+
86
+ - **Correction to EV-15's lower bound.** Measured v10 spend is at least $7.09, over 9 completions, so cost per completed is at least **$0.788**, not $0.5788. EV-15 summed only the 10 costed rows. It dropped the measured plan and implement dollars inside the 4 null rows ($0.32, $0.59, $0.25, $0.72 before Wall). Raw is $0.5085, so v10 is at least 55% more per completed task.
87
+ - **Priority-2 gap, root cause.** All 4 `cost_usd: null` rows (3105 r1 and r2, 3121 r2, 3271 r2) are runs where Wall was killed at its limit.
88
+ - Evidence: `cost wall usd=None ... in=0 out=0`. Only `result-cost-*-impl.json` and `result-cost-*-plan.json` exist under `.loki/metrics/` (for example 3105 r1).
89
+ - A killed session never receives the SDK result message, so no cost file is written. `iteration-2.json` is Wall's efficiency record.
90
+ - **Overhead stages.** Plan, Wall and intake cost $2.18, which is 31% of v10's measured spend. Wall bought a sealed test in 3 of 14 runs.
91
+ - **Latency.** Implement waits for the whole `["plan", "wall"]` group. When Wall is killed at 90s beside a 15-31s plan, that adds about 60-75s before implement starts.
92
+ - **Implement burns 1.9x raw's cache reads** (9.23M vs 4.79M), on a cheaper model. Most of it is in the long runs:
93
+ - attrs r2: 286s, 2.49M cache read, $0.97.
94
+ - jinja r2: 360s, 2.34M, $0.94.
95
+ - werkzeug-3105 r2: 1.11M, $0.47.
96
+ - werkzeug-3271 r2: 239s, 0.94M, $0.63.
97
+ - The brief gives no test to run, so the session explores instead of converging.
98
+
99
+ Completed runs where v10 was slower or costlier than raw on the same task and run:
100
+ - attrs r2: $1.06 and 317s vs $0.28 and 60s. Implement ran 286s.
101
+ - click r2: 212s vs 49s. Wall was killed at 90s, then implement ran 121s.
102
+ - faker r2: 128s vs 227s, a v10 win on time.
103
+ - 3121 r2: 141s vs 29s. Wall was killed at 90s, then implement ended in `spec_conflict`.
104
+ - 3271 r2: 330s, a v10 win. Wall was killed at 90s, then implement ran 239s.
105
+
106
+ In every slow case the time went to Wall hitting its limit, or to a long implement session with no test to run.
107
+
108
+ ## 5. Root causes, ranked by lost completions explained
109
+
110
+ | rank | cause | lost completions explained | other effect |
111
+ |---|---|---|---|
112
+ | 1 | Verify runs pytest as bare `python`: not on PATH, and the task `.venv` is ignored (verify.ts:31) | 2 of 2 (r2 directly; r1 once cause 2 is fixed) | 27/27 checks `not_run`; 0 fix rounds; cascade escalation unreachable |
113
+ | 2 | `spec_conflict` early exit skips verify and fix (machine.ts:55), triggered by the "existing test files are read-only" rule (implement.ts:33) | 1 (jinja r1) | 5/14 runs unverified; 4 of the 5 caused by the read-only rule |
114
+ | 3 | Implementer is given no impacted tests: Python repomap has 0 entries (repomap.ts:23), and `[]` blocks the `namedFiles` fallback (implement.ts:17) | contributing to 2 (the implementer never ran `test_core_tags.py`) | 9/14 implement runs had no tests to run; long, cache-heavy sessions |
115
+ | 4 | Implement pinned to sonnet by the cascade, with escalation only through verify failures | contributing, unproven (EV-14 v10 passed jinja 2/2) | cheaper tokens, but 1.9x the cache reads |
116
+ | 5 | Wall 90s limit kills and low yield | 0 | all 4 null-cost rows; +60-75s latency; 3/14 useful |
117
+
118
+ ## 6. Fix slice cards
119
+
120
+ D33: the core is 4,942 lines against a 5,000 cap, so there are 58 lines of headroom. Card deltas below total +34 or fewer. IDs are E-98a to E-98f, to avoid clashing with an E-102 that exists on a local main.
121
+
122
+ Re-running the failed tasks uses `eval/loki10/run.sh` with a separate `--out` per run. There is no `--runs` flag, so use n=3 per task: EV-14 passed jinja 2/2, so n=2 cannot tell a fix from noise. Copy each run's `work/.loki` out before cleanup (E-101), with the output under `/Users/lokesh/loki-ci-logs/eval/e98-*`.
123
+
124
+ ### E-98a: verify uses the project interpreter
125
+ - Goal: pytest checks run on the repo's own environment, so a regression shows up as `fail` and drives a fix round.
126
+ - File set:
127
+ - `loki-ts/src/engine10/stages/verify.ts`: `runnerCmd` resolves `<repoDir>/.venv/bin/python`, then `<repoDir>/venv/bin/python`, then `$VIRTUAL_ENV/bin/python`, then `python3`, then `python`.
128
+ - The same file: each check records the interpreter it used. A check that ran on a system interpreter adds "tests ran on the system interpreter" to not_proven, because system `python3` imported the installed Jinja2 3.1.6, not `src/`, in jinja r2.
129
+ - `loki-ts/tests/engine10/verify*.test.ts`.
130
+ - Net core delta: at most +12.
131
+ - Wall check:
132
+ - Red first: a fixture with a `.venv/bin/python` shim and no `python` on PATH gives `not_run` before the change and `pass`/`fail` after. A second fixture with system python3 only records `interpreter: system` plus the not_proven line.
133
+ - Then `eval/loki10/run.sh --arm v10 --tasks pub-jinja-1413 --out /Users/lokesh/loki-ci-logs/eval/e98a-r{1,2,3}`.
134
+ - Expected: `test.result` for `pytest:tests/test_core_tags.py` is `pass` or `fail` (never `not_run`) in 3 of 3 runs, and completed in at least 2 of 3.
135
+ - Budget: 30 min. Tier: HIGH (verify).
136
+
137
+ ### E-98b: spec_conflict still verifies
138
+ - Goal: a `spec_conflict` implement exit still runs verify and the fix loop. Only `already_satisfied` short-circuits. The receipt keeps the `SPEC_CONFLICT` verdict and reason.
139
+ - File set: `loki-ts/src/engine10/machine.ts` (`earlyExit`, plus the verdict carry-through only if seal needs it), `loki-ts/tests/engine10/machine*.test.ts`. Net core delta: at most +3.
140
+ - Wall check:
141
+ - A fake-stage test: implement `spec_conflict`, then verify runs, then a `fail` triggers `fix`, then seal still says `SPEC_CONFLICT`. It must fail on current main.
142
+ - Then re-run `pub-jinja-1413`, `pub-werkzeug-3121` and `pub-werkzeug-3271` at n=3 into `EV/e98b-*`, with E-98a merged.
143
+ - Expected: every run with a `spec_conflict` exit has a `stage.completed verify`. Completions are at least EV-15's on these tasks (jinja 0/2, 3121 2/2, 3271 1/2).
144
+ - Budget: 30 min. Tier: HIGH (moat flow).
145
+
146
+ ### E-98c: brief allows adding tests; impacted tests fall back
147
+ - Goal: existing test files are append-only (add new test functions, never edit or delete existing ones). Wall files stay read-only and are restored as today; seal.ts:176 still reports any modification. `impactedTests` falls back to `namedFiles` when `relevant_files` is empty, not only when it is missing.
148
+ - File set: `loki-ts/src/engine10/stages/implement.ts` (the brief line at :33, and `impactedTests` at :17 using `?.length ?` in place of `??`), plus its test. Net core delta: at most +2.
149
+ - Wall check:
150
+ - A unit test: a brief with `relevant_files: []` and a task naming `parser.py` lists that file's tests.
151
+ - Re-run `pub-werkzeug-3121` and `pub-werkzeug-3271` at n=3 into `EV/e98c-*`.
152
+ - Expected: no run exits `spec_conflict` citing read-only existing tests (4 of 14 did in EV-15), and completions do not drop.
153
+ - Budget: 15 min. Tier: MEDIUM.
154
+
155
+ ### E-98d: Python symbols in the repo map
156
+ - Goal: `buildRepoMap` extracts Python top-level `def` and `class` names, alongside the JS `export` regex, so `selectRelevantFiles` and the impacted-test map work on Python repos.
157
+ - File set: `loki-ts/src/engine10/repomap.ts`, `loki-ts/tests/engine10/repomap*.test.ts`. Net core delta: at most +4 (a second regex applied to `.py`).
158
+ - Wall check:
159
+ - Offline, no model: on each of the 7 medium task repos at their `repo_ref`, `relevant_files` is non-empty and contains the file the upstream refdiff touches (`eval/loki10/refdiff/`). At least 5 of 7 must pass. EV-15 had 0 of 7, 8 of 8 plan stages empty.
160
+ - Keyword ties across a package directory are a known ceiling. Record the rank of the upstream file.
161
+ - Budget: 30 min. Tier: MEDIUM.
162
+
163
+ ### E-98e: killed sessions still report cost
164
+ - Goal: a session killed at its stage limit writes a cost record from the per-message usage already streamed, marked `source: "partial-stream"`, so the harness row is never `cost_usd: null` because Wall was killed.
165
+ - File set: `loki-ts/src/engine10/session.ts`, `loki-ts/src/engine10/cost.ts`, and a test. Net core delta: at most +10, or offset by deleting dead code in cost.ts.
166
+ - Wall check:
167
+ - A unit test: a fake stream killed after 2 assistant messages gives a non-null usd equal to the summed usage price.
168
+ - Re-run `pub-werkzeug-3105`, `pub-werkzeug-3121` and `pub-werkzeug-3271` at n=3 into `EV/e98e-*`.
169
+ - Expected: `cost_usd` is non-null on every row, and `eval/loki10/summarize` reports a numeric `cost_per_completed`.
170
+ - Budget: 30 min. Tier: MEDIUM.
171
+
172
+ ### E-98f: A/B of Wall and cascade on medium (eval-first, then a sizing change)
173
+ - Goal: measure whether Wall (`LOKI_E10_WALL=0`) and the sonnet cascade (`LOKI_E10_CASCADE=0`) pay for themselves on medium, with E-98a to E-98c merged. Only if a knob wins on completions without losing on cost, change `sizing.ts` so that `size: "normal"` takes that path by default.
174
+ - File set: an eval run only, then `loki-ts/src/engine10/sizing.ts` (at most +3 core lines) and its test.
175
+ - Wall check:
176
+ - All 7 medium tasks at n=3 per arm: default, `LOKI_E10_WALL=0`, `LOKI_E10_CASCADE=0`, into `EV/e98f-{default,nowall,nocascade}-r{1,2,3}`.
177
+ - The chosen default must be at or above raw's EV-15 10/14 rate (71.4%) on completions, and below raw's $0.5085 on cost per completed.
178
+ - The results are published in this file as the "after" table.
179
+ - Budget: 60 min of eval, then a 15 min code change. Tier: HIGH (it changes the default flow).
180
+
181
+ Order: a, b, c, d and e in parallel (their file sets do not overlap), then f. The "after" table for the founder is the E-98f default arm next to section 1 above.