loki-mode 11.74.2 → 11.75.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 (166) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +2 -3
  3. package/VERSION +1 -1
  4. package/autonomy/completion-council.sh +10 -10
  5. package/autonomy/council-v2.sh +4 -4
  6. package/autonomy/grill.sh +1 -1
  7. package/autonomy/lib/browser-open.sh +1 -1
  8. package/autonomy/lib/chat.sh +1 -1
  9. package/autonomy/lib/cockpit-render.sh +1 -1
  10. package/autonomy/lib/done-recognition.sh +4 -4
  11. package/autonomy/lib/efficiency_cost.py +1 -1
  12. package/autonomy/lib/engine10-push.sh +2 -2
  13. package/autonomy/lib/prd-enrich.sh +1 -1
  14. package/autonomy/lib/proof-check.sh +1 -1
  15. package/autonomy/lib/proof-generator.py +3 -3
  16. package/autonomy/lib/proof-pr.sh +1 -1
  17. package/autonomy/lib/skill-link-heal.sh +1 -1
  18. package/autonomy/lib/voter-agents.sh +1 -1
  19. package/autonomy/loki +26 -37
  20. package/autonomy/prd-checklist.sh +1 -1
  21. package/autonomy/receipt_jwt.py +1 -1
  22. package/autonomy/run.sh +28 -28
  23. package/autonomy/trigger-schedule.py +6 -414
  24. package/autonomy/tui.sh +1 -1
  25. package/autonomy/verify.sh +4 -4
  26. package/completions/loki.bash +0 -5
  27. package/dashboard/__init__.py +1 -1
  28. package/docs/ARCHITECTURE.md +1 -2
  29. package/docs/CLI-REFERENCE.md +1 -1
  30. package/docs/COMPONENTS.md +1 -1
  31. package/docs/INSTALLATION.md +1 -1
  32. package/docs/ROUTING-EVIDENCE.md +1 -2
  33. package/docs/V10-RESEARCH.md +1 -1
  34. package/docs/dev/architecture-reference.md +3 -7
  35. package/docs/dev/project-structure.md +1 -4
  36. package/docs/dev/release-checklist.md +13 -31
  37. package/docs/research-2026-07/OBSERVABILITY-TOOL-SPEC.md +1 -1
  38. package/docs/v11/MARKET-SLICES.md +1 -1
  39. package/docs/v11/REGISTRIES.md +1 -1
  40. package/docs/v11/ROUTER-1.md +2 -2
  41. package/loki-ts/dist/loki.js +2 -2
  42. package/mcp/__init__.py +1 -1
  43. package/package.json +2 -2
  44. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  45. package/skills/extending.md +2 -3
  46. package/skills/factory-operations.md +11 -18
  47. package/skills/release-cadence.md +2 -2
  48. package/web-app/dist/assets/{AdminPage-jkjilfbl.js → AdminPage-xKgtIhk2.js} +1 -1
  49. package/web-app/dist/assets/{Avatar-bd5JWkSJ.js → Avatar-Q14AHox9.js} +1 -1
  50. package/web-app/dist/assets/{Badge-DVRit2Xw.js → Badge-yk5M-lip.js} +1 -1
  51. package/web-app/dist/assets/{Button-BNAB-pVZ.js → Button-ynznk0At.js} +1 -1
  52. package/web-app/dist/assets/{CockpitPage-DpG29h_w.js → CockpitPage-C8B765za.js} +1 -1
  53. package/web-app/dist/assets/{ComparePage-Dasg5V41.js → ComparePage-DqzmWKnf.js} +1 -1
  54. package/web-app/dist/assets/{ErrorBoundary-DJojse6b.js → ErrorBoundary-DdBPd_Lq.js} +1 -1
  55. package/web-app/dist/assets/{EvidenceReceiptPanel-Blxw7_u1.js → EvidenceReceiptPanel-jb4Tp38b.js} +1 -1
  56. package/web-app/dist/assets/{GitHubIssuesPanel-BBvSFj80.js → GitHubIssuesPanel-xJQiLcxs.js} +1 -1
  57. package/web-app/dist/assets/{GitHubPRsPanel-BCIKeSBg.js → GitHubPRsPanel-84W3Dhk_.js} +1 -1
  58. package/web-app/dist/assets/{HomePage-C7d__oNG.js → HomePage-St1Xl2tu.js} +2 -2
  59. package/web-app/dist/assets/{LoginPage-BXljL3yY.js → LoginPage-jRt0NUHb.js} +1 -1
  60. package/web-app/dist/assets/{MagicPage-Xjkts_yE.js → MagicPage-CQLFe7LR.js} +1 -1
  61. package/web-app/dist/assets/{MetricsPage-kQvVp-j2.js → MetricsPage-zzX9eTC5.js} +1 -1
  62. package/web-app/dist/assets/{NotFoundPage-D-4ZlEaO.js → NotFoundPage-DDu023SY.js} +1 -1
  63. package/web-app/dist/assets/{ProjectPage-DfzR5RXP.js → ProjectPage-D60UURaH.js} +3 -3
  64. package/web-app/dist/assets/{ProjectsPage-DFDsWzkV.js → ProjectsPage-DqVsKxlt.js} +1 -1
  65. package/web-app/dist/assets/{SettingsPage-CLPIoYT3.js → SettingsPage-G7pPKvo0.js} +1 -1
  66. package/web-app/dist/assets/{ShowcasePage-PZKkyGeY.js → ShowcasePage-CrU_aKgS.js} +1 -1
  67. package/web-app/dist/assets/{SystemSettingsPage-BsBlcnzo.js → SystemSettingsPage-ClKGQFsB.js} +1 -1
  68. package/web-app/dist/assets/{TeamsPage-BSjgNhoU.js → TeamsPage-B530vSNe.js} +1 -1
  69. package/web-app/dist/assets/{TemplatesPage-W2KeAzbg.js → TemplatesPage-COmv_Cqd.js} +1 -1
  70. package/web-app/dist/assets/{TerminalOutput-BjroTiCC.js → TerminalOutput-CufG9YzF.js} +1 -1
  71. package/web-app/dist/assets/{activity-BXZ5YYes.js → activity-Ct1Updr6.js} +1 -1
  72. package/web-app/dist/assets/{bell-D1urp5pa.js → bell-rcvhQuGr.js} +1 -1
  73. package/web-app/dist/assets/{bot-Chedf2bF.js → bot-DzeqEI-b.js} +1 -1
  74. package/web-app/dist/assets/{check-DhaCuOCV.js → check-zacnZHyC.js} +1 -1
  75. package/web-app/dist/assets/{chevron-left-D7BpQyA6.js → chevron-left-Lxnkl8Qg.js} +1 -1
  76. package/web-app/dist/assets/{circle-alert-DnGvQ_AQ.js → circle-alert-DoqSdQdB.js} +1 -1
  77. package/web-app/dist/assets/{clock-CqfxWhHM.js → clock-B7bJcVIC.js} +1 -1
  78. package/web-app/dist/assets/{cloud-BKxp5AWB.js → cloud-DdA9Bu6q.js} +1 -1
  79. package/web-app/dist/assets/{code-xml-BDQ6GBtt.js → code-xml-CAZEZ9T8.js} +1 -1
  80. package/web-app/dist/assets/{database-BmpEx1y_.js → database-Da2GkEIN.js} +1 -1
  81. package/web-app/dist/assets/{dollar-sign-DYNY9R_C.js → dollar-sign-DjDiG-37.js} +1 -1
  82. package/web-app/dist/assets/{file-code-corner-BJi0IBFd.js → file-code-corner-CSL-Jij-.js} +1 -1
  83. package/web-app/dist/assets/{file-plus-Dqyb2bcQ.js → file-plus-02DRA8pV.js} +1 -1
  84. package/web-app/dist/assets/{globe-DPh4RWfM.js → globe-CGyB90kK.js} +1 -1
  85. package/web-app/dist/assets/{hammer-B3xnuoA1.js → hammer-BaQB96TG.js} +1 -1
  86. package/web-app/dist/assets/{index-BpX8DcTr.js → index-lcoI1_Kk.js} +3 -3
  87. package/web-app/dist/assets/{layers-BRCmyCW8.js → layers-BWJBvoeg.js} +1 -1
  88. package/web-app/dist/assets/{loader-circle-n07Pky0M.js → loader-circle-CdcI0FeS.js} +1 -1
  89. package/web-app/dist/assets/{lock-BWqOuQmS.js → lock-BBkw5NJx.js} +1 -1
  90. package/web-app/dist/assets/{package-BJlB_Z-Z.js → package-BpPRO3LM.js} +1 -1
  91. package/web-app/dist/assets/{plus-oH17BZu2.js → plus-D7XbyK29.js} +1 -1
  92. package/web-app/dist/assets/{refresh-cw-CPQ476LL.js → refresh-cw-DLG3hyAi.js} +1 -1
  93. package/web-app/dist/assets/{rotate-ccw-7hLvOcnS.js → rotate-ccw-Bqau4R_S.js} +1 -1
  94. package/web-app/dist/assets/{scroll-text-BCmLauQn.js → scroll-text-BtIL3cNk.js} +1 -1
  95. package/web-app/dist/assets/{server-DfTfvW84.js → server-tZCmZ4yH.js} +1 -1
  96. package/web-app/dist/assets/{shield-alert-CaeGRq19.js → shield-alert-K5JXzFKg.js} +1 -1
  97. package/web-app/dist/assets/{thumbs-up-Dz-l2GPC.js → thumbs-up-CHCVyJdw.js} +1 -1
  98. package/web-app/dist/assets/{trash-2-B-OsDmSo.js → trash-2-DncNxVq0.js} +1 -1
  99. package/web-app/dist/assets/{trending-down-CXTFOxzq.js → trending-down-D8Bp0azX.js} +1 -1
  100. package/web-app/dist/assets/{trending-up-FQEdqr3v.js → trending-up-AixETdKR.js} +1 -1
  101. package/web-app/dist/assets/{upload-CacWSNTg.js → upload-VCbjFn2H.js} +1 -1
  102. package/web-app/dist/assets/{usePolling-cIjZ9qd2.js → usePolling-CQvKD2Jj.js} +1 -1
  103. package/web-app/dist/assets/{user-DAouWFHi.js → user-SK-YguQ6.js} +1 -1
  104. package/web-app/dist/index.html +1 -1
  105. package/autonomy/company-seats.json +0 -82
  106. package/docs/COMPETITIVE-INTEL-2026-09.md +0 -444
  107. package/docs/FOUNDER-DECISIONS-TRUST-SEMANTICS-2026-08-01.md +0 -145
  108. package/docs/FOUNDER-STATUS-AND-DECISIONS-2026-07-01.md +0 -132
  109. package/docs/LOKI-10-BUILD-PROMPT.md +0 -350
  110. package/docs/STRATEGY-2026-2028.md +0 -124
  111. package/docs/V10-VISION.md +0 -161
  112. package/docs/v10/ADOPTION-PLAN.md +0 -375
  113. package/docs/v10/ARCHITECT-CUTS.md +0 -744
  114. package/docs/v10/BACKLOG.md +0 -231
  115. package/docs/v10/BOARD.md +0 -1403
  116. package/docs/v10/CONTROL-PLANE.md +0 -120
  117. package/docs/v10/CONTROL.md +0 -36
  118. package/docs/v10/CP-ASK-PLAN.md +0 -85
  119. package/docs/v10/CP-ENTERPRISE-UI.md +0 -537
  120. package/docs/v10/D51-PHASE-B.md +0 -120
  121. package/docs/v10/D61-SPEED.md +0 -105
  122. package/docs/v10/D63-CARDS.md +0 -354
  123. package/docs/v10/DECISIONS.md +0 -915
  124. package/docs/v10/E2E-D65.md +0 -123
  125. package/docs/v10/ENGINE-LAWS.md +0 -163
  126. package/docs/v10/ENGINE-MEASURE.md +0 -69
  127. package/docs/v10/ENGINE.md +0 -743
  128. package/docs/v10/FAILURE-CLASSES.md +0 -2026
  129. package/docs/v10/FC21B-FC22-PLAN.md +0 -107
  130. package/docs/v10/FIRST-RUN-GATE.md +0 -39
  131. package/docs/v10/FOUNDER-QUEUE.md +0 -29
  132. package/docs/v10/GAP-RESEARCH-1003.md +0 -32
  133. package/docs/v10/GUARDS.md +0 -883
  134. package/docs/v10/L0-WAVE1.md +0 -81
  135. package/docs/v10/LEGACY-REMOVAL.md +0 -408
  136. package/docs/v10/MEDIUM-ANALYSIS.md +0 -346
  137. package/docs/v10/METRICS.md +0 -645
  138. package/docs/v10/MODERNIZE.md +0 -437
  139. package/docs/v10/OPENCODE-PARITY-PLAN.md +0 -84
  140. package/docs/v10/OPERATING-MODEL.md +0 -60
  141. package/docs/v10/PLAN-V12.md +0 -896
  142. package/docs/v10/PROGRESS.md +0 -2735
  143. package/docs/v10/RELEASE-11.md +0 -77
  144. package/docs/v10/RETRO-2026.md +0 -650
  145. package/docs/v10/ROADMAP-D63.md +0 -35
  146. package/docs/v10/SCALE.md +0 -140
  147. package/docs/v10/SCORECARD-PLAN.md +0 -250
  148. package/docs/v10/SWARM-PROMPT.md +0 -98
  149. package/docs/v10/SWARM.md +0 -293
  150. package/docs/v10/cp-redesign/PARITY.md +0 -188
  151. package/docs/v10/cp-redesign/legacy/INDEX.md +0 -1167
  152. package/docs/v10/roadmap-10/01-measurement.md +0 -113
  153. package/docs/v10/roadmap-10/02-cost.md +0 -75
  154. package/docs/v10/roadmap-10/03-speed.md +0 -65
  155. package/docs/v10/roadmap-10/04-first-run.md +0 -61
  156. package/docs/v10/roadmap-10/05-deploy.md +0 -61
  157. package/docs/v10/roadmap-10/06-stability.md +0 -64
  158. package/docs/v10/roadmap-10/07-quality.md +0 -57
  159. package/docs/v10/roadmap-10/08-proof.md +0 -48
  160. package/docs/v10/roadmap-10/09-safety.md +0 -74
  161. package/docs/v10/roadmap-10/README.md +0 -1464
  162. package/skills/sdlc-fleet.md +0 -170
  163. package/tools/cockpit/SPEC.md +0 -275
  164. package/tools/cockpit/index.html +0 -146
  165. package/tools/cockpit/roi-basis.json +0 -33
  166. package/tools/cockpit/server.py +0 -946
@@ -1,743 +0,0 @@
1
- # Loki 10 engine (ENGINE.md)
2
-
3
- Status: design of record for CEO directive D29 (docs/v10/DECISIONS.md D29). Cut at 2026-09-27T21:50Z. The engine is additive: it runs only when `LOKI_ENGINE=v10` is set. When the variable is unset, the routing of `bin/loki`, `autonomy/loki`, `autonomy/run.sh` and every existing loki-ts command stays byte-for-byte the same.
4
-
5
- ## 1. Goal and release gate
6
-
7
- Users report that Loki does not finish tasks. augmentiq #52 ("add a search bar") ran 73.7+ minutes and completed 0 tasks. The Loki 10 engine replaces the RARV loop with one explicit state machine that aims for a pull request in about 5 minutes.
8
-
9
- Release gate, from D29, published in full including misses:
10
- - at least 25 tasks with hidden tests;
11
- - v10 completion at or above raw `claude -p` at the same model and budget;
12
- - p50 time to PR of 5 minutes or less, and p90 of 10 minutes or less;
13
- - cost per completed task at or below raw Claude Code.
14
-
15
- Deadline: if the gate is not met by 03:00 UTC, v10.0.0 ships with legacy still the default, v10 opt-in, and the measured gap stated plainly.
16
-
17
- ## 2. Measured stage times
18
-
19
- Source: docs/v10/ENGINE-MEASURE.md, a read-only measurement of four real runs taken from their own logs.
20
-
21
- ### Where the minutes go (minutes, logged durations only)
22
-
23
- | Stage | R1 augmentiq #52 | R2 anonima | R3 lokimode | R4 fizzbuzz |
24
- |---|---|---|---|---|
25
- | Boot, intake, spec interrogation, PRD parsing | 1.3 | 0.5 | 0.6 | 0.3 |
26
- | Agent provider calls | 3.9 (iterations 1-2) + 57.7+ (iteration 3, still running) | 3.9 | 5.4+ (cut off) | 0.6 |
27
- | Of which: agent running the full E2E suite inside iteration 3 | about 41 (17:05-17:46 EDT, inferred from log file times) | not measured | not measured | not measured |
28
- | App runner / docker | 1.8 | 0 | 0 | 0 |
29
- | Gates (static through LSP) plus unlabelled gaps | 2.7 | 0.1 | 0 | 0 |
30
- | Code review | 0.6 | 4.4 | 0 | 0.8 |
31
- | Doc generation | 5.0 (timed out at 300s) | 4.3 | 0 | 0 |
32
- | Checklist, evidence gate, council | 0.6 (council never voted) | 7.2 | 0 | 1.8 |
33
- | Total wall time | 73.7+ | 20.5 | 6.0+ | 3.8 |
34
-
35
- Agent share of wall time where the run finished: R2 19% (234s of 1231s), R4 15% (35s of 228s). The rest of the time goes to harness stages around the agent.
36
-
37
- ### Five proven causes of non-completion (R1)
38
-
39
- 1. The app runner's docker call fails ("docker: unknown command: docker compose", then "unknown shorthand flag: 'd' in -d") while the containers report healthy. The evidence gate therefore records app_boot_failed (metrics/trust-events.jsonl 20:45:21Z; app-runner/state.json crash_count 5).
40
- 2. A secret-leak match in the changed file SETUP.md blocks completion ("Evidence gate BLOCKED: a secret/credential was detected in the changed files").
41
- 3. The test gate finds no test runner ("no test runner detected, recording inconclusive"; tests_ok=inconclusive runner=none), while the agent's own runs show pytest 2847 passed and vitest 1552 passed.
42
- 4. Code review refuses a 431361-byte context (committed USAGE.md, TESTING.md, SETUP.md). Completion is then rejected "because code review is BLOCKED (Critical/High findings)", although no review ran.
43
- 5. Iteration 3 is one provider call with no time limit and no progress events. The last events.jsonl entry is 20:48:28Z iteration_start 3, and dashboard-state.json still shows iteration 0 and council total_votes 0 at 21:45:53Z. Inside that call the agent drifted into the unrelated full E2E suite at 94-100% CPU and killed processes with `pkill -f` and `kill -9`.
44
-
45
- Also: the feature already existed before the run. Iterations 1 and 2 correctly said so, and the gates rejected both claims.
46
-
47
- ### Where each finding is handled in the machine
48
-
49
- | Finding | Stage that handles it | Mechanism |
50
- |---|---|---|
51
- | Feature already existed; correct "done" claims were rejected, then the run looped | Intake, Wall, Implement, Fast verify | Intake runs deterministic checks only (issue closed, or a merged PR already closes it) and exits with a sealed ALREADY_SATISFIED receipt. Wave 2: Wall tests run on the base tree before Implement; if they are green, the run seals ALREADY_SATISFIED without an implement session. Wave 1: the implementer can print `LOKI_ALREADY_DONE: <evidence>`. An empty diff plus green impacted tests gives a sealed ALREADY_SATISFIED receipt, no PR, and no second session. An empty diff without that marker is FAILED. Never a loop. |
52
- | Cause 1: app runner / docker | Deep verify only | No app boot on the fast path. If deep verify cannot boot the app, it posts the log and turns the `loki/deep-verify` check red. It never withholds the PR. |
53
- | Cause 2: secret match in a generated doc | Implement brief; Deep verify | The brief forbids writing docs the task did not ask for. `autonomy/lib/secret-scan.sh` runs on changed files in deep verify. A match is a real red check with file:line, reported where the user sees it. |
54
- | Cause 3: runner=none while pytest and vitest pass | Intake (test map) | `testmap.ts` detects pytest, vitest, jest, npm/bun scripts, go and cargo from real config files. A fixture test covers a mixed pytest+vitest repo. |
55
- | Cause 4: refused review counted as blocking | Deep verify | No review or council on the fast path. The council context leaves out generated docs. A refused or oversized check is recorded as NOT PROVEN, never as a finding. |
56
- | Cause 5: silent 57-minute call, full-suite drift, process kills | Implement (session wrapper) | One provider session per process group. The stage limit kills the whole group. A heartbeat event every 60s reports diff progress. The brief forbids full-suite runs and process kills. For claude, the host guard (`autonomy/hooks/validate-bash.sh:91-93`) blocks `kill`, `pkill` and `killall`. |
57
- | Agent was 19% of wall time (R2) | Whole machine | No PRD, spec interrogation, doc generation, council or app runner before the PR. |
58
-
59
- ## 3. Module layout
60
-
61
- New code lives in `loki-ts/src/engine10/`. Total size stays under 5,000 lines of TypeScript, enforced by `loki-ts/tests/engine10/budget.test.ts`.
62
-
63
- ```
64
- loki-ts/src/engine10/
65
- types.ts Stage, StageResult, RunContext, Verdict, RunOptions
66
- events.ts event schema, append, fold, tail
67
- machine.ts stage table, run loop, resume, budgets, global cap, optional() loader
68
- supervisor.ts process topology, credentials, .loki/engine.json marker, pr + deep spawn
69
- worker.ts token-withheld process that runs intake..seal
70
- session.ts one provider session in its own process group; heartbeat; cost harvest
71
- cost.ts provider cost to cost event + .loki/metrics/efficiency/iteration-N.json
72
- fetch_issue.ts credentialed, deterministic issue fetch via autonomy/issue-providers.sh
73
- repomap.ts file list + top-level symbols, size-capped
74
- testmap.ts runner detection + source-to-test map
75
- output.ts live stage lines, heartbeat lines, 5-line summary
76
- cli.ts engine10 subcommand router
77
- stages/intake.ts stages/plan.ts stages/wall.ts stages/implement.ts
78
- stages/verify.ts stages/fix.ts stages/seal.ts stages/pr.ts stages/deep.ts
79
- failures.ts groups test failures into reasons for fix rounds
80
- cache.ts per-repo cache keyed by tree hash
81
- pr_body.ts honest PR body (verdict, NOT PROVEN, stage times, draft reason)
82
- eta.ts ETA from stage targets and cached history
83
- status.ts `loki status`
84
- verify_cmd.ts `loki verify`
85
- escalate.ts --deep and logged auto-escalation
86
- dashboard/server.ts dashboard/page.ts (HTML inlined as a string so dist bundles it)
87
- adapters/types.ts adapters/index.ts adapters/github.ts adapters/gitlab.ts
88
- adapters/jira.ts adapters/slack.ts
89
- autonomy/lib/engine10-push.sh credentialed push, PR, comment, status (GitHub)
90
- autonomy/lib/engine10-push-gitlab.sh credentialed push + MR (GitLab), wave 3
91
- ```
92
-
93
- **Seams fixed in wave 1 so later waves only add files.**
94
- - `machine.ts` owns the stage table and a helper `optional(path)`. The helper dynamically imports an optional stage or module (plan, wall, fix, cache, eta, pr_body, deep, escalate, adapters). When the file is absent, the helper returns null and the machine emits `stage.skipped` with `data.reason: "module not present"`.
95
- - `cli.ts` owns the router and dispatches hidden subcommands to optional modules the same way.
96
-
97
- This is what keeps every slice's file set disjoint.
98
-
99
- **Stage interface (types.ts):**
100
-
101
- ```ts
102
- export type StageName = "intake"|"plan"|"wall"|"implement"|"verify"|"fix"|"seal"|"pr"|"deep";
103
- export type Verdict = "VERIFIED"|"PARTIAL"|"ALREADY_SATISFIED"|"SPEC_CONFLICT"|"FAILED";
104
- export interface RunContext {
105
- runId: string; repoDir: string; runDir: string; baseSha: string; branch: string;
106
- provider: ProviderName; deep: boolean; deadlineMs: number;
107
- emit(type: string, stage: StageName|null, data: Record<string, unknown>): void;
108
- signal: AbortSignal; // aborted at the stage limit or the global cap
109
- prior: FoldedRun; // folded events (outputs of completed stages)
110
- }
111
- export interface Stage {
112
- name: StageName; targetS: number; limitS: number;
113
- run(ctx: RunContext): Promise<Record<string, unknown>>; // becomes stage.completed.data
114
- }
115
- ```
116
-
117
- ## 4. State machine
118
-
119
- ```
120
- Intake (15s) -> [Plan || Wall] (45s) -> Implement (3 min) -> Fast verify (60s)
121
- -> [Fix -> Fast verify] x at most 2 -> commit -> Seal (15s) -> PR (15s)
122
- -> Deep verify (async, detached)
123
- Global hard cap: 15 min. The cap fires at 14:00 so Seal + draft PR land by 15:00.
124
- ```
125
-
126
- Targets drive the ETA. Limits are hard kills of the stage (the whole process group for provider sessions).
127
-
128
- | Stage | Process | Target | Limit | Output (stage.completed.data) |
129
- |---|---|---|---|---|
130
- | intake | worker | 15s | 60s | task_sha256, source, base_sha, tree, branch, repomap_ref, testmap {runners, commands}, already_satisfied? |
131
- | plan | worker | 45s | 90s | plan (10 lines or fewer, truncated by the engine), relevant_files |
132
- | wall | worker | 45s | 90s | files [{path, sha256}], base_run {pass, fail} |
133
- | implement | worker | 180s | 480s (1800s with --deep) | exit: done / already_done / spec_conflict / killed, diff_stat, tests_reverted[] |
134
- | verify | worker | 60s | 120s | checks [{name, cmd, result, duration_s}], failures_grouped[], flaky[] |
135
- | fix | worker | 90s each | 180s each, at most 2 | round, groups_fed, diff_stat |
136
- | seal | worker | 15s | 60s | receipt_path, receipt_sha256, signed (bool), kid, verdict, not_proven[] |
137
- | pr | supervisor (credentialed child) | 15s | 60s | pr_url, draft (bool), existing (bool) |
138
- | deep | detached deep supervisor + token-less deep worker | async | 45 min | checks[], addendum_sha256, status_state |
139
-
140
- **Intake (no PRD, no LLM):**
141
- 1. Reject a dirty tracked tree with a one-line message.
142
- 2. Record `base_sha` and `git rev-parse HEAD^{tree}`.
143
- 3. Create branch `loki/<run-id>`.
144
- 4. Append `.loki/` to `.git/info/exclude`. This is not .gitignore, so it adds no diff.
145
- 5. Load the task: the literal task text, or the issue JSON the supervisor's fetch child wrote to `<runDir>/issue.json`.
146
- 6. For an issue, deterministic already-done checks: state closed, or `closedByPullRequestsReferences` contains a merged PR. Either one leads to Seal with verdict ALREADY_SATISFIED.
147
- 7. Build the repo map and test map, or read them from the cache by tree hash when `cache.ts` is present.
148
-
149
- **Plan + Wall (parallel, `Promise.all`):**
150
- - **Planner:** a fast-tier session that sees the task, the repo map and up to 8 relevant files, chosen by keyword overlap between the task and repo map paths and symbols. It writes at most 10 lines.
151
- - **Wall author:** a separate session whose cwd is a fresh temp dir holding only `task.md` and `repomap.txt`. It never sees the repo, which enforces "never the code" physically. It writes behavioral acceptance tests named `loki_wall_*` in the repo's detected test framework.
152
- - The engine copies the Wall tests into the repo test dir, hashes each file (sha256), emits `wall.sealed` before Implement, and keeps a sealed copy in `<runDir>/wall/`.
153
- - The engine then runs the Wall tests on the base tree. If they all pass, the run seals ALREADY_SATISFIED.
154
- - **Wall holdout (on by default):** when the Wall has 5 or more checks, a deterministic 20% subset (at least 1) is kept outside the repo and runDir, never shown to the implementer, and copied in only at Fast verify as blocking `holdout:N` checks. A held-out failure blocks the Seal (NOT PROVEN naming the holdout check). It reaches the fix stage only as an opaque count (`holdout_failed`), never as a name, command or failure text. Opt out with `LOKI_WALL_HOLDOUT=0` (or `LOKI_WALL_HOLDOUT_RATIO=0`); `LOKI_WALL_HOLDOUT_RATIO=0.4` holds out about 40%, capped at 0.9. An unparseable ratio falls back to 0.2, never to off.
155
-
156
- **Implement:** exactly ONE provider session through the existing loki-ts invoker (`resolveProvider(provider).invoke({mainLoop: true, tier: "development", cwd: repoDir, ...})`), wrapped by `session.ts`.
157
-
158
- The implementer brief (in `stages/implement.ts`) says:
159
- - the task text is quoted untrusted data;
160
- - follow the plan, if one exists;
161
- - the Wall and existing test files are read-only;
162
- - run only these impacted tests: `<list>`;
163
- - never run the full suite, E2E suites or long-lived servers;
164
- - never kill processes;
165
- - write no documentation unless the task asks;
166
- - do not commit or push;
167
- - finish with one of: `LOKI_DONE`, `LOKI_ALREADY_DONE: <file:line evidence>`, or `LOKI_SPEC_CONFLICT: <reason>`.
168
-
169
- After the session:
170
- - the engine diffs against `base_sha`, excluding `.loki/`;
171
- - any modified or deleted pre-existing test file is restored from base and listed in `tests_reverted`;
172
- - any Wall file whose sha256 no longer matches is restored from `<runDir>/wall/` and listed.
173
-
174
- A spec conflict leads to Seal with verdict SPEC_CONFLICT: no PR and no push: the branch stays local and its location is printed.
175
-
176
- **Fast verify:**
177
- - Changed files: impacted tests from the test map, plus changed test files, plus Wall tests, plus lint/typecheck of the changed files only (eslint/tsc for TS/JS, ruff or flake8 for Python, `bash -n`/shellcheck for shell).
178
- - When the target is the loki-mode repo itself (`scripts/select-tests.sh` exists at the repo root), the engine also runs `scripts/select-tests.sh --files - --run` with the changed files on stdin. For every other target, the test map does the selection.
179
- - A tool that is not installed yields a NOT PROVEN entry, never a failure.
180
- - A failing test is rerun once. If it passes on the rerun, it is recorded as flaky: a NOT PROVEN entry, not a blocker.
181
- - Failures are grouped by `failures.ts` into at most 5 normalized reasons.
182
-
183
- **Fix rounds:** at most 2. Each round is a new session (same brief rules) given the grouped reasons, the plan and the diff stat, followed by Fast verify again.
184
-
185
- **Commit:** the worker runs `git add -A` excluding `.loki/` and commits `loki: <title>` with a `Loki-Run: <run-id>` trailer. No token is needed.
186
-
187
- **Seal:** see section 9.
188
-
189
- **PR:** runs in the supervisor, through the credentialed push child (section 7).
190
- - DRAFT when the verdict is not VERIFIED, or when the cap fired.
191
- - After the PR opens, the supervisor sets commit status `loki/deep-verify=pending`.
192
-
193
- **Deep verify:** detached. It runs:
194
- - the full suite;
195
- - app boot (via `project_graph.ts discoverProjectGraph`);
196
- - the council (`loki-ts/src/council/voter_agents.ts:297 dispatchClaudeAgents`, claude only, with the diff minus generated docs);
197
- - the security scan (`autonomy/lib/secret-scan.sh` on changed files).
198
-
199
- It then appends a PR comment and a signed receipt addendum, and sets `loki/deep-verify` to success or failure. A refused or unavailable check is NOT PROVEN, never red.
200
-
201
- **Hard cap:**
202
- - At 14:00 elapsed, the machine aborts the running stage (process-group kill), commits whatever diff exists, seals with verdict PARTIAL and the missing checks as NOT PROVEN, and keeps the branch local (only VERIFIED pushes).
203
- - The cap is 900s by default. `LOKI_E10_CAP_S` exists for tests only.
204
- - `--deep` or auto-escalation raises it to 45 minutes and logs an `escalated` event (section 13).
205
-
206
- **Resume:** `loki --resume <run-id>`.
207
- - `events.ts fold()` gives the last `stage.completed`. The run restarts at the first stage that is not completed, and Implement restarts as a new session on the current tree.
208
- - If Seal completed but `pr.opened` is missing, only the PR step runs. That step uses check-before-create, so it never opens a second PR.
209
- - A `run.completed` event makes the run final.
210
-
211
- ## 5. Event log (the single source of truth)
212
-
213
- **Location and writers:**
214
- - Path: `<repo>/.loki/runs/<run-id>/events.jsonl`, append-only.
215
- - Single writer: the supervisor. The worker and deep worker send events as JSON lines on their stdout; the supervisor validates them, stamps `seq`, and appends.
216
- - The CLI, `loki status`, the dashboard and the receipt all read this file. The engine keeps no other state file.
217
-
218
- **Derived artifacts, not state:** `receipt.json`, `receipt.md`, `wall/`, session logs, and the eval pointer `.loki/engine.json`. Legacy side files written by reused invokers (for example `.loki/events.jsonl` and `agents.json` from `consumeSdkStream`) are never read by the engine.
219
-
220
- **Line format:**
221
-
222
- ```json
223
- {"v":1,"seq":7,"ts":"2026-09-27T22:01:03.120Z","run":"e10-20260927T220103Z-ab12","type":"stage.completed","stage":"intake","data":{"base_sha":"...","tree":"...","duration_s":11.2}}
224
- ```
225
-
226
- Required keys: `type`, `stage` (null for run-level events), `ts` (ISO UTC, ms), `data` (object). Also `v`, `seq` and `run`. Unknown types are kept and ignored by readers.
227
-
228
- | type | stage | data (required keys) |
229
- |---|---|---|
230
- | run.started | null | task_source (text/issue), issue_ref?, provider, model, model_override_applied, origin_repo (OWNER/REPO or null), branch, deep, cap_s |
231
- | stage.started | name | target_s, limit_s, eta_s? |
232
- | stage.completed | name | duration_s + the per-stage outputs in section 4 |
233
- | stage.failed | name | duration_s, reason |
234
- | stage.skipped | name | reason |
235
- | heartbeat | name | waiting_on, elapsed_s, eta_s?, diff {files, insertions, deletions} |
236
- | session.started | name | session_id, provider, model, pgid |
237
- | session.ended | name | session_id, exit (done/already_done/spec_conflict/killed/error), duration_s |
238
- | cost | name | session_id, usd (number or null), input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, source |
239
- | wall.sealed | wall | files [{path, sha256}] |
240
- | test.result | verify/deep | name, cmd, result (pass/fail/not_run/flaky), duration_s, reason? |
241
- | fix.round | fix | round, groups [{signature, count, sample}] |
242
- | cap.hit | name | elapsed_s |
243
- | escalated | null | reason, from_cap_s, to_cap_s |
244
- | tamper.detected | null | expected_sha256, actual_sha256 |
245
- | receipt.sealed | seal | path, receipt_sha256, signed, kid, verdict, not_proven[] |
246
- | pr.opened | pr | url, draft, existing |
247
- | deep.completed | deep | checks[], status_state, addendum_sha256 |
248
- | run.completed | null | verdict, pr_url?, not_proven[], cost_usd (or null), wall_s |
249
-
250
- Unknown is never 0. A missing cost is `usd: null`, and every reader renders null as "not measured".
251
-
252
- **Work-item state (one vocabulary).** `workItemState(events, nowMs?)` in `util/run_outputs.ts` (beside `phaseOf`) folds the log into one name per run, used by `loki status --json` (`state`), `phaseOf` (resume) and chat (which shells to status): `received` (run.started only), `prepared` (intake done), `planned` (plan done or wall seen), `executing` (implement running), `validating` (implement done, or verify/fix/commit/seal/pr/deep seen), `ready_to_ship` (receipt.sealed), `delivering` (pr.opened, written by the supervisor, run not yet complete), `observing` (delivering plus deep.started, the supervisor's detached post-PR deep verify is running). Terminal states come only from run.completed: `completed`, `waiting_for_input` (verdict SPEC_CONFLICT), `budget_stopped` (cap.hit with verdict PARTIAL or FAILED), `failed`, `cancelled`. `stalled` needs the clock argument and 30 minutes without events on an unfinished run.
253
-
254
- ## 6. Process topology and Rule of Two
255
-
256
- The process that reads untrusted issue text into an LLM context never holds a push token. The PR step runs as a separate process.
257
-
258
- | Process | Holds GitHub credentials | Runs an LLM | Reads untrusted text |
259
- |---|---|---|---|
260
- | P0 supervisor (`loki ...`) | yes, in its own env | no | no (passes file paths, never parses the issue body) |
261
- | P1 fetch child (`fetch_issue.ts` via `autonomy/issue-providers.sh:404 fetch_issue`) | yes (read) | no | writes it to a file, deterministic, exits before any LLM starts |
262
- | P2 worker (`engine10 worker`) | no: env is a COPY passed through `withholdGithubTokens` (`loki-ts/src/runner/github_token.ts:183`) | spawns sessions | yes |
263
- | P3 sessions (own process groups) | no (inherit P2 env) | yes | yes |
264
- | P4 push child (`autonomy/lib/engine10-push.sh`) | yes | no | no; inputs only from P0 memory via argv/env |
265
- | P5 deep supervisor (detached `engine10 deep-supervise`) | yes | no | no |
266
- | P6 deep worker | no | council | yes |
267
-
268
- Rules the implementation must keep:
269
- - **Credentials:** `withholdGithubTokens` mutates the object it is given. The supervisor calls it on `{...process.env}` for the worker, never on `process.env`, so the push child still gets real credentials.
270
- - **Origin pin:** P0 reads `remote.origin.url` once at start, before any provider runs. It passes the pinned URL to P4 as `_LOKI_ORIGIN_PINNED=1 _LOKI_PINNED_ORIGIN=<url>`. The pin is never read back from the event log, which sits in the agent-writable tree. The same holds for the branch, the repo and the Wall hashes.
271
- - **Tamper check:** P0 keeps a running sha256 of the bytes it appended. After every `session.ended` and before the PR, it re-hashes the file. On mismatch it emits `tamper.detected`, adds a NOT PROVEN entry ("event log modified outside the engine"), and does not push.
272
- - **Resume residual:** on resume, P0 re-reads the origin from git config and requires it to equal `run.started.data.origin_repo`; otherwise the push is refused. Remaining exposure: an agent that edits both the log and the origin is stopped only by `_loki_trusted_push`'s literal-github.com and default-branch checks.
273
- - **No token near repo code or agent output:** deep verify runs repository code, so P6 holds no token. PR comments and statuses go through P5, which calls `engine10-push.sh comment|status`.
274
- - **Model override:** when `LOKI_MODEL_OVERRIDE` is set, the session child gets `LOKI_CLAUDE_MODEL_PLANNING`, `LOKI_CLAUDE_MODEL_DEVELOPMENT` and `LOKI_CLAUDE_MODEL_FAST` set to it. `claudeTierToModel` reads those (`providers.ts:170`); the variable is not honored directly without `ANTHROPIC_BASE_URL` (`providers.ts:204`). Other providers record `model_override_applied: false` and a NOT PROVEN entry.
275
- - **Host guard:** `LOKI_HOST_GUARD=1` is set only for claude sessions. `resolveProvider` throws for other providers when the guard is required (`providers.ts:63`). For codex, cline and aider, the receipt lists "process-kill blocking not enforced" as NOT PROVEN.
276
-
277
- **Existing guards and tests that must stay green (listed for reference; the engine does not modify them):**
278
- - `autonomy/run.sh:5901 _loki_trusted_push` and helpers:
279
- - `:5777 _loki_with_github_tokens`
280
- - `:5826 _loki_github_repo_from_url`
281
- - `:5847 _loki_origin_refusal`
282
- - `:5868 _loki_pin_origin`
283
- - `:5883 _loki_run_neutral`
284
- - `:5951 _loki_withhold_github_tokens`
285
- - `loki-ts/src/runner/github_token.ts:183 withholdGithubTokens`
286
- - `tests/test-trusted-push-agent-config.sh`
287
- - `tests/test-gh-withhold-nested.sh`
288
- - `tests/moat/p9-rule-of-two.sh`
289
- - `loki-ts/tests/runner/github_token_withheld.test.ts`
290
- - `tests/test-issue-to-pr-action.sh`
291
- - `tests/test-pre-push-hook.sh`
292
- - `tests/test-branch-lifecycle.sh`
293
-
294
- ## 7. PR path (reuse of the trusted push)
295
-
296
- `autonomy/lib/engine10-push.sh <mode> ...` with modes `push-pr`, `comment` and `status`.
297
- - It sources exactly the region `tests/test-trusted-push-agent-config.sh` already extracts: from `^_LOKI_WITHHELD_TOKENS=""$` (`run.sh:5517`) through the closing brace of `_loki_withhold_github_tokens` (`run.sh:5992`), using the same awk anchors, with `log_warn` and `log_info` stubbed to stderr.
298
- - It fails closed if the anchors are missing.
299
- - It calls `_loki_trusted_push _loki_with_github_tokens "$repo_dir" "$branch"`. With nothing withheld in P4, the runner simply passes the command through.
300
- - Check-before-create: it mirrors `create_session_pr` (`run.sh:11181`, `gh pr list --head` at `:11287`), all through `_loki_run_neutral "$repo" command gh ...`:
301
- - `gh pr list --repo R --head B --state open --json url --jq '.[0].url'`
302
- - `gh pr create --repo R --head B --title T --body-file F [--draft]`
303
- - `status` mode: `gh api repos/R/statuses/SHA -f state=... -f context=loki/deep-verify -f description=...`.
304
-
305
- ## 8. Test map and runner detection (testmap.ts)
306
-
307
- `repo_profile.ts:117-131` reads only package.json scripts, which is cause 3. `testmap.ts` detects the following, each with the file that proves it:
308
-
309
- | Runner | Detected from | Command shape for selected files |
310
- |---|---|---|
311
- | pytest | pyproject.toml `[tool.pytest`, pytest.ini, setup.cfg `[tool:pytest]`, conftest.py, `tests/test_*.py` | `python -m pytest -q <files>` |
312
- | vitest | package.json deps or scripts mention vitest, vitest.config.* | `npx vitest run <files>` |
313
- | jest | package.json deps or scripts mention jest, jest.config.* | `npx jest <files>` |
314
- | bun | bunfig.toml or a `bun test` script | `bun test <files>` |
315
- | npm script | package.json scripts.test (fallback only) | `npm test --silent` (marked coarse) |
316
- | go | go.mod | `go test ./<pkg dirs>` |
317
- | cargo | Cargo.toml | `cargo test` (marked coarse) |
318
-
319
- The source-to-test map pairs each test file with the source basenames it imports or references (grep over test files). A monorepo can report several runners. `scripts/select-tests.sh` (`:36-38` switches into its own repo root; rules R0-R7 at `:102-419` name loki-mode paths) is used only when the target is this repo.
320
-
321
- ## 9. Seal and receipt
322
-
323
- `receipt.json` (schema `loki.v10.receipt/1`) contains:
324
- - run_id, task_sha256, source (text / issue_ref), repo (OWNER/REPO or null);
325
- - base_sha, head_sha, tree, diff_sha256;
326
- - wall {files [{path, sha256}], passed};
327
- - checks [{name, cmd, result, duration_s}];
328
- - not_proven[];
329
- - verdict, provider, model;
330
- - cost {usd or null, tokens};
331
- - time {wall_s, per_stage};
332
- - events_sha256 (hash of events.jsonl up to seal);
333
- - receipt_sha256, a sha256 over the canonical JSON (sorted keys, compact) with `verification` removed;
334
- - verification {jwt or null, kid}.
335
-
336
- The NOT PROVEN list always names the deferred deep checks: full suite, app boot, council, security scan. It also lists any tool that was missing, any flaky test, reverted test edits, `kill blocking not enforced` for non-claude providers, and `model override not applied` when that is the case.
337
-
338
- **Signing** reuses `autonomy/receipt_jwt.py`: `:117 load_signing_key`, `:220 sign_attestation`, `:266 verify_attestation`, `:199 build_jwks`.
339
- - It runs through `findIsolatedPython3()` (`loki-ts/src/util/python.ts:82`, the TS mirror of `_loki_snapshot_py_tool` at `autonomy/run.sh:10000`).
340
- - The command is `[py, "-I", "-c", code]`, where `code` puts `autonomy/` on `sys.path` explicitly and calls `sign_attestation(key, kid, job_id=run_id, run_id=run_id, receipt_hash=receipt_sha256)`. This is the pattern `autonomy/lib/proof-generator.py:2185-2197` uses.
341
- - Do NOT add `-S`: it drops site-packages, so `cryptography` never imports and every receipt comes out unsigned. `-I` already excludes user site and PYTHON* env.
342
- - An empty token means the summary prints UNSIGNED. The receipt is never presented as attested in that case.
343
-
344
- `receipt.md` is rendered from the same JSON and becomes the PR body section. A deep verify addendum (`receipt-addendum-1.json`) references `receipt_sha256` and is signed the same way.
345
-
346
- ## 10. Cost capture and the eval harness contract
347
-
348
- Eval harness contract (EV-1), met in the first wave:
349
-
350
- 1. **Marker file.** At run start, the supervisor writes `<checkout>/.loki/engine.json` as `{"engine":"v10","run_id":"<id>","events":".loki/runs/<id>/events.jsonl"}` (atomic write). A failing run still leaves it behind. Without it, the harness scores the run `arm_unavailable`. `autonomy/loki` never reads `LOKI_ENGINE`, so the routing lives in the bin/loki hook (section 11).
351
- 2. **Cost.** The harness reads `autonomy/lib/cost-summary.py <checkout> --json` and takes `total_cost_usd` only when `fully_measured` is true, otherwise null. The engine writes provider-reported cost where cost-summary.py already reads it:
352
- - `.loki/metrics/efficiency/iteration-<N>.json`, one per provider session;
353
- - N is the next integer after any existing file, and fields are `iteration, status, duration_ms, model, cost_usd, input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens`;
354
- - a session with no provider-reported dollars omits `cost_usd`, so cost-summary.py reports it as unmeasured and `fully_measured` goes false, which is honest.
355
-
356
- The same numbers also go into a `cost` event.
357
- 3. **Environment.** The engine honors `LOKI_MODEL_OVERRIDE` and `LOKI_SESSION_MODEL` (section 6). It never opens a browser: `loki dashboard` prints its URL only. It starts no dashboard during a run, so `LOKI_DASHBOARD=false` and `LOKI_NO_BROWSER=1` need no special handling.
358
-
359
- **Cost source:**
360
- - The claude CLI invoker (`providers.ts:323`) runs plain `-p` and records no cost. The SDK invoker records it: `sdk_stream_parser.ts:314-316` reads `total_cost_usd`, and `writeResultCost` (`:425-445`) writes `.loki/metrics/result-cost-<LOKI_ITERATION>.json`. That mirrors the bash capture at `autonomy/run.sh:25737-25800`.
361
- - So `session.ts` runs claude with `LOKI_SDK_LOOP=1` (selected by `selectClaudeInvokerKind`, `providers.ts:148`) and a unique `LOKI_ITERATION=<N>` per session. `cost.ts` then converts `result-cost-<N>.json` into the efficiency record and the cost event.
362
- - `LOKI_E10_INVOKER=cli` forces the CLI invoker. Its cost then reads "not measured".
363
- - Codex reports tokens only, so its dollar cost reads "not measured".
364
-
365
- **Session bounds:**
366
- - The SDK path has no timeout of its own, and `util/shell.ts:87 run` kills only the direct child.
367
- - `session.ts` therefore spawns each session as `engine10 session` in a new process group (`node:child_process` spawn with `detached: true`) and enforces the limit with `process.kill(-pgid, "SIGTERM")`, then `SIGKILL` after 2s.
368
-
369
- ## 11. CLI surface and dispatch hook
370
-
371
- Commands (all only with `LOKI_ENGINE=v10`):
372
- - `loki "<task>"` runs the engine on a free-text task in the current repo.
373
- - `loki <issue-url|owner/repo#N>` runs on a GitHub issue. GitLab and Jira URLs work in wave 3.
374
- - `loki status [run-id]` shows the latest run by default.
375
- - `loki verify [run-id]` checks receipt hashes and the JWT (via `verify_attestation` with the JWKS).
376
- - `loki dashboard` serves the one-screen SSE dashboard.
377
- - Flags: `--deep`, `--provider <name>`, `--resume <run-id>`, `--no-pr` (seal only; useful for eval and fixtures).
378
- - Hidden subcommands: `engine10 worker|session|deep-supervise|deep-worker`.
379
-
380
- **bin/loki hook.** One block inserted after the `LOKI_LEGACY_BASH` block (ends at line 244) and before the bun-presence check (line 248). `LOKI_LEGACY_BASH` still wins. When `LOKI_ENGINE` is unset, the block is a single skipped `if`:
381
-
382
- ```bash
383
- # Loki 10 engine (D29): additive; skipped entirely unless LOKI_ENGINE=v10.
384
- if [ "${LOKI_ENGINE:-}" = "v10" ]; then
385
- _e10=0
386
- case "${1:-}" in
387
- status|verify|dashboard) _e10=1 ;;
388
- ""|-*) _e10=0 ;;
389
- */*\#[0-9]*|http*://*/issues/*|http*://*/-/issues/*|http*://*/browse/*) _e10=1 ;;
390
- *" "*) _e10=1 ;;
391
- *) if declare -F _loki_known_command >/dev/null 2>&1 \
392
- && [ "$(_loki_known_command "$1")" = "other" ] && [ ! -e "$1" ]; then _e10=1; fi ;;
393
- esac
394
- if [ "$_e10" = "1" ]; then
395
- command -v bun >/dev/null 2>&1 || { echo "Error: LOKI_ENGINE=v10 needs bun. Unset LOKI_ENGINE to use the current engine." >&2; exit 1; }
396
- exec bun "$BUN_CLI" engine10 "$@"
397
- fi
398
- fi
399
- ```
400
-
401
- `_loki_known_command` comes from `autonomy/telemetry.sh:167`, sourced earlier by bin/loki. Legacy commands (`start`, `issue`, and so on) and existing file paths fall through unchanged.
402
-
403
- **loki-ts/src/cli.ts hook.** One arm before `default:` (line 303):
404
-
405
- ```ts
406
- case "engine10": {
407
- const { runEngine10 } = await import("./engine10/cli.ts");
408
- return runEngine10(rest);
409
- }
410
- ```
411
-
412
- The import is lazy, so legacy commands never load engine code. No other line of `src/cli.ts` or `bin/loki` changes; `tests/engine10/cli.test.ts` checks that the string `engine10` appears only in this arm.
413
-
414
- **`loki legacy` contract.** `loki legacy <args>` is an alias contract that lands only when the default flips to v10. It will run exactly today's route for `<args>`. Until then nothing is added. E-30 records today's routing table as a golden fixture so the flip can be checked against it.
415
-
416
- **Live output (output.ts, plus eta.ts in wave 2)**, one line per stage:
417
-
418
- ```
419
- [00:11] intake done 11s repo map cached, runners: pytest, vitest
420
- [00:49] plan+wall done 38s plan 7 lines, 4 wall tests sealed
421
- [01:05] implement waiting on claude session 1m00s ETA 2m00s (3 files, +41 -2)
422
- ```
423
-
424
- A heartbeat line appears every 60s while a stage is waiting. The final 5-line summary:
425
-
426
- ```
427
- PR: https://github.com/o/r/pull/12 (draft: fix rounds exhausted)
428
- Verdict: PARTIAL
429
- NOT PROVEN: full suite, app boot, council, security scan (deep verify running); flaky tests/test_x.py::t
430
- Cost: $0.84 (claude, 212k tokens) or not measured (codex reports tokens only)
431
- Time: 4m12s (intake 11s, plan+wall 38s, implement 2m41s, verify 29s, seal+pr 13s)
432
- ```
433
-
434
- ## 12. Dashboard
435
-
436
- - Served by `loki dashboard` (v10) from `engine10/dashboard/server.ts` with `Bun.serve` on 127.0.0.1:57375 (`LOKI_E10_DASHBOARD_PORT`).
437
- - The old FastAPI dashboard (`dashboard/`, port 57374) is untouched.
438
- - Routes:
439
- - `GET /` serves the page inlined from `page.ts`;
440
- - `GET /api/runs` lists runs folded from `.loki/runs/*/events.jsonl`;
441
- - `GET /api/runs/:id/events` is SSE: it replays the file, then tails it with `fs.watch` plus a 1s poll fallback.
442
- - One screen: runs list; per-run live stage timeline; PR; verdict; NOT PROVEN; cost; time.
443
- - A panel renders only when its data exists. Null renders as "not measured", never 0.
444
- - Localhost only. The server never opens a browser.
445
-
446
- ## 13. Memory, escalation, adapters
447
-
448
- **Cache (cache.ts):**
449
- - Location: `~/.loki/cache/v10/<repo-key>/`, where repo-key is sha256 of the pinned origin, or of the absolute path when there is no origin.
450
- - `repomap-<fp>-<tree>.json` and `testmap-<fp>-<tree>.json` are keyed by `HEAD^{tree}` and `<fp>`, the first 16 hex of the producer fingerprint (sha256 of every `loki-ts/src` .ts file; generated into the bundle by scripts/build.ts). The cache dir is 0700, files are 0600, written through a temp file plus rename.
451
- - `flaky.json` and `failures.jsonl` (the top 3 past failure signatures go into the implementer brief) are per repo.
452
- - Reads are optional and O(1). Writes happen after the PR, so nothing slows the first run.
453
-
454
- **Escalation (escalate.ts):**
455
- - `--deep` or auto-escalation applies when any of these hold: the repo has more than 20,000 tracked files, the plan names more than 12 files, or the issue carries an `epic` or `large` label.
456
- - Effects: cap 45 min, implement limit 30 min, full suite on the fast path.
457
- - It is always logged as an `escalated` event and shown in the summary.
458
-
459
- **Adapter interface (adapters/types.ts):**
460
-
461
- ```ts
462
- export interface Adapter {
463
- name: "github"|"gitlab"|"jira"|"slack";
464
- matches?(ref: string): boolean;
465
- fetchIssue?(ref: string): Promise<NormalizedIssue>; // github, gitlab, jira
466
- openPr?(req: PrRequest): Promise<{ url: string; draft: boolean }>; // github, gitlab
467
- notify?(summary: RunSummary): Promise<void>; // slack
468
- }
469
- ```
470
-
471
- - GitHub and GitLab adapters wrap `issue-providers.sh` `fetch_github_issue` (`:170`) and `fetch_gitlab_issue` (`:283`). Jira wraps `fetch_jira_issue` (`:321`).
472
- - GitHub PR-out goes through `engine10-push.sh`. GitLab MR-out needs `engine10-push-gitlab.sh`, because `_loki_trusted_push` refuses any non-github.com origin.
473
- - Slack posts the 5-line summary to `LOKI_SLACK_WEBHOOK_URL` from the supervisor.
474
- - Every adapter runs only in credentialed deterministic processes (P0, P1, P4) and has a fixture test.
475
-
476
- ## 14. Build and compatibility constraints
477
-
478
- - **dist:** `bin/loki` runs `loki-ts/dist/loki.js` by default, or `src/cli.ts` when src is newer. New src code is not guaranteed to be reachable until a train rebuilds dist.
479
- - No slice touches `loki-ts/dist/`; the release captain rebuilds it once per train.
480
- - Every Wall check runs from source.
481
- - The 01:00 UTC real-task run uses `LOKI_TS_ENTRY=<abs>/loki-ts/src/cli.ts` unless dist has been rebuilt.
482
- - **Parity fixtures:** do not touch `loki-ts/tests/fixtures/build_prompt/` or `loki-ts/tests/parity/build_prompt.test.ts`.
483
- - **No legacy edits:** no edits to `autonomy/run.sh`, `autonomy/loki`, `providers/*.sh`, `loki-ts/src/runner/*` or `loki-ts/src/providers/*`. The engine reuses them only through imports or by sourcing.
484
- - **Size:** engine10 stays under 5,000 lines (budget test).
485
-
486
- ## 15. Reuse inventory
487
-
488
- | Item | Location | Use |
489
- |---|---|---|
490
- | receipt_jwt | autonomy/receipt_jwt.py:117 load_signing_key, :199 build_jwks, :220 sign_attestation, :266 verify_attestation; caller pattern autonomy/lib/proof-generator.py:2185-2197 | Seal, addendum, `loki verify` |
491
- | select-tests | scripts/select-tests.sh:9-12 usage (`--files -`, `--run`), :36-38 repo-root cd, R0-R7 at :102-419 | Fast verify when the target is loki-mode only |
492
- | trusted push | autonomy/run.sh:5901 _loki_trusted_push (region :5517-:5992), :5883 _loki_run_neutral, :11181 create_session_pr (check-before-create :11287) | engine10-push.sh |
493
- | provider contracts | providers/claude.sh:31-32 flags, :380 provider_invoke, :413 provider_invoke_argv, :649 provider_invoke_with_tier; codex.sh:218/:308/:368; cline.sh:120/:155/:168; aider.sh:122/:157/:179; loader.sh:25 load_provider | Mirrored by the loki-ts invokers |
494
- | loki-ts invokers | loki-ts/src/runner/providers.ts:59 resolveProvider, :148 selectClaudeInvokerKind, :323 claudeProvider, :584 sdkQueryProvider, :837 codexProvider, :908 clineProvider, :958 aiderProvider; types.ts:95 ProviderInvocation, :122 ProviderInvoker, :126 ProviderResult | session.ts |
495
- | host guard | providers.ts:267 hostGuardRequired, :284 hostGuardSettingsJson; autonomy/hooks/validate-bash.sh:91-93 | Blocks process kills (claude) |
496
- | _loki_snapshot_py_tool | autonomy/run.sh:10000; TS mirror loki-ts/src/util/python.ts:82 findIsolatedPython3 | Signing interpreter |
497
- | cost capture | autonomy/run.sh:25737-25800; loki-ts/src/runner/sdk_stream_parser.ts:119 consumeSdkStream, :314-316, :425-445 writeResultCost; providers.ts:677-679 passes LOKI_ITERATION; autonomy/lib/cost-summary.py (reads .loki/metrics/efficiency) | cost.ts |
498
- | token withholding | loki-ts/src/runner/github_token.ts:183 withholdGithubTokens | Worker env |
499
- | issue fetch | autonomy/issue-providers.sh:110 parse_issue_reference, :170 github, :283 gitlab, :321 jira, :404 fetch_issue | fetch_issue.ts, adapters |
500
- | secret scan | autonomy/lib/secret-scan.sh | Deep verify |
501
- | council voters | loki-ts/src/council/voter_agents.ts:297 dispatchClaudeAgents | Deep verify |
502
- | repo profile | loki-ts/src/runner/repo_profile.ts:117-131 (package.json scripts only) | testmap.ts reuses it for npm scripts |
503
-
504
- ## 16. Slices
505
-
506
- All paths are relative to the repo root. `loki-ts/tests/engine10/` is written `T/`, and `loki-ts/src/engine10/` is written `S/`. Every fixture subdir is owned by exactly one slice. The union of all file sets was checked for duplicates: none.
507
-
508
- Wall checks for loki-ts tests are run as `cd loki-ts && bun test <file>`.
509
-
510
- ### Wave 1: thin vertical path (target: one real task end to end by about 01:00 UTC)
511
-
512
- - **E-01: Event log and schema.**
513
- - Files: S/events.ts, T/events.test.ts.
514
- - Tier: MEDIUM. Deps: none.
515
- - Wall: `cd loki-ts && bun test tests/engine10/events.test.ts`.
516
- - Red before: the file is missing. Green: append, seq, fold, tail, the required keys, unknown types ignored, and null cost kept as null.
517
- - **E-02: State machine skeleton.**
518
- - Files: S/machine.ts, S/types.ts, T/machine.test.ts, T/budget.test.ts.
519
- - Contents: stage table, Plan and Wall parallel group, `optional()` loader, budgets, global cap and deadline AbortSignal, resume from the last completed stage.
520
- - Tier: HIGH. Deps: E-01.
521
- - Wall: `cd loki-ts && bun test tests/engine10/machine.test.ts tests/engine10/budget.test.ts`.
522
- - Red: missing. Green: missing optional stages emit stage.skipped; resume skips completed stages; the cap aborts and jumps to seal; engine10 is under 5,000 lines.
523
- - **E-03: Supervisor and worker split, Rule of Two, eval marker.**
524
- - Files: S/supervisor.ts, S/worker.ts, T/rule_of_two.test.ts.
525
- - Contents: env copy through withholdGithubTokens, origin pin kept in memory, single-writer log with a running sha256 and tamper check, `.loki/engine.json` marker.
526
- - Tier: HIGH. Deps: E-01, E-02.
527
- - Wall: `cd loki-ts && bun test tests/engine10/rule_of_two.test.ts`.
528
- - Green:
529
- - the worker env holds the sentinel, not the canary token;
530
- - the supervisor env keeps the canary;
531
- - a tampered log blocks the push;
532
- - engine.json exists after a failing run.
533
- - **E-04: Intake.**
534
- - Files: S/stages/intake.ts, S/fetch_issue.ts, S/repomap.ts, T/intake.test.ts, T/fixtures/intake/.
535
- - Contents: dirty-tree refusal, branch, `.git/info/exclude`, issue fetch child, closed / merged-PR already-done check, repo map; no PRD.
536
- - Tier: MEDIUM. Deps: E-02, E-03.
537
- - Wall: `cd loki-ts && bun test tests/engine10/intake.test.ts`.
538
- - Green: a closed-issue fixture gives ALREADY_SATISFIED, no LLM call, and intake under 15s on a fixture repo.
539
- - **E-05: Test map and runner detection.**
540
- - Files: S/testmap.ts, T/testmap.test.ts, T/fixtures/testmap/ (includes a mixed pytest+vitest repo).
541
- - Tier: MEDIUM. Deps: none.
542
- - Wall: `cd loki-ts && bun test tests/engine10/testmap.test.ts`.
543
- - Red: missing. Green: the mixed fixture reports runners pytest and vitest with evidence files, never none; the source-to-test map is correct.
544
- - **E-06: Cost capture.**
545
- - Files: S/cost.ts, T/cost.test.ts, T/fixtures/cost/.
546
- - Contents: result-cost-N.json to cost event plus `.loki/metrics/efficiency/iteration-N.json`; tokens-only sessions omit cost_usd.
547
- - Tier: MEDIUM. Deps: E-01.
548
- - Wall: `cd loki-ts && bun test tests/engine10/cost.test.ts`.
549
- - Green: `cost-summary.py <fixture> --json`, run inside the test, reports fully_measured true with a total for a claude fixture, and false with a null total for a codex fixture.
550
- - **E-07: Session wrapper.**
551
- - Files: S/session.ts, T/session.test.ts, T/fixtures/session/.
552
- - Contents: its own process group, resolveProvider reuse, `LOKI_SDK_LOOP=1` for claude, unique `LOKI_ITERATION`, model override through `LOKI_CLAUDE_MODEL_*`, `LOKI_HOST_GUARD=1` for claude only, 60s heartbeat with diff shortstat, group kill at the limit.
553
- - Tier: MEDIUM. Deps: E-01, E-06.
554
- - Wall: `cd loki-ts && bun test tests/engine10/session.test.ts`.
555
- - Green: a stub provider that forks a sleeping grandchild is fully killed at the limit (grandchild pid gone); a heartbeat is emitted; the override reaches the child env.
556
- - **E-08: Implement.**
557
- - Files: S/stages/implement.ts, T/implement.test.ts, T/fixtures/implement/.
558
- - Contents: brief (no full suite, no kills, no docs, markers), post-session test read-only check with restore, spec-conflict and already-done exits.
559
- - Tier: MEDIUM. Deps: E-07, E-05.
560
- - Wall: `cd loki-ts && bun test tests/engine10/implement.test.ts`.
561
- - Green: a stub that edits an existing test sees it restored and listed; the LOKI_SPEC_CONFLICT and LOKI_ALREADY_DONE markers are parsed.
562
- - **E-09: Fast verify.**
563
- - Files: S/stages/verify.ts, T/verify.test.ts, T/fixtures/verify/.
564
- - Contents: impacted and Wall tests, lint/typecheck of changed files, select-tests.sh only for the loki-mode target, missing tool gives NOT PROVEN, one flaky rerun, 60s limit.
565
- - Tier: MEDIUM. Deps: E-05, E-02.
566
- - Wall: `cd loki-ts && bun test tests/engine10/verify.test.ts`.
567
- - Green: a missing ruff is NOT PROVEN, not a failure; a fail-then-pass test is flaky; the empty-diff already-done path gives ALREADY_SATISFIED.
568
- - **E-10: Seal.**
569
- - Files: S/stages/seal.ts, T/seal.test.ts.
570
- - Contents: commit, receipt.json and receipt.md, canonical receipt_sha256, receipt_jwt signing via `python3 -I` (no -S), NOT PROVEN list, UNSIGNED when no key.
571
- - Tier: HIGH. Deps: E-01, E-09.
572
- - Wall: `cd loki-ts && bun test tests/engine10/seal.test.ts`.
573
- - Green:
574
- - with a test Ed25519 key, the JWT verifies through verify_attestation and the hash recomputes;
575
- - without a key, signed is false and the summary says UNSIGNED;
576
- - deep checks are always in NOT PROVEN.
577
- - **E-11: Trusted push and PR.**
578
- - Files: autonomy/lib/engine10-push.sh, S/stages/pr.ts, tests/test-engine10-push.sh, T/pr.test.ts.
579
- - Contents: sources the run.sh region by anchor, check-before-create, draft flag, pending `loki/deep-verify` status; runs in the supervisor.
580
- - Tier: HIGH. Deps: E-03, E-10.
581
- - Wall: `bash tests/test-engine10-push.sh`.
582
- - Green:
583
- - a planted pre-push hook records no canary;
584
- - a push to main is refused;
585
- - a second call reuses the existing PR URL;
586
- - missing anchors fail closed.
587
- - **E-12: CLI entry.**
588
- - Files: S/cli.ts, loki-ts/src/cli.ts (one `case "engine10"` arm before `default:` at line 303), bin/loki (one block between lines 244 and 246), tests/test-engine10-dispatch.sh, T/cli.test.ts.
589
- - Tier: MEDIUM. Deps: E-03.
590
- - Wall: `bash tests/test-engine10-dispatch.sh`.
591
- - Green:
592
- - with LOKI_ENGINE unset, `loki "fix x"`, `loki status` and `loki start` route exactly as before (stub LOKI_TS_ENTRY records argv);
593
- - with v10, tasks, issue refs, status, verify and dashboard reach `engine10`;
594
- - LOKI_LEGACY_BASH still wins;
595
- - no bun plus v10 exits 1 with a message;
596
- - `engine10` appears only in the one cli.ts arm.
597
- - **E-13: Live output.**
598
- - Files: S/output.ts, T/output.test.ts.
599
- - Contents: stage lines with elapsed time, heartbeat line, 5-line summary, null rendered as "not measured".
600
- - Tier: MEDIUM. Deps: E-01.
601
- - Wall: `cd loki-ts && bun test tests/engine10/output.test.ts`.
602
- - Green: a golden 5-line summary for VERIFIED and PARTIAL fixtures; no "$0.00" when cost is null.
603
- - **E-14: Thin-path end to end.**
604
- - Files: T/e2e.test.ts, T/fixtures/e2e/ (tiny repo plus a stub claude CLI).
605
- - Tier: MEDIUM. Deps: E-01 through E-13.
606
- - Wall: `cd loki-ts && bun test tests/engine10/e2e.test.ts`.
607
- - Green: `LOKI_ENGINE=v10 LOKI_E10_INVOKER=cli LOKI_CLAUDE_CLI=<stub> loki "<task>" --no-pr` produces events through seal, receipt.json, `.loki/engine.json` and an efficiency record in under 60s.
608
- - Then run the real task from source (`LOKI_TS_ENTRY=<abs>/loki-ts/src/cli.ts`).
609
-
610
- ### Wave 2: quality and speed
611
-
612
- - **E-15: Wall author.**
613
- - Files: S/stages/wall.ts, T/wall.test.ts, T/fixtures/wall/.
614
- - Contents: isolated temp-dir session (task and repo map only), copy into the repo, sha256 seal before Implement, base-tree run gives ALREADY_SATISFIED.
615
- - Tier: MEDIUM. Deps: E-02, E-07, E-04.
616
- - Wall: `cd loki-ts && bun test tests/engine10/wall.test.ts`.
617
- - Green: the session cwd contains no repo files; wall.sealed comes before session.started(implement); green on base short-circuits.
618
- - **E-16: Plan.**
619
- - Files: S/stages/plan.ts, T/plan.test.ts.
620
- - Contents: relevant-file selection, output truncated to 10 lines, runs in parallel with the Wall.
621
- - Tier: MEDIUM. Deps: E-02, E-07, E-04.
622
- - Wall: `cd loki-ts && bun test tests/engine10/plan.test.ts`.
623
- - Green: a 25-line stub output is truncated to 10; Plan and Wall start times differ by less than 1s.
624
- - **E-17: Fix rounds and failure grouping.**
625
- - Files: S/stages/fix.ts, S/failures.ts, T/fix.test.ts, T/failures.test.ts, T/fixtures/failures/.
626
- - Tier: MEDIUM. Deps: E-09, E-07.
627
- - Wall: `cd loki-ts && bun test tests/engine10/fix.test.ts tests/engine10/failures.test.ts`.
628
- - Green: pytest, vitest and jest output groups into at most 5 signatures; at most 2 rounds, then PARTIAL.
629
- - **E-18: Cache.**
630
- - Files: S/cache.ts, T/cache.test.ts.
631
- - Contents: repo key, tree-hash repo map and test map, flaky list, failure causes, writes after the PR.
632
- - Tier: MEDIUM. Deps: E-04, E-05.
633
- - Wall: `cd loki-ts && bun test tests/engine10/cache.test.ts`.
634
- - Green: the second intake on the same tree reads from the cache; the first run performs no cache write before pr.opened.
635
- - **E-19: Hard cap and DRAFT PR body.**
636
- - Files: S/pr_body.ts, T/cap.test.ts.
637
- - Tier: MEDIUM. Deps: E-02, E-07, E-11.
638
- - Wall: `cd loki-ts && bun test tests/engine10/cap.test.ts`.
639
- - Green: with `LOKI_E10_CAP_S=20` and a sleeping stub, the group is killed, verdict is PARTIAL, a draft is requested, and the body lists the missing checks.
640
- - **E-20: ETA.**
641
- - Files: S/eta.ts, T/eta.test.ts.
642
- - Tier: MEDIUM. Deps: E-13, E-18.
643
- - Wall: `cd loki-ts && bun test tests/engine10/eta.test.ts`.
644
- - Green: the ETA uses stage targets on the first run and cached history afterwards; it is never negative.
645
- - **E-21: `loki status`.**
646
- - Files: S/status.ts, T/status.test.ts.
647
- - Tier: MEDIUM. Deps: E-01, E-12.
648
- - Wall: `cd loki-ts && bun test tests/engine10/status.test.ts`.
649
- - Green: output is folded from events only; an unfinished run shows the current stage and elapsed time.
650
- - **E-22: `loki verify`.**
651
- - Files: S/verify_cmd.ts, T/verify_cmd.test.ts.
652
- - Tier: MEDIUM. Deps: E-10.
653
- - Wall: `cd loki-ts && bun test tests/engine10/verify_cmd.test.ts`.
654
- - Green: a tampered receipt fails; a signed receipt verifies against the JWKS; an unsigned one reports UNSIGNED.
655
- - **E-23: Deep verify.**
656
- - Files: S/stages/deep.ts, T/deep.test.ts, T/fixtures/deep/.
657
- - Contents: detached deep supervisor plus token-less worker; full suite, app boot, council (claude), secret scan; generated docs excluded; refused checks are NOT PROVEN; comment, addendum and status go through engine10-push.sh.
658
- - Tier: MEDIUM. Deps: E-11, E-10, E-03.
659
- - Wall: `cd loki-ts && bun test tests/engine10/deep.test.ts`.
660
- - Green: a secret in a changed file sets the status to failure; an oversized council context is NOT PROVEN; the deep worker env holds no token.
661
-
662
- ### Wave 3: surface and reach
663
-
664
- - **E-24: Dashboard (SSE).**
665
- - Files: S/dashboard/server.ts, S/dashboard/page.ts, T/dashboard.test.ts.
666
- - Tier: MEDIUM. Deps: E-01, E-12.
667
- - Wall: `cd loki-ts && bun test tests/engine10/dashboard.test.ts`.
668
- - Green: binds 127.0.0.1 only; the SSE replays then streams a new event within 2s; panels without data are absent; null shows as "not measured".
669
- - **E-25: Adapter interface and GitHub adapter.**
670
- - Files: S/adapters/types.ts, S/adapters/index.ts, S/adapters/github.ts, T/adapters_github.test.ts, T/fixtures/adapters-github/.
671
- - Tier: MEDIUM. Deps: E-04, E-11.
672
- - Wall: `cd loki-ts && bun test tests/engine10/adapters_github.test.ts`.
673
- - Green: the fixture issue normalizes; openPr calls engine10-push.sh with argv only.
674
- - **E-26: GitLab adapter.**
675
- - Files: S/adapters/gitlab.ts, autonomy/lib/engine10-push-gitlab.sh, T/adapters_gitlab.test.ts, tests/test-engine10-push-gitlab.sh, T/fixtures/adapters-gitlab/.
676
- - Contents: issue in, and MR out through a fresh-repo push with a literal gitlab.com origin check.
677
- - Tier: HIGH (Rule of Two). Deps: E-25.
678
- - Wall: `bash tests/test-engine10-push-gitlab.sh`.
679
- - Green: a planted hook records no canary; a non-gitlab.com origin is refused.
680
- - **E-27: Jira read adapter.**
681
- - Files: S/adapters/jira.ts, T/adapters_jira.test.ts, T/fixtures/adapters-jira/.
682
- - Tier: MEDIUM. Deps: E-25.
683
- - Wall: `cd loki-ts && bun test tests/engine10/adapters_jira.test.ts`.
684
- - Green: the fixture normalizes; there is no write path.
685
- - **E-28: Slack notify adapter.**
686
- - Files: S/adapters/slack.ts, T/adapters_slack.test.ts.
687
- - Tier: MEDIUM. Deps: E-25, E-13.
688
- - Wall: `cd loki-ts && bun test tests/engine10/adapters_slack.test.ts`.
689
- - Green: a local HTTP fixture receives exactly the 5-line summary; no call is made when the webhook is unset.
690
- - **E-29: Escalation.**
691
- - Files: S/escalate.ts, T/escalate.test.ts.
692
- - Contents: --deep and auto rules, logged `escalated` event, raised caps.
693
- - Tier: MEDIUM. Deps: E-02, E-16.
694
- - Wall: `cd loki-ts && bun test tests/engine10/escalate.test.ts`.
695
- - Green: a 13-file plan escalates with an event; without a trigger, the cap stays 900s.
696
- - **E-30: Legacy alias contract.**
697
- - Files: tests/test-engine10-legacy-contract.sh, tests/fixtures/engine10-legacy-routes.txt.
698
- - Contents: golden routes today; the `loki legacy` assertions are skipped until the default flips.
699
- - Tier: MEDIUM. Deps: E-12.
700
- - Wall: `bash tests/test-engine10-legacy-contract.sh`.
701
- - Green: 20 recorded legacy routes match today's behavior; the legacy-alias assertions report SKIP until LOKI_ENGINE defaults to v10.
702
-
703
- ## 17. BOARD
704
-
705
- | id | title | files | tier | wall check | status | notes |
706
- |---|---|---|---|---|---|---|
707
- | E-01 | Event log, schema and shared types | loki-ts/src/engine10/events.ts, loki-ts/src/engine10/types.ts, loki-ts/tests/engine10/events.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/events.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on none |
708
- | E-02 | State machine skeleton, resume, cap, optional loader | loki-ts/src/engine10/machine.ts, loki-ts/tests/engine10/machine.test.ts, loki-ts/tests/engine10/budget.test.ts | HIGH | cd loki-ts && bun test tests/engine10/machine.test.ts tests/engine10/budget.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-01 |
709
- | E-03 | Supervisor/worker split, Rule of Two, engine.json marker | loki-ts/src/engine10/supervisor.ts, loki-ts/src/engine10/worker.ts, loki-ts/tests/engine10/rule_of_two.test.ts | HIGH | cd loki-ts && bun test tests/engine10/rule_of_two.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-01, E-02 |
710
- | E-04 | Intake (no PRD, already-done detection) | loki-ts/src/engine10/stages/intake.ts, loki-ts/src/engine10/fetch_issue.ts, loki-ts/src/engine10/repomap.ts, loki-ts/tests/engine10/intake.test.ts, loki-ts/tests/engine10/fixtures/intake/ | MEDIUM | cd loki-ts && bun test tests/engine10/intake.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-02, E-03 |
711
- | E-05 | Test map and real runner detection | loki-ts/src/engine10/testmap.ts, loki-ts/tests/engine10/testmap.test.ts, loki-ts/tests/engine10/fixtures/testmap/ | MEDIUM | cd loki-ts && bun test tests/engine10/testmap.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on none |
712
- | E-06 | Cost capture into cost-summary.py records | loki-ts/src/engine10/cost.ts, loki-ts/tests/engine10/cost.test.ts, loki-ts/tests/engine10/fixtures/cost/ | MEDIUM | cd loki-ts && bun test tests/engine10/cost.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-01 |
713
- | E-07 | Session wrapper (process group, heartbeat, model override) | loki-ts/src/engine10/session.ts, loki-ts/tests/engine10/session.test.ts, loki-ts/tests/engine10/fixtures/session/ | MEDIUM | cd loki-ts && bun test tests/engine10/session.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-01, E-06 |
714
- | E-08 | Implement stage and brief | loki-ts/src/engine10/stages/implement.ts, loki-ts/tests/engine10/implement.test.ts, loki-ts/tests/engine10/fixtures/implement/ | MEDIUM | cd loki-ts && bun test tests/engine10/implement.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-05, E-07 |
715
- | E-09 | Fast verify | loki-ts/src/engine10/stages/verify.ts, loki-ts/tests/engine10/verify.test.ts, loki-ts/tests/engine10/fixtures/verify/ | MEDIUM | cd loki-ts && bun test tests/engine10/verify.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-02, E-05 |
716
- | E-10 | Seal (signed receipt, NOT PROVEN) | loki-ts/src/engine10/stages/seal.ts, loki-ts/tests/engine10/seal.test.ts | HIGH | cd loki-ts && bun test tests/engine10/seal.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-01, E-09 |
717
- | E-11 | Trusted push and PR | autonomy/lib/engine10-push.sh, loki-ts/src/engine10/stages/pr.ts, tests/test-engine10-push.sh, loki-ts/tests/engine10/pr.test.ts | HIGH | bash tests/test-engine10-push.sh | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-03, E-10 |
718
- | E-12 | CLI entry behind LOKI_ENGINE=v10 | loki-ts/src/engine10/cli.ts, loki-ts/src/cli.ts (case engine10 before default at line 303), bin/loki (block between lines 244 and 246), tests/test-engine10-dispatch.sh, loki-ts/tests/engine10/cli.test.ts | MEDIUM | bash tests/test-engine10-dispatch.sh | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-03 |
719
- | E-13 | Live output and 5-line summary | loki-ts/src/engine10/output.ts, loki-ts/tests/engine10/output.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/output.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-01 |
720
- | E-14 | Thin-path end to end | loki-ts/tests/engine10/e2e.test.ts, loki-ts/tests/engine10/fixtures/e2e/ | MEDIUM | cd loki-ts && bun test tests/engine10/e2e.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 1; depends on E-01 through E-13 |
721
- | E-15 | Wall author (blind, hashed) | loki-ts/src/engine10/stages/wall.ts, loki-ts/tests/engine10/wall.test.ts, loki-ts/tests/engine10/fixtures/wall/ | MEDIUM | cd loki-ts && bun test tests/engine10/wall.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-02, E-04, E-07 |
722
- | E-16 | Plan (10 lines or fewer) | loki-ts/src/engine10/stages/plan.ts, loki-ts/tests/engine10/plan.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/plan.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-02, E-04, E-07 |
723
- | E-17 | Fix rounds and failure grouping | loki-ts/src/engine10/stages/fix.ts, loki-ts/src/engine10/failures.ts, loki-ts/tests/engine10/fix.test.ts, loki-ts/tests/engine10/failures.test.ts, loki-ts/tests/engine10/fixtures/failures/ | MEDIUM | cd loki-ts && bun test tests/engine10/fix.test.ts tests/engine10/failures.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-07, E-09 |
724
- | E-18 | Per-repo cache by tree hash | loki-ts/src/engine10/cache.ts, loki-ts/tests/engine10/cache.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/cache.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-04, E-05 |
725
- | E-19 | Hard cap and DRAFT PR body | loki-ts/src/engine10/pr_body.ts, loki-ts/tests/engine10/cap.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/cap.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-02, E-07, E-11 |
726
- | E-20 | ETA | loki-ts/src/engine10/eta.ts, loki-ts/tests/engine10/eta.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/eta.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-13, E-18 |
727
- | E-21 | loki status | loki-ts/src/engine10/status.ts, loki-ts/tests/engine10/status.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/status.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-01, E-12 |
728
- | E-22 | loki verify | loki-ts/src/engine10/verify_cmd.ts, loki-ts/tests/engine10/verify_cmd.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/verify_cmd.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-10 |
729
- | E-23 | Deep verify (async, token-less worker) | loki-ts/src/engine10/stages/deep.ts, loki-ts/tests/engine10/deep.test.ts, loki-ts/tests/engine10/fixtures/deep/ | MEDIUM | cd loki-ts && bun test tests/engine10/deep.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 2; depends on E-03, E-10, E-11 |
730
- | E-24 | Dashboard over SSE | loki-ts/src/engine10/dashboard/server.ts, loki-ts/src/engine10/dashboard/page.ts, loki-ts/tests/engine10/dashboard.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/dashboard.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 3; depends on E-01, E-12 |
731
- | E-25 | Adapter interface and GitHub adapter | loki-ts/src/engine10/adapters/types.ts, loki-ts/src/engine10/adapters/index.ts, loki-ts/src/engine10/adapters/github.ts, loki-ts/tests/engine10/adapters_github.test.ts, loki-ts/tests/engine10/fixtures/adapters-github/ | MEDIUM | cd loki-ts && bun test tests/engine10/adapters_github.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 3; depends on E-04, E-11 |
732
- | E-26 | GitLab adapter (issue in, MR out) | loki-ts/src/engine10/adapters/gitlab.ts, autonomy/lib/engine10-push-gitlab.sh, loki-ts/tests/engine10/adapters_gitlab.test.ts, tests/test-engine10-push-gitlab.sh, loki-ts/tests/engine10/fixtures/adapters-gitlab/ | HIGH | bash tests/test-engine10-push-gitlab.sh | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 3; depends on E-25 |
733
- | E-27 | Jira read adapter | loki-ts/src/engine10/adapters/jira.ts, loki-ts/tests/engine10/adapters_jira.test.ts, loki-ts/tests/engine10/fixtures/adapters-jira/ | MEDIUM | cd loki-ts && bun test tests/engine10/adapters_jira.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 3; depends on E-25 |
734
- | E-28 | Slack notify adapter | loki-ts/src/engine10/adapters/slack.ts, loki-ts/tests/engine10/adapters_slack.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/adapters_slack.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 3; depends on E-13, E-25 |
735
- | E-29 | Escalation (--deep, logged auto) | loki-ts/src/engine10/escalate.ts, loki-ts/tests/engine10/escalate.test.ts | MEDIUM | cd loki-ts && bun test tests/engine10/escalate.test.ts | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 3; depends on E-02, E-16 |
736
- | E-30 | Legacy alias contract (golden routes) | tests/test-engine10-legacy-contract.sh, tests/fixtures/engine10-legacy-routes.txt | MEDIUM | bash tests/test-engine10-legacy-contract.sh | ready@2026-09-27T21:50Z | Source: ENGINE.md 21:50Z cut; wave 3; depends on E-12 |
737
-
738
- ---
739
-
740
- ## Chief of Staff amendment (2026-09-27T22:02Z): parallel build order
741
-
742
- To let wave 1 build in parallel, `loki-ts/src/engine10/types.ts` moves from E-02 into E-01. E-01 owns events.ts AND types.ts, and types.ts declares every cross-module interface up front: the event envelope and event types, Stage, RunContext, Verdict, stage budgets, the Receipt shape, a SessionRunner interface (what session.ts implements), a TestMap interface (what testmap.ts returns), a CostReader interface, and the push-child argv contract. Every other wave 1 module depends on its siblings only through those interfaces, injected via RunContext, so each can be unit-tested with fakes before its siblings exist. Build order: phase A = E-01, E-05, E-06; phase B (after E-01 merges) = E-02, E-03, E-04, E-07 to E-13 in parallel; phase C = E-14 and wave 2.
743
-