loki-mode 10.7.0 → 10.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +1 -0
  2. package/SKILL.md +2 -2
  3. package/VERSION +1 -1
  4. package/autonomy/loki +4 -1
  5. package/autonomy/run.sh +9 -5
  6. package/dashboard/__init__.py +1 -1
  7. package/dashboard/server.py +6 -8
  8. package/docs/INSTALLATION.md +1 -1
  9. package/docs/v10/CONTROL-PLANE.md +7 -0
  10. package/docs/v10/CP-ENTERPRISE-UI.md +263 -2
  11. package/docs/v10/DECISIONS.md +41 -0
  12. package/docs/v10/ENGINE-LAWS.md +155 -0
  13. package/docs/v10/FAILURE-CLASSES.md +166 -0
  14. package/docs/v10/GUIDE.md +4 -2
  15. package/docs/v10/L0-WAVE1.md +81 -0
  16. package/docs/v10/METRICS.md +6 -0
  17. package/docs/v10/MORNING-BRIEF-1003.md +11 -25
  18. package/docs/v10/OPERATING-MODEL.md +1 -0
  19. package/docs/v10/PROGRESS.md +28 -0
  20. package/loki-ts/data/model-pricing.json +6 -6
  21. package/loki-ts/dist/loki.js +851 -837
  22. package/loki-ts/package.json +2 -1
  23. package/mcp/__init__.py +1 -1
  24. package/package.json +2 -2
  25. package/packages/control-plane/dist/server.js +17103 -5411
  26. package/packages/control-plane/drizzle/0002_tiresome_fixer.sql +7 -0
  27. package/packages/control-plane/drizzle/0003_integrity.sql +4 -0
  28. package/packages/control-plane/drizzle/0004_cpe03_local_repos_actions.sql +17 -0
  29. package/packages/control-plane/drizzle/meta/0002_snapshot.json +409 -0
  30. package/packages/control-plane/drizzle/meta/0003_snapshot.json +437 -0
  31. package/packages/control-plane/drizzle/meta/0004_snapshot.json +542 -0
  32. package/packages/control-plane/drizzle/meta/_journal.json +22 -1
  33. package/packages/control-plane/package.json +4 -1
  34. package/packages/control-plane/src/db/migrate.ts +6 -2
  35. package/packages/control-plane/src/db/prune.ts +91 -0
  36. package/packages/control-plane/src/db/schema.ts +32 -0
  37. package/packages/control-plane/src/server/app.ts +30 -22
  38. package/packages/control-plane/src/server/audit.ts +15 -0
  39. package/packages/control-plane/src/server/auth.ts +7 -1
  40. package/packages/control-plane/src/server/integrity.ts +147 -0
  41. package/packages/control-plane/src/server/legacy/routes-metrics.ts +18 -0
  42. package/packages/control-plane/src/server/legacy/routes.ts +237 -0
  43. package/packages/control-plane/src/server/legacy/shim.ts +195 -0
  44. package/packages/control-plane/src/server/repos.ts +27 -0
  45. package/packages/control-plane/src/server/routes/artifacts.ts +104 -0
  46. package/packages/control-plane/src/server/routes/audit.ts +17 -0
  47. package/packages/control-plane/src/server/routes/config.ts +319 -0
  48. package/packages/control-plane/src/server/routes/control.ts +75 -0
  49. package/packages/control-plane/src/server/routes/cost.ts +70 -0
  50. package/packages/control-plane/src/server/routes/cost_ledger.ts +210 -0
  51. package/packages/control-plane/src/server/routes/fleet.ts +101 -0
  52. package/packages/control-plane/src/server/routes/index.ts +68 -0
  53. package/packages/control-plane/src/server/routes/integrations.ts +123 -0
  54. package/packages/control-plane/src/server/routes/merge_risk.ts +209 -0
  55. package/packages/control-plane/src/server/routes/metrics.ts +93 -0
  56. package/packages/control-plane/src/server/routes/notify.ts +48 -0
  57. package/packages/control-plane/src/server/routes/providers.ts +111 -0
  58. package/packages/control-plane/src/server/routes/start.ts +39 -0
  59. package/packages/control-plane/src/server/routes/stats.ts +76 -0
  60. package/packages/control-plane/src/server/routes/stream.ts +85 -0
  61. package/packages/control-plane/src/server/routes/verify.ts +66 -0
  62. package/packages/control-plane/src/server/runs.ts +46 -4
  63. package/packages/control-plane/src/server/spawn.ts +79 -0
  64. package/packages/control-plane/src/shipper/discover.ts +50 -3
  65. package/packages/control-plane/src/shipper/ship.ts +15 -0
  66. package/packages/control-plane/src/shipper/watch.ts +3 -1
  67. package/packages/control-plane/ui/dist/assets/index-BQbFv65M.css +1 -0
  68. package/packages/control-plane/ui/dist/assets/index-Dbhu244h.js +155 -0
  69. package/packages/control-plane/ui/dist/index.html +2 -2
  70. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  71. package/web-app/dist/assets/{AdminPage-BQPb5rc5.js → AdminPage-DDDvUz0N.js} +1 -1
  72. package/web-app/dist/assets/{Avatar-Cttco6FC.js → Avatar-Dcdz46i6.js} +1 -1
  73. package/web-app/dist/assets/{Badge-CPb6kpbH.js → Badge-BB24cCpK.js} +1 -1
  74. package/web-app/dist/assets/{Button-caTL28a4.js → Button-D0-DmPZL.js} +1 -1
  75. package/web-app/dist/assets/{CockpitPage-bEbLx6ph.js → CockpitPage-CdjpU2JW.js} +1 -1
  76. package/web-app/dist/assets/{ComparePage-DNtJSij-.js → ComparePage-DT5U0y0d.js} +1 -1
  77. package/web-app/dist/assets/{ErrorBoundary-BrgC3K44.js → ErrorBoundary-lEHcl0EO.js} +1 -1
  78. package/web-app/dist/assets/{EvidenceReceiptPanel-Q-mSrUUQ.js → EvidenceReceiptPanel-GpnWvdCr.js} +1 -1
  79. package/web-app/dist/assets/{GitHubIssuesPanel-DbmYl_Er.js → GitHubIssuesPanel-C7VOh1B7.js} +1 -1
  80. package/web-app/dist/assets/{GitHubPRsPanel-C6PCHM4B.js → GitHubPRsPanel-G_kOuINv.js} +1 -1
  81. package/web-app/dist/assets/{HomePage-7zsL_k_e.js → HomePage-PqRisOny.js} +2 -2
  82. package/web-app/dist/assets/{LoginPage-Cl4ON8RQ.js → LoginPage-DU7pFAkf.js} +1 -1
  83. package/web-app/dist/assets/{MagicPage-BNEAhTqH.js → MagicPage-C5JWIWMk.js} +1 -1
  84. package/web-app/dist/assets/{MetricsPage-DyBH-88q.js → MetricsPage-CbIGS_qo.js} +1 -1
  85. package/web-app/dist/assets/{NotFoundPage-CIVr21yL.js → NotFoundPage-vU1pvdSt.js} +1 -1
  86. package/web-app/dist/assets/{ProjectPage-BMeVYocF.js → ProjectPage-SsixIPPv.js} +3 -3
  87. package/web-app/dist/assets/{ProjectsPage-D-H2WRVU.js → ProjectsPage-BfQKSR9k.js} +1 -1
  88. package/web-app/dist/assets/{SettingsPage-o0kR9RAt.js → SettingsPage-B8YfXAom.js} +1 -1
  89. package/web-app/dist/assets/{ShowcasePage-DtfMDMjp.js → ShowcasePage-Ba407f2-.js} +1 -1
  90. package/web-app/dist/assets/{SystemSettingsPage-CkXdpZ_T.js → SystemSettingsPage-DzNQhhBS.js} +1 -1
  91. package/web-app/dist/assets/{TeamsPage-Cu5H9cQ0.js → TeamsPage-tqUnpZ15.js} +1 -1
  92. package/web-app/dist/assets/{TemplatesPage-3wdbVwil.js → TemplatesPage-ClB5EpI3.js} +1 -1
  93. package/web-app/dist/assets/{TerminalOutput-CWn301xh.js → TerminalOutput-CBvpYfEu.js} +1 -1
  94. package/web-app/dist/assets/{activity-YGaAt4zJ.js → activity-C1s0L_X9.js} +1 -1
  95. package/web-app/dist/assets/{bell-C28q0GO7.js → bell-DMEiXr73.js} +1 -1
  96. package/web-app/dist/assets/{bot-DLcQGI92.js → bot-BF_xIOxu.js} +1 -1
  97. package/web-app/dist/assets/{check-w0sBNlcm.js → check-Dv1Ynvrs.js} +1 -1
  98. package/web-app/dist/assets/{chevron-left-W7O0vC_m.js → chevron-left-Ddhsod7S.js} +1 -1
  99. package/web-app/dist/assets/{circle-alert-Cxjq9fxB.js → circle-alert-OATHUkBZ.js} +1 -1
  100. package/web-app/dist/assets/{clock-C8EqzmNl.js → clock-C1Ltva07.js} +1 -1
  101. package/web-app/dist/assets/{cloud-xNgp4g3Y.js → cloud-B-S4oOy9.js} +1 -1
  102. package/web-app/dist/assets/{code-xml-B-lyNDLJ.js → code-xml-D3Femn_F.js} +1 -1
  103. package/web-app/dist/assets/{database-DoW5lmWc.js → database-DBSeFgO3.js} +1 -1
  104. package/web-app/dist/assets/{dollar-sign-BcARA5sC.js → dollar-sign-sgDgNuGE.js} +1 -1
  105. package/web-app/dist/assets/{file-code-corner-CehcII0J.js → file-code-corner-C-MbdZEc.js} +1 -1
  106. package/web-app/dist/assets/{file-plus-DI9Zo5hP.js → file-plus-CCB6yqXv.js} +1 -1
  107. package/web-app/dist/assets/{globe-CiZWBk3H.js → globe-DlbrNAj1.js} +1 -1
  108. package/web-app/dist/assets/{hammer-3qv_T2N-.js → hammer-B-DWm695.js} +1 -1
  109. package/web-app/dist/assets/{index-gF9grAz-.js → index-Dvny-1SU.js} +3 -3
  110. package/web-app/dist/assets/{layers-CN7d0By9.js → layers-99qsKpOT.js} +1 -1
  111. package/web-app/dist/assets/{loader-circle-DywcM-im.js → loader-circle-ZvZyZl3J.js} +1 -1
  112. package/web-app/dist/assets/{lock-_hdSmkU4.js → lock-DosGjcxP.js} +1 -1
  113. package/web-app/dist/assets/{package-BV5zgqxJ.js → package-C-PumesN.js} +1 -1
  114. package/web-app/dist/assets/{plus-CU_Hh4-x.js → plus-CTYYskTB.js} +1 -1
  115. package/web-app/dist/assets/{refresh-cw-DMK-fNl-.js → refresh-cw-qW2ztTFS.js} +1 -1
  116. package/web-app/dist/assets/{rotate-ccw-CEB3_v5_.js → rotate-ccw-ZIKrf-vO.js} +1 -1
  117. package/web-app/dist/assets/{scroll-text-BSdXxcRN.js → scroll-text-BamlXjAT.js} +1 -1
  118. package/web-app/dist/assets/{server-CAMlP1yJ.js → server-BljXb79I.js} +1 -1
  119. package/web-app/dist/assets/{shield-alert-B-r1Dt3h.js → shield-alert-Dr6eT9c_.js} +1 -1
  120. package/web-app/dist/assets/{thumbs-up-CYfxw9o4.js → thumbs-up-v3oBXZgU.js} +1 -1
  121. package/web-app/dist/assets/{trash-2-DX3nGPS8.js → trash-2-BOuIrCpi.js} +1 -1
  122. package/web-app/dist/assets/{trending-down-Bt-hSntd.js → trending-down-Dp7jMCgH.js} +1 -1
  123. package/web-app/dist/assets/{trending-up-DVSlvQp8.js → trending-up-CDiur-nP.js} +1 -1
  124. package/web-app/dist/assets/{upload-D45RRHAP.js → upload-DxIHXhNE.js} +1 -1
  125. package/web-app/dist/assets/{usePolling-fq_Xj8iw.js → usePolling-D2Uu-YZb.js} +1 -1
  126. package/web-app/dist/assets/{user-BWcJkLlr.js → user-BVWCUAfF.js} +1 -1
  127. package/web-app/dist/index.html +1 -1
  128. package/packages/control-plane/src/server/actions.ts +0 -60
  129. package/packages/control-plane/ui/dist/assets/index-CUQ65vJY.css +0 -1
  130. package/packages/control-plane/ui/dist/assets/index-CwwGfp6E.js +0 -129
package/README.md CHANGED
@@ -303,6 +303,7 @@ A local control plane and UI for many runs, on by default. Turn it off with `LOK
303
303
  loki control serve # 127.0.0.1, default port 47821 (--port N, --db PATH)
304
304
  loki control backfill . # ship ./.loki/runs to the control plane
305
305
  loki control status # reachable? how many runs held?
306
+ loki control prune --repo acme/widget # remove those runs from the local control DB (--before DATE, --dry-run)
306
307
  ```
307
308
 
308
309
  The URL comes from `LOKI_CONTROL_URL`, else `http://127.0.0.1:${LOKI_CONTROL_PORT:-47821}`. While `loki control serve` is running, runs on this machine ship to it automatically (it publishes `~/.loki/control/instance.json`, mode 0600, removed on exit); a run never starts the server. Set `LOKI_CONTROL_URL` to ship elsewhere. See [docs/v10/CONTROL-PLANE.md](docs/v10/CONTROL-PLANE.md).
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: An autonomous software factory that knows what it is supposed to deliver, and proves it did. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
4
4
  ---
5
5
 
6
- # Loki Mode v10.7.0
6
+ # Loki Mode v10.8.0
7
7
 
8
8
  **Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the legacy engine, which still ships and is being removed (`loki start owner/repo#N` still routes to it; prefer `loki owner/repo#N`).
9
9
 
@@ -473,4 +473,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
473
473
 
474
474
  ---
475
475
 
476
- **v10.7.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
476
+ **v10.8.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 10.7.0
1
+ 10.8.0
package/autonomy/loki CHANGED
@@ -1981,6 +1981,9 @@ _loki_control_ui() {
1981
1981
  echo "loki: the Control Plane needs bun (https://bun.sh); using the classic dashboard." >&2
1982
1982
  return 1
1983
1983
  fi
1984
+ # FC-07: LOKI_CONTROL=0 is the test off switch (supervisor, run-all-tests, local-ci);
1985
+ # it must never start a detached `control serve` that writes ~/.loki/control.
1986
+ [ "${LOKI_CONTROL:-}" = "0" ] && return 1
1984
1987
  local cli="$SKILL_DIR/loki-ts/dist/loki.js" cdir="${HOME}/.loki/control" spid
1985
1988
  [ -f "$cli" ] || cli="$SKILL_DIR/loki-ts/src/cli.ts"
1986
1989
  mkdir -p "$cdir" && chmod 700 "$cdir" 2>/dev/null || true
@@ -21331,7 +21334,7 @@ tokens_per_tier = {
21331
21334
  pricing = {
21332
21335
  'Fable': {'input': 10.00, 'output': 50.00},
21333
21336
  'Opus': {'input': 5.00, 'output': 25.00},
21334
- 'Sonnet': {'input': 3.00, 'output': 15.00},
21337
+ 'Sonnet': {'input': 2.00, 'output': 10.00},
21335
21338
  'Haiku': {'input': 1.00, 'output': 5.00},
21336
21339
  }
21337
21340
 
package/autonomy/run.sh CHANGED
@@ -7581,7 +7581,7 @@ _write_pricing_json() {
7581
7581
  "fable": {"input": 10.00, "output": 50.00, "label": "Fable 5 (top, 2x Opus)", "provider": "claude"},
7582
7582
  "claude-fable-5": {"input": 10.00, "output": 50.00, "label": "Fable 5 (top, 2x Opus)", "provider": "claude"},
7583
7583
  "opus": {"input": 5.00, "output": 25.00, "label": "Opus (latest)", "provider": "claude"},
7584
- "sonnet": {"input": 3.00, "output": 15.00, "label": "Sonnet (latest)", "provider": "claude"},
7584
+ "sonnet": {"input": 2.00, "output": 10.00, "label": "Sonnet (latest)", "provider": "claude"},
7585
7585
  "haiku": {"input": 1.00, "output": 5.00, "label": "Haiku (latest)", "provider": "claude"},
7586
7586
  "gpt-5.3-codex": {"input": 1.75, "output": 14.00, "label": "GPT-5.3 Codex", "provider": "codex"}
7587
7587
  }
@@ -20250,7 +20250,7 @@ pricing = {
20250
20250
  'fable': {'input': 10.00, 'output': 50.00},
20251
20251
  'claude-fable-5': {'input': 10.00, 'output': 50.00},
20252
20252
  'opus': {'input': 5.00, 'output': 25.00},
20253
- 'sonnet': {'input': 3.00, 'output': 15.00},
20253
+ 'sonnet': {'input': 2.00, 'output': 10.00},
20254
20254
  'haiku': {'input': 1.00, 'output': 5.00},
20255
20255
  'gpt-5.3-codex': {'input': 1.75, 'output': 14.00},
20256
20256
  'gpt-5.6-sol': {'input': 2.50, 'output': 20.00},
@@ -24828,10 +24828,14 @@ except Exception:
24828
24828
  if [[ "${ENABLE_DASHBOARD:-true}" == "true" ]] && command -v curl &>/dev/null; then
24829
24829
  local project_cwd
24830
24830
  project_cwd="$(pwd)"
24831
- curl -sf -X POST "http://127.0.0.1:${DASHBOARD_PORT}/api/focus" \
24831
+ # CPE-24: the Control Plane answers 501 (no focus API). Best-effort; say so
24832
+ # honestly in debug output rather than treating the miss as an error.
24833
+ _focus_code="$(curl -s -o /dev/null -w '%{http_code}' -X POST "http://127.0.0.1:${DASHBOARD_PORT}/api/focus" \
24832
24834
  -H "Content-Type: application/json" \
24833
- -d "{\"project_dir\": \"${project_cwd}\"}" \
24834
- >/dev/null 2>&1 || true
24835
+ -d "{\"project_dir\": \"${project_cwd}\"}" 2>/dev/null || true)"
24836
+ case "$_focus_code" in
24837
+ 501|410) type log_debug >/dev/null 2>&1 && log_debug "project focus: not available on the Control Plane (HTTP ${_focus_code})" ;;
24838
+ esac
24835
24839
  fi
24836
24840
 
24837
24841
  # Initialize Cross-Provider Failover (v6.19.0)
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "10.7.0"
10
+ __version__ = "10.8.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -7752,7 +7752,7 @@ _DEFAULT_PRICING = {
7752
7752
  "fable": {"input": 10.00, "output": 50.00},
7753
7753
  "claude-fable-5": {"input": 10.00, "output": 50.00},
7754
7754
  "opus": {"input": 5.00, "output": 25.00},
7755
- "sonnet": {"input": 3.00, "output": 15.00},
7755
+ "sonnet": {"input": 2.00, "output": 10.00},
7756
7756
  "haiku": {"input": 1.00, "output": 5.00},
7757
7757
  # OpenAI Codex
7758
7758
  "gpt-5.3-codex": {"input": 1.50, "output": 12.00},
@@ -8587,18 +8587,16 @@ _PROVIDER_LABELS = {
8587
8587
  }
8588
8588
 
8589
8589
  # Display-only pricing notes, keyed by model. These annotate the pricing table in
8590
- # the UI WITHOUT changing any computed cost number. The Sonnet 5 launch carries an
8591
- # intro price ($2/$10 per MTok through Aug 31 2026), but the cost estimator keeps
8592
- # quoting the standard $3/$15 rate: over-estimating the display is the safe
8593
- # direction (a bill can only come in lower than quoted, never higher). This note
8594
- # tells the user why the quote is conservative during the intro window.
8590
+ # the UI WITHOUT changing any computed cost number. The Sonnet 5 intro price
8591
+ # ($2/$10 per MTok) became the standard price, so the 2026-09-01 increase to
8592
+ # $3/$15 will not occur (platform.claude.com pricing page, read 2026-10-03).
8595
8593
  _UNVERIFIED_RATE_NOTE = (
8596
8594
  "Unverified placeholder rate, scaled from gpt-5.3; not from OpenAI's pricing page."
8597
8595
  )
8598
8596
  _MODEL_PRICING_NOTES = {
8599
8597
  "sonnet": (
8600
- "Intro pricing: $2 / $10 per MTok through Aug 31 2026. "
8601
- "Estimates use the standard $3 / $15 rate (conservative)."
8598
+ "Standard pricing: $2 / $10 per MTok. "
8599
+ "The intro price became the standard price; no increase to $3 / $15."
8602
8600
  ),
8603
8601
  # See the UNVERIFIED RATES comment on the pricing table: shown, not hidden.
8604
8602
  "gpt-5.6-sol": _UNVERIFIED_RATE_NOTE,
@@ -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.7.0
5
+ **Version:** v10.8.0
6
6
 
7
7
  **Engine note:** `loki "<task>"`, `loki owner/repo#N` and `loki quick` run the Loki 10 engine. `loki start` still routes to the legacy engine, which is being removed (planned work resumes 2026-10-07); prefer `loki owner/repo#N`. See [docs/v10/GUIDE.md](v10/GUIDE.md).
8
8
 
@@ -46,6 +46,7 @@ Architect design, 2026-10-01, base 1dfc87103. Design only. Flag: `LOKI_CONTROL=1
46
46
  - events.jsonl is the spool. The shipper never writes to it (the supervisor treats outside writes as tamper). Its acked cursor lives in `.loki/runs/<id>/ship.json {acked_seq, url}`, written atomically.
47
47
  - Started by the supervisor next to the log (one hook line, skipped when `LOKI_CONTROL=0`; the url comes from `LOKI_CONTROL_URL` or local discovery, section 6), it uses `tail()` (events.ts:155), batches up to 200 events or 1 s, and POSTs. Backoff 1, 2, 4 ... 60 s with jitter. It never blocks or fails the run: on supervisor exit it flushes for at most 5 s, then leaves the rest for replay.
48
48
  - Every string in `data` goes through `redactSecrets` before sending.
49
+ - Cleanup: `loki control prune --repo OWNER/NAME` and/or `--before ISO_DATE` (`--dry-run` previews) deletes matching runs, their events and orphaned sources in one transaction, direct on the SQLite file (WAL, 5 s busy timeout), so it works with the server up or down. `DELETE /v1/runs/:source/:run` (JSON content type, same-host Origin, bearer when a token is set) removes one run and writes an `audit` row first; the UI Run detail page has a Remove button with a confirm step.
49
50
  - Replay: `loki control backfill [--repo DIR]` and every `loki` start ship each run whose ship.json acked_seq is below its last seq. Backfill of old .loki/runs uses the same code path.
50
51
 
51
52
  ## 6. Local discovery (on by default)
@@ -111,3 +112,9 @@ A run blocked on a spec conflict shows its question in the run view with an answ
111
112
  `loki answer [<run-id>] [--text "..."]` reads the run's task and question from `.loki/runs/<run>/events.jsonl` and the answer from `--text` or the answer file above, then launches `bin/loki "<task>\n\nClarification answering \"<question>\": <answer>"` and prints the new run id. The default run is the newest BLOCKED run in the current repo. The child env drops every `SLACK_*` variable and `LOKI_CONTROL_TOKEN` and sets `LOKI_NO_BROWSER=1`. A run that is not BLOCKED, or has no answer, exits 2 with the reason.
112
113
 
113
114
  `LOKI_CONTROL_DEFAULT=1` (off by default) makes `loki dashboard` open the Control Plane.
115
+
116
+ ### Integrity and the display verdict (D86, FC-08)
117
+
118
+ Ingest runs a pure verifier (`src/server/integrity.ts`) over every stored run and persists `tampered`, `attested`, `sig_checked` and `integrity_reasons`. Only the sealed prefix (events through `log.sealed`) supplies the verdict; a second `run.completed`, or any verdict-bearing event after `log.sealed`, is TAMPERED. The `log.sealed` kid must equal the signed receipt kid, and with keys configured an unknown kid is TAMPERED.
119
+
120
+ Display verdicts (`effective_verdict`, mirrored by `ui/src/api.ts`): TAMPERED; UNVERIFIED (a VERIFIED claim that is not attested, or a log redacted before ingest); "VERIFIED (signature not checked)" (attested, but no key in `LOKI_CP_RECEIPT_PUBKEYS` checked the seal signature); VERIFIED (attested and signature-checked). With no keys configured nothing can be plain VERIFIED. Choice for the list filter: `?verdict=VERIFIED` lists signature-checked runs only; `?verdict=VERIFIED (signature not checked)` lists the rest. ALREADY_SATISFIED is a success outcome and needs a seal exactly like VERIFIED (same UNVERIFIED and signature-not-checked rules). Any other verdict on an unattested run shows `<verdict> (unattested)`, so an edited or redacted FAILED or PARTIAL never reads as plain. The Overview VERIFIED tile counts only plain VERIFIED; a separate tile counts signature-not-checked runs. Rows are recomputed at boot in chunks (one transaction each) when attested is NULL or the stored key-set fingerprint (`integrity_key_fp`) differs from the configured one; rows whose events are gone are marked unattested once and not retried.
@@ -230,13 +230,274 @@ Gap: the server stores events only. Artifacts live in the local repo, and source
230
230
 
231
231
  Every mutating endpoint: requires the bearer token when the server is not loopback-only, refuses non-JSON bodies, checks Origin against the served host, writes an audit row before acting, and returns the resulting state for optimistic reconciliation.
232
232
 
233
- ## 5. Parity checklist (gate for CPE-24)
233
+ ## 5. Legacy integration contract (gate for CPE-24)
234
+
235
+ The legacy dashboard (dashboard/server.py, port 57374, 13194 lines) serves 234 routes (method and path entries after dropping HEAD; routers api_v2 at /api/v2, api_operator at /api/operator, api_start, api_runs_v1 at /api/v1/runs, the /lab and /assets mounts, WS /ws and /ws/collab). Deleting it (CPE-24) must not break a real integration. This section is the contract: one row per route, what consumes it, what the Control Plane offers, and what the shim at packages/control-plane/src/server/legacy/ does with it.
236
+
237
+ Method. Route list: FastAPI introspection of `dashboard.server.app` (the 234 entries). Consumers: a repo-wide text scan of git-tracked files, then each used route's consumer lines were read by hand. Counted as a consumer: the TypeScript and Python SDKs, vscode-extension (src and the bundled media/loki-dashboard.js webview), autonomy/loki and autonomy/run.sh, web-app, .github/workflows, tests/moat, tests/e2e, tests/integration, scripts/run-dashboard-* (marked "(test)" when a test). Not counted: dashboard/ itself, dashboard-ui/ (the legacy UI is deleted with the server), docs, generated maps, packages/control-plane. The scan matches path text, so single-segment paths (/start, /cost, /trust, /) were checked by hand: every hit was `loki start`, `/api/cost` or `/lab/api/cost`, none a request to that HTML route. Limits: a path built at runtime from parts is invisible to a text scan, and an HTTP verb is inferred from the nearby call text, so a verb on a bundled-JS row is best effort. A route with a consumer is USED, otherwise UNUSED.
238
+
239
+ Status values: EXISTS (the CP serves it today), PARTIAL (the shim maps it and says what differs), MISSING (a USED route the CP has no data or mechanism for), UNUSED (no consumer). Shim actions: map (answer from CP data), 308 to CP UI (HTML page), 410 with notice (UNUSED, retired), 501 not yet supported (USED but no CP data or mechanism: the shim answers an explicit 501, never a faked success), none (the CP already serves the path).
240
+
241
+ Counts: map 6, 308 5, 501 77, 410 142, none 4; total 234.
242
+
243
+ Auth contract (never looser than legacy). Legacy `require_scope` is open when LOKI_ENTERPRISE_AUTH and OIDC are both off, and otherwise answers 401 without a token and 403 on a missing scope. Open in every mode: /health, /.well-known/agent.json, /api/enterprise/status, /api/auth/info, /api/providers/models, /metrics, the docs routes. The shim applies one rule to every route the legacy server guarded: if LOKI_CONTROL_TOKEN is set, require the CP bearer token (401 with www-authenticate otherwise); if no CP token is set but legacy enterprise auth or OIDC is enabled in the environment, fail closed with 401 (the CP has no way to check the legacy `loki_*` tokens); if neither is set, open, matching the legacy default. The CP token carries every scope, which is safe because the shim exposes only read routes and answers 501 or 410 for the rest. 501 and 410 answers are also behind the guard, so an unauthenticated caller learns nothing about a guarded route. The shim never binds a port; mounting it on the CP app keeps hostGuard and the loopback-only action routes exactly as they are.
244
+
245
+ First hit per process, each route logs one line: `legacy dashboard route <path> is served by the Control Plane; migrate to /v1/...` (mapped and 308 routes). A 501 or 410 route logs the same single line in the words "is not served by the Control Plane (501)" or "is retired (410)".
246
+
247
+ ### 5.1 Parity checklist (gate for CPE-24)
234
248
  1. Every row of section 1 marked KEEP or REWORK has its v10 home rendered on real data, proven by a UI test with a fixture run.
235
249
  2. Every row of section 3.3 not marked DEFERRED works end to end in tests/e2e (start a fixture run, stream, BLOCKED answer, stop, retry, verify, config write).
236
250
  3. Visual parity: screenshots of wordmark, nav, card, KPI, badge, table in light and dark compared against legacy captures (CPE-23).
237
251
  4. No route under the old dashboard is reachable except the CP-LEGACY redirects (7b701d238).
238
252
  5. Lighthouse accessibility at or above 95 on composer, thread, Home; axe zero serious violations.
239
253
 
254
+
255
+ ### 5.2 Route contract
256
+
257
+ | Method and path | Consumers (verified file:line) | CP /v1 equivalent | Status | Shim action |
258
+ |---|---|---|---|---|
259
+ | GET `/openapi.json` | none | none | UNUSED | 410 with notice |
260
+ | GET `/docs` | none | none | UNUSED | 410 with notice |
261
+ | GET `/docs/oauth2-redirect` | none | none | UNUSED | 410 with notice |
262
+ | GET `/redoc` | none | none | UNUSED | 410 with notice |
263
+ | POST `/api/v2/tenants` | sdk/python/loki_mode_sdk/client.py:204, sdk/typescript/src/client.ts:237 | none | MISSING | 501 not yet supported |
264
+ | GET `/api/v2/tenants` | sdk/python/loki_mode_sdk/client.py:191, sdk/typescript/src/client.ts:225 | none | MISSING | 501 not yet supported |
265
+ | GET `/api/v2/tenants/{tenant_id}` | sdk/typescript/src/client.ts:229 | none | MISSING | 501 not yet supported |
266
+ | PUT `/api/v2/tenants/{tenant_id}` | none | none | UNUSED | 410 with notice |
267
+ | DELETE `/api/v2/tenants/{tenant_id}` | sdk/typescript/src/client.ts:241 | none | MISSING | 501 not yet supported |
268
+ | GET `/api/v2/tenants/{tenant_id}/projects` | none | none | UNUSED | 410 with notice |
269
+ | POST `/api/v2/runs` | vscode-extension/media/loki-dashboard.js:9617 | none | MISSING | 501 not yet supported |
270
+ | GET `/api/v2/runs` | sdk/python/loki_mode_sdk/client.py:220, sdk/typescript/src/client.ts:201 | /v1/runs | PARTIAL (ids are source:run strings, not ints; no project_id filter; status maps to running/completed; limit/offset map to limit/cursor) | map |
271
+ | GET `/api/v2/runs/{run_id}` | sdk/python/loki_mode_sdk/client.py:228, sdk/typescript/src/client.ts:205 | /v1/runs/:id | PARTIAL (run_id is source:run (URL-encoded) or a bare run id; legacy integer ids answer 404) | map |
272
+ | POST `/api/v2/runs/{run_id}/cancel` | sdk/python/loki_mode_sdk/client.py:233, sdk/typescript/src/client.ts:209, vscode-extension/media/loki-dashboard.js:9617 | none | MISSING | 501 not yet supported |
273
+ | POST `/api/v2/runs/{run_id}/replay` | sdk/python/loki_mode_sdk/client.py:238, sdk/typescript/src/client.ts:213, vscode-extension/media/loki-dashboard.js:9617 | none | MISSING | 501 not yet supported |
274
+ | GET `/api/v2/runs/{run_id}/timeline` | sdk/python/loki_mode_sdk/client.py:243, sdk/typescript/src/client.ts:217, vscode-extension/media/loki-dashboard.js:9255 | /v1/runs/:id (stages, events) | PARTIAL (phases are CP stages; events carry seq, ts, type, stage only) | map |
275
+ | POST `/api/v2/api-keys` | sdk/python/loki_mode_sdk/client.py:263, sdk/typescript/src/client.ts:178, vscode-extension/media/loki-dashboard.js:10097 | none | MISSING | 501 not yet supported |
276
+ | GET `/api/v2/api-keys` | sdk/python/loki_mode_sdk/client.py:253, sdk/typescript/src/client.ts:170 | none | MISSING | 501 not yet supported |
277
+ | GET `/api/v2/api-keys/{identifier}` | none | none | UNUSED | 410 with notice |
278
+ | PUT `/api/v2/api-keys/{identifier}` | none | none | UNUSED | 410 with notice |
279
+ | DELETE `/api/v2/api-keys/{identifier}` | sdk/typescript/src/client.ts:190, vscode-extension/media/loki-dashboard.js:10097 | none | MISSING | 501 not yet supported |
280
+ | POST `/api/v2/api-keys/{identifier}/rotate` | sdk/python/loki_mode_sdk/client.py:271, sdk/typescript/src/client.ts:186, vscode-extension/media/loki-dashboard.js:10097 | none | MISSING | 501 not yet supported |
281
+ | GET `/api/v2/policies` | none | none | UNUSED | 410 with notice |
282
+ | PUT `/api/v2/policies` | none | none | UNUSED | 410 with notice |
283
+ | POST `/api/v2/policies/evaluate` | none | none | UNUSED | 410 with notice |
284
+ | GET `/api/v2/audit` | sdk/python/loki_mode_sdk/client.py:293, sdk/typescript/src/client.ts:254, vscode-extension/media/loki-dashboard.js:9813 | /v1/audit (added by the shim) | PARTIAL (CP audit is an operator-action log (run removal, prune), not the legacy hash-chained log; resource_type filter answers 400) | map |
285
+ | GET `/api/v2/audit/verify` | tests/moat/p2-honest-verdict.sh:1162 (test), tests/moat/p2-honest-verdict.sh:1258 (test), vscode-extension/media/loki-dashboard.js:9813 | none | MISSING | 501 not yet supported |
286
+ | GET `/api/v2/audit/export` | none | /v1/audit | UNUSED | 410 with notice |
287
+ | GET `/api/operator/runs/{run_id}` | none | /v1/runs/:id | UNUSED | 410 with notice |
288
+ | GET `/api/operator/tests` | none | none | UNUSED | 410 with notice |
289
+ | GET `/api/operator/receipts` | none | none | UNUSED | 410 with notice |
290
+ | GET `/api/operator/releases` | none | none | UNUSED | 410 with notice |
291
+ | GET `/api/operator/phases` | none | none | UNUSED | 410 with notice |
292
+ | GET `/api/operator/workspaces/runs` | none | none | UNUSED | 410 with notice |
293
+ | GET `/api/operator/workspaces/runs/{ws}/{run_id}` | none | none | UNUSED | 410 with notice |
294
+ | GET `/api/onboarding/state` | none | none | UNUSED | 410 with notice |
295
+ | POST `/api/onboarding/provider` | none | none | UNUSED | 410 with notice |
296
+ | POST `/api/onboarding/github` | none | none | UNUSED | 410 with notice |
297
+ | GET `/api/onboarding/repos` | none | none | UNUSED | 410 with notice |
298
+ | POST `/api/onboarding/repo` | none | none | UNUSED | 410 with notice |
299
+ | GET `/api/backlog/issues` | none | none | UNUSED | 410 with notice |
300
+ | POST `/api/backlog/run` | none | none | UNUSED | 410 with notice |
301
+ | GET `/api/backlog/status` | none | none | UNUSED | 410 with notice |
302
+ | GET `/api/v1/runs` | none | /v1/runs | UNUSED | 410 with notice |
303
+ | GET `/api/v1/runs/{run_id}` | none | /v1/runs/:id | UNUSED | 410 with notice |
304
+ | POST `/api/v1/runs` | none | /v1/runs | UNUSED | 410 with notice |
305
+ | POST `/api/v1/runs/{run_id}/stop` | none | none | UNUSED | 410 with notice |
306
+ | GET `/start` | none | CP UI (/) | EXISTS | 308 to CP UI |
307
+ | MOUNT `/lab` | none | CP UI (/) | EXISTS | 308 to CP UI |
308
+ | GET `/health` | autonomy/loki:1929, autonomy/loki:7760, autonomy/run.sh:19293 (+10) | /health | EXISTS (CP /health answers {service, pid, install_path}, not the legacy body; CLI discovery relies on that identity, so the shim never overrides it) | none (CP /health serves) |
309
+ | GET `/api/providers/models` | none | none | UNUSED | 410 with notice |
310
+ | GET `/.well-known/agent.json` | .github/workflows/integrity-audit.yml:114, .github/workflows/integrity-audit.yml:115 | none (static card) | PARTIAL (static card from shim constants; capabilities the CP cannot back (streaming, enterprise rbac/multi-tenant) are false) | map |
311
+ | GET `/api/status` | autonomy/loki:15601, autonomy/run.sh:19357, autonomy/run.sh:19541 (+10) | /v1/runs (derived) | PARTIAL (status, version, uptime, active_sessions, phase, provider only; no running_agents, pending_tasks, iteration, complexity, mode, current_task (CP has no such data, fields omitted)) | map |
312
+ | GET `/api/projects` | sdk/python/loki_mode_sdk/client.py:166, sdk/typescript/src/client.ts:127, tests/moat/p7-no-fabricated-data.sh:446 (test) | none | MISSING | 501 not yet supported |
313
+ | POST `/api/projects` | sdk/python/loki_mode_sdk/client.py:184, sdk/typescript/src/client.ts:139, tests/moat/p7-no-fabricated-data.sh:437 (test) (+1) | none | MISSING | 501 not yet supported |
314
+ | GET `/api/projects/{project_id}` | sdk/python/loki_mode_sdk/client.py:174, sdk/typescript/src/client.ts:131 | none | MISSING | 501 not yet supported |
315
+ | PUT `/api/projects/{project_id}` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
316
+ | DELETE `/api/projects/{project_id}` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
317
+ | GET `/api/tasks` | sdk/python/loki_mode_sdk/tasks.py:30, sdk/typescript/src/client.ts:150 | none | MISSING | 501 not yet supported |
318
+ | POST `/api/tasks` | sdk/python/loki_mode_sdk/tasks.py:56, sdk/typescript/src/client.ts:162, vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
319
+ | GET `/api/tasks/{task_id}` | sdk/python/loki_mode_sdk/tasks.py:38, sdk/typescript/src/client.ts:154, vscode-extension/src/views/dashboardWebview.ts:168 | none | MISSING | 501 not yet supported |
320
+ | PUT `/api/tasks/{task_id}` | sdk/python/loki_mode_sdk/tasks.py:71, vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
321
+ | DELETE `/api/tasks/{task_id}` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
322
+ | POST `/api/tasks/{task_id}/move` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
323
+ | WS `/ws` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
324
+ | GET `/api/registry/projects` | none | none | UNUSED | 410 with notice |
325
+ | POST `/api/registry/projects` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
326
+ | GET `/api/registry/projects/{identifier}` | none | none | UNUSED | 410 with notice |
327
+ | DELETE `/api/registry/projects/{identifier}` | none | none | UNUSED | 410 with notice |
328
+ | GET `/api/registry/projects/{identifier}/health` | none | none | UNUSED | 410 with notice |
329
+ | POST `/api/registry/projects/{identifier}/access` | none | none | UNUSED | 410 with notice |
330
+ | GET `/api/registry/discover` | none | none | UNUSED | 410 with notice |
331
+ | POST `/api/registry/sync` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
332
+ | GET `/api/registry/tasks` | none | none | UNUSED | 410 with notice |
333
+ | GET `/api/registry/learnings` | none | none | UNUSED | 410 with notice |
334
+ | GET `/api/fleet/runs` | tests/moat/p7-no-fabricated-data.sh:4637 (test), tests/moat/p7-no-fabricated-data.sh:4706 (test), tests/moat/p7-no-fabricated-data.sh:4710 (test) (+1) | /v1/fleet/runs (CPE24-P1) | PARTIAL (reads the same .loki or registry source; unmeasured values are null with a not-measured marker) | map |
335
+ | GET `/api/fleet/summary` | tests/moat/p7-no-fabricated-data.sh:4637 (test), tests/moat/p7-no-fabricated-data.sh:4695 (test), tests/moat/p7-no-fabricated-data.sh:4696 (test) (+1) | /v1/fleet/summary (CPE24-P1) | PARTIAL (reads the same .loki or registry source; unmeasured values are null with a not-measured marker) | map |
336
+ | GET `/api/fleet/runs/{identifier}` | none | none | UNUSED | 410 with notice |
337
+ | POST `/api/focus` | autonomy/run.sh:24831, web-app/server.py:2744 | none | MISSING | 501 not yet supported |
338
+ | GET `/api/focus` | none | none | UNUSED | 410 with notice |
339
+ | DELETE `/api/focus` | none | none | UNUSED | 410 with notice |
340
+ | GET `/api/session/model` | none | none | UNUSED | 410 with notice |
341
+ | POST `/api/session/model` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
342
+ | GET `/api/running-projects` | none | none | UNUSED | 410 with notice |
343
+ | POST `/api/control/start` | vscode-extension/media/loki-dashboard.js:496, vscode-extension/src/api/client.ts:257, vscode-extension/src/extension.ts:580 | none | MISSING | 501 not yet supported |
344
+ | GET `/api/control/builds/{execution_id}` | none | none | UNUSED | 410 with notice |
345
+ | GET `/api/control/builds/{execution_id}/proof` | none | none | UNUSED | 410 with notice |
346
+ | POST `/api/control/builds/{execution_id}/stop` | none | none | UNUSED | 410 with notice |
347
+ | POST `/api/running-projects/stop` | none | none | UNUSED | 410 with notice |
348
+ | POST `/api/fleet/runs/{identifier}/retry` | none | none | UNUSED | 410 with notice |
349
+ | POST `/api/fleet/runs/{identifier}/cancel` | none | none | UNUSED | 410 with notice |
350
+ | GET `/api/enterprise/status` | none | none | UNUSED | 410 with notice |
351
+ | GET `/api/auth/info` | none | none | UNUSED | 410 with notice |
352
+ | POST `/api/enterprise/tokens` | none | none | UNUSED | 410 with notice |
353
+ | GET `/api/enterprise/tokens` | none | none | UNUSED | 410 with notice |
354
+ | DELETE `/api/enterprise/tokens/{identifier}` | none | none | UNUSED | 410 with notice |
355
+ | GET `/api/enterprise/audit` | none | none | UNUSED | 410 with notice |
356
+ | GET `/api/enterprise/audit/summary` | none | none | UNUSED | 410 with notice |
357
+ | GET `/api/compliance` | none | none | UNUSED | 410 with notice |
358
+ | GET `/api/memory/summary` | none | none | UNUSED | 410 with notice |
359
+ | GET `/api/memory/episodes` | vscode-extension/src/views/memoryViewProvider.ts:152 | none | MISSING | 501 not yet supported |
360
+ | GET `/api/memory/episodes/{episode_id}` | vscode-extension/src/views/dashboardWebview.ts:204, vscode-extension/src/views/memoryViewProvider.ts:215 | none | MISSING | 501 not yet supported |
361
+ | GET `/api/memory/patterns` | vscode-extension/src/views/memoryViewProvider.ts:151 | none | MISSING | 501 not yet supported |
362
+ | GET `/api/memory/patterns/{pattern_id}` | vscode-extension/src/views/dashboardWebview.ts:186, vscode-extension/src/views/memoryViewProvider.ts:197 | none | MISSING | 501 not yet supported |
363
+ | GET `/api/memory/skills` | vscode-extension/src/views/memoryViewProvider.ts:153 | none | MISSING | 501 not yet supported |
364
+ | GET `/api/memory/skills/{skill_id}` | none | none | UNUSED | 410 with notice |
365
+ | GET `/api/memory/economics` | tests/moat/p7-no-fabricated-data.sh:4638 (test), tests/moat/p7-no-fabricated-data.sh:4749 (test), tests/moat/p7-no-fabricated-data.sh:4750 (test) (+2) | none | MISSING | 501 not yet supported |
366
+ | POST `/api/memory/consolidate` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
367
+ | POST `/api/memory/retrieve` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
368
+ | GET `/api/memory/index` | none | none | UNUSED | 410 with notice |
369
+ | GET `/api/memory/timeline` | none | none | UNUSED | 410 with notice |
370
+ | GET `/api/memory/files` | none | none | UNUSED | 410 with notice |
371
+ | GET `/api/memory/file` | none | none | UNUSED | 410 with notice |
372
+ | GET `/api/memory/search` | none | none | UNUSED | 410 with notice |
373
+ | GET `/api/memory/stats` | none | none | UNUSED | 410 with notice |
374
+ | GET `/api/learning/metrics` | tests/moat/p7-no-fabricated-data.sh:4638 (test), tests/moat/p7-no-fabricated-data.sh:4752 (test) | none | MISSING | 501 not yet supported |
375
+ | GET `/api/learning/trends` | none | none | UNUSED | 410 with notice |
376
+ | GET `/api/learning/signals` | none | none | UNUSED | 410 with notice |
377
+ | GET `/api/learning/aggregation` | none | none | UNUSED | 410 with notice |
378
+ | POST `/api/learning/aggregate` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
379
+ | GET `/api/learning/preferences` | none | none | UNUSED | 410 with notice |
380
+ | GET `/api/learning/errors` | none | none | UNUSED | 410 with notice |
381
+ | GET `/api/learning/success` | none | none | UNUSED | 410 with notice |
382
+ | GET `/api/learning/tools` | none | none | UNUSED | 410 with notice |
383
+ | POST `/api/control/pause` | vscode-extension/media/loki-dashboard.js:496, vscode-extension/src/api/client.ts:277, vscode-extension/src/extension.ts:703 | none | MISSING | 501 not yet supported |
384
+ | POST `/api/control/resume` | vscode-extension/media/loki-dashboard.js:496, vscode-extension/src/api/client.ts:285, vscode-extension/src/extension.ts:743 | none | MISSING | 501 not yet supported |
385
+ | POST `/api/control/stop` | vscode-extension/media/loki-dashboard.js:496, vscode-extension/src/api/client.ts:269, vscode-extension/src/extension.ts:651 | none | MISSING | 501 not yet supported |
386
+ | GET `/api/cost` | tests/moat/p7-no-fabricated-data.sh:4637 (test), tests/moat/p7-no-fabricated-data.sh:4646 (test), tests/moat/p7-no-fabricated-data.sh:4647 (test) (+3) | /v1/cost/snapshot (CPE24-P1) | PARTIAL (reads the same .loki or registry source; unmeasured values are null with a not-measured marker) | map |
387
+ | GET `/api/budget` | tests/e2e/dashboard-evidence-panels.mjs:73 (test), tests/moat/p7-no-fabricated-data.sh:4637 (test), tests/moat/p7-no-fabricated-data.sh:4650 (test) (+3) | none | MISSING | 501 not yet supported |
388
+ | GET `/api/cost/timeline` | tests/moat/p7-no-fabricated-data.sh:4637 (test), tests/moat/p7-no-fabricated-data.sh:4652 (test), tests/moat/p7-no-fabricated-data.sh:4653 (test) (+15) | /v1/cost/timeline (CPE24-P1) | PARTIAL (reads the same .loki or registry source; unmeasured values are null with a not-measured marker) | map |
389
+ | GET `/api/trust/trajectory` | none | none | UNUSED | 410 with notice |
390
+ | GET `/api/gate-policy` | none | none | UNUSED | 410 with notice |
391
+ | GET `/api/pricing` | none | none | UNUSED | 410 with notice |
392
+ | GET `/api/council/state` | none | none | UNUSED | 410 with notice |
393
+ | GET `/api/council/verdicts` | none | none | UNUSED | 410 with notice |
394
+ | GET `/api/council/convergence` | none | none | UNUSED | 410 with notice |
395
+ | GET `/api/council/report` | none | none | UNUSED | 410 with notice |
396
+ | POST `/api/council/force-review` | vscode-extension/media/loki-dashboard.js:496, vscode-extension/media/loki-dashboard.js:4312 | none | MISSING | 501 not yet supported |
397
+ | GET `/api/council/transcripts` | vscode-extension/media/loki-dashboard.js:12426 | none | MISSING | 501 not yet supported |
398
+ | GET `/api/council/transcripts/{iteration_id}` | none | none | UNUSED | 410 with notice |
399
+ | GET `/api/context` | tests/moat/p7-no-fabricated-data.sh:4638 (test), tests/moat/p7-no-fabricated-data.sh:4745 (test), tests/moat/p7-no-fabricated-data.sh:4746 (test) (+3) | none | MISSING | 501 not yet supported |
400
+ | GET `/api/notifications` | none | none | UNUSED | 410 with notice |
401
+ | GET `/api/notifications/triggers` | none | none | UNUSED | 410 with notice |
402
+ | PUT `/api/notifications/triggers` | vscode-extension/media/loki-dashboard.js:496, vscode-extension/media/loki-dashboard.js:6802 | none | MISSING | 501 not yet supported |
403
+ | POST `/api/notifications/{notification_id}/acknowledge` | none | none | UNUSED | 410 with notice |
404
+ | POST `/api/notifications/{notification_id}/unacknowledge` | none | none | UNUSED | 410 with notice |
405
+ | GET `/api/checkpoints` | vscode-extension/src/views/checkpointProvider.ts:108, vscode-extension/src/views/checkpointProvider.ts:134 | none | MISSING | 501 not yet supported |
406
+ | GET `/api/checkpoints/{checkpoint_id}` | none | none | UNUSED | 410 with notice |
407
+ | POST `/api/checkpoints` | vscode-extension/media/loki-dashboard.js:5960 | none | MISSING | 501 not yet supported |
408
+ | POST `/api/checkpoints/{checkpoint_id}/rollback` | vscode-extension/media/loki-dashboard.js:5960 | none | MISSING | 501 not yet supported |
409
+ | GET `/api/agents` | none | none | UNUSED | 410 with notice |
410
+ | POST `/api/agents/{agent_id}/kill` | vscode-extension/media/loki-dashboard.js:4312 | none | MISSING | 501 not yet supported |
411
+ | POST `/api/agents/{agent_id}/pause` | vscode-extension/media/loki-dashboard.js:4312 | none | MISSING | 501 not yet supported |
412
+ | POST `/api/agents/{agent_id}/resume` | vscode-extension/media/loki-dashboard.js:4312 | none | MISSING | 501 not yet supported |
413
+ | GET `/api/logs` | none | none | UNUSED | 410 with notice |
414
+ | POST `/api/collab/join` | none | none | UNUSED | 410 with notice |
415
+ | POST `/api/collab/leave` | none | none | UNUSED | 410 with notice |
416
+ | GET `/api/collab/users` | none | none | UNUSED | 410 with notice |
417
+ | GET `/api/collab/users/{user_id}` | none | none | UNUSED | 410 with notice |
418
+ | POST `/api/collab/users/{user_id}/heartbeat` | none | none | UNUSED | 410 with notice |
419
+ | POST `/api/collab/users/{user_id}/cursor` | none | none | UNUSED | 410 with notice |
420
+ | POST `/api/collab/users/{user_id}/status` | none | none | UNUSED | 410 with notice |
421
+ | GET `/api/collab/presence` | none | none | UNUSED | 410 with notice |
422
+ | GET `/api/collab/file/{file_path:path}` | none | none | UNUSED | 410 with notice |
423
+ | GET `/api/collab/state` | none | none | UNUSED | 410 with notice |
424
+ | GET `/api/collab/state/value` | none | none | UNUSED | 410 with notice |
425
+ | POST `/api/collab/operation` | none | none | UNUSED | 410 with notice |
426
+ | POST `/api/collab/sync` | none | none | UNUSED | 410 with notice |
427
+ | GET `/api/collab/history` | none | none | UNUSED | 410 with notice |
428
+ | WS `/ws/collab` | none | none | UNUSED | 410 with notice |
429
+ | GET `/api/collab/status` | none | none | UNUSED | 410 with notice |
430
+ | GET `/api/secrets/status` | none | none | UNUSED | 410 with notice |
431
+ | GET `/api/github/status` | none | none | UNUSED | 410 with notice |
432
+ | GET `/api/github/tasks` | none | none | UNUSED | 410 with notice |
433
+ | GET `/api/github/sync-log` | none | none | UNUSED | 410 with notice |
434
+ | GET `/api/health/processes` | none | none | UNUSED | 410 with notice |
435
+ | GET `/metrics` | autonomy/loki:29162, tests/e2e/webapp-admin-honesty.mjs:271 (test), tests/e2e/webapp-receipt-panel.mjs:54 (test) (+2) | /v1/metrics (CPE24-P1) | PARTIAL (reads the same .loki or registry source; unmeasured values are null with a not-measured marker) | map |
436
+ | GET `/api/checklist` | none | none | UNUSED | 410 with notice |
437
+ | GET `/api/usage` | none | none | UNUSED | 410 with notice |
438
+ | GET `/api/checklist/summary` | none | none | UNUSED | 410 with notice |
439
+ | GET `/api/prd-observations` | none | none | UNUSED | 410 with notice |
440
+ | GET `/api/checklist/waivers` | none | none | UNUSED | 410 with notice |
441
+ | POST `/api/checklist/waivers` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
442
+ | DELETE `/api/checklist/waivers/{item_id}` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
443
+ | GET `/api/council/gate` | tests/moat/p7-no-fabricated-data.sh:4638 (test), tests/moat/p7-no-fabricated-data.sh:4760 (test), tests/moat/p7-no-fabricated-data.sh:4762 (test) (+1) | none | MISSING | 501 not yet supported |
444
+ | GET `/api/app-runner/status` | none | none | UNUSED | 410 with notice |
445
+ | GET `/api/app-runner/logs` | none | none | UNUSED | 410 with notice |
446
+ | GET `/api/app-runner/errors` | none | none | UNUSED | 410 with notice |
447
+ | POST `/api/control/app-restart` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
448
+ | POST `/api/control/app-stop` | vscode-extension/media/loki-dashboard.js:496 | none | MISSING | 501 not yet supported |
449
+ | GET `/api/playwright/results` | none | none | UNUSED | 410 with notice |
450
+ | GET `/api/playwright/screenshot` | none | none | UNUSED | 410 with notice |
451
+ | GET `/api/failures` | none | none | UNUSED | 410 with notice |
452
+ | GET `/api/prompt-versions` | none | none | UNUSED | 410 with notice |
453
+ | POST `/api/prompt-optimize` | autonomy/loki:17793, vscode-extension/media/loki-dashboard.js:7581 | none | MISSING | 501 not yet supported |
454
+ | MOUNT `/assets` | none | UI static assets | EXISTS (vite output under ui/dist/assets) | none (CP UI serves it) |
455
+ | GET `/api/activity` | vscode-extension/media/loki-dashboard.js:8596 | none | MISSING | 501 not yet supported |
456
+ | GET `/api/session-diff` | none | none | UNUSED | 410 with notice |
457
+ | POST `/api/activity` | none | none | UNUSED | 410 with notice |
458
+ | GET `/favicon.svg` | none | UI static asset | EXISTS (the CP UI serves its own favicon from ui/dist) | none (CP UI serves it) |
459
+ | GET `/cost` | none | CP UI (/) | EXISTS | 308 to CP UI |
460
+ | GET `/trust` | none | CP UI (/) | EXISTS | 308 to CP UI |
461
+ | GET `/` | none | CP UI (/) | EXISTS | 308 to CP UI |
462
+ | GET `/api/quality-score` | none | none | UNUSED | 410 with notice |
463
+ | GET `/api/quality-score/history` | none | none | UNUSED | 410 with notice |
464
+ | POST `/api/quality-scan` | autonomy/loki:23927, vscode-extension/media/loki-dashboard.js:7832 | none | MISSING | 501 not yet supported |
465
+ | GET `/api/quality-report` | autonomy/loki:23994 | none | MISSING | 501 not yet supported |
466
+ | GET `/api/migration/list` | vscode-extension/media/loki-dashboard.js:8173 | none | MISSING | 501 not yet supported |
467
+ | POST `/api/migration/start` | none | none | UNUSED | 410 with notice |
468
+ | GET `/api/migration/{migration_id}/status` | vscode-extension/media/loki-dashboard.js:8173 | none | MISSING | 501 not yet supported |
469
+ | GET `/api/migration/{migration_id}/plan` | none | none | UNUSED | 410 with notice |
470
+ | GET `/api/migration/{migration_id}/features` | none | none | UNUSED | 410 with notice |
471
+ | GET `/api/migration/{migration_id}/seams` | none | none | UNUSED | 410 with notice |
472
+ | POST `/api/migration/{migration_id}/advance` | none | none | UNUSED | 410 with notice |
473
+ | POST `/api/migration/{migration_id}/start-phase` | none | none | UNUSED | 410 with notice |
474
+ | GET `/api/managed/events` | vscode-extension/media/loki-dashboard.js:11965 | none | MISSING | 501 not yet supported |
475
+ | GET `/api/managed/status` | tests/integration/test_dashboard_api_smoke.sh:105 (test), tests/integration/test_dashboard_api_smoke.sh:106 (test), vscode-extension/media/loki-dashboard.js:11965 | none | MISSING | 501 not yet supported |
476
+ | GET `/api/managed/memory_versions/{memory_id}` | none | none | UNUSED | 410 with notice |
477
+ | GET `/api/findings/{iteration}` | none | none | UNUSED | 410 with notice |
478
+ | GET `/api/quality/architecture` | none | none | UNUSED | 410 with notice |
479
+ | GET `/api/learnings` | tests/e2e/dashboard-evidence-panels.mjs:72 (test) | none | MISSING | 501 not yet supported |
480
+ | GET `/api/escalations` | vscode-extension/media/loki-dashboard.js:12356 | none | MISSING | 501 not yet supported |
481
+ | GET `/api/escalations/{filename}` | none | none | UNUSED | 410 with notice |
482
+ | GET `/api/phases` | none | none | UNUSED | 410 with notice |
483
+ | GET `/api/proofs` | tests/e2e/dashboard-evidence-panels.mjs:71 (test), tests/e2e/webapp-receipt-panel.mjs:75 (test), tests/e2e/webapp-receipt-panel.mjs:84 (test) | none | MISSING | 501 not yet supported |
484
+ | GET `/api/proofs/summary` | tests/e2e/webapp-receipt-panel.mjs:76 (test) | none | MISSING | 501 not yet supported |
485
+ | GET `/api/proofs/{run_id}` | tests/moat/p2-honest-verdict.sh:1251 (test) | none | MISSING | 501 not yet supported |
486
+ | GET `/api/proofs/{run_id}/html` | none | none | UNUSED | 410 with notice |
487
+ | GET `/api/spec` | none | none | UNUSED | 410 with notice |
488
+ | GET `/api/spec/history` | none | none | UNUSED | 410 with notice |
489
+ | GET `/api/wiki` | none | none | UNUSED | 410 with notice |
490
+ | GET `/api/wiki/{section}` | none | none | UNUSED | 410 with notice |
491
+ | POST `/api/wiki/ask` | vscode-extension/media/loki-dashboard.js:12595 | none | MISSING | 501 not yet supported |
492
+ | GET `/{full_path:path}` | none | SPA fallback | EXISTS (CP app.get("*") serves the SPA and 404s missing assets) | none (CP UI serves it) |
493
+
494
+ ### 5.3 Notes for the deletion gate
495
+
496
+ - Test consumers that block deleting the legacy routes (they run the Python app in process, so they need the routes or a rewrite): tests/moat/p2-honest-verdict.sh (GET /api/proofs/{run_id}, GET /api/v2/audit/verify) and tests/moat/p7-no-fabricated-data.sh (/api/status, /api/projects, /api/cost, /api/budget, /api/cost/timeline, /api/fleet/runs, /api/fleet/summary, /api/context, /api/memory/economics, /api/learning/metrics, /api/council/gate, /metrics). tests/e2e/dashboard-evidence-panels.mjs and webapp-receipt-panel.mjs read /api/proofs, /api/proofs/summary, /api/learnings, /api/budget. None of these may be weakened or added to tests/moat/pending.txt; CPE-24 must port the property each one proves before the route goes.
497
+ - Corrections to the inventory hints: tests/moat/p5-sovereignty.sh does not call /api/enterprise/status or /api/enterprise/tokens (it runs `loki start`, matched by the text `/start`); autonomy/loki does not call /api/control/start or /api/control/stop on the dashboard; the VS Code extension requests `/status`, which the legacy server never served (its catch-all answered HTML), so it is not a row.
498
+ - /api/memory/* and /api/learning/* are consumed by the VS Code memory view (src/views/memoryViewProvider.ts, dashboardWebview.ts) and the bundled webview, and p7 reads /api/memory/economics and /api/learning/metrics, so those that appear USED above are not deletable on the UI alone.
499
+ - /health: the CP /health identity ({service: "loki-control"}) is relied on by CLI discovery. Callers that probe the legacy /health body at port 57374 (autonomy/loki, autonomy/run.sh, web-app) need either a migrated probe or a separate listener; the shim does not add one.
500
+
240
501
  ## 6. STEP 2 slice plan
241
502
 
242
503
  Rules: one writer per file; UI pages register through ui/src/pages/registry.ts and server routes through src/server/routes/index.ts, both CREATED with stubs for every planned page and route by CPE-02 and CPE-03, so later slices only fill their own stub files. Wall checks run from packages/control-plane. HIGH = opus D12 review.
@@ -251,7 +512,7 @@ Rules: one writer per file; UI pages register through ui/src/pages/registry.ts a
251
512
  | CPE-06 | Run thread view: stage messages, live log, diff, evidence, receipt, NOT PROVEN, cost, PR, BLOCKED reply prompt, Details drawer; replaces Live.tsx | ui/src/pages/run/**, ui/src/Live.tsx (delete), test/ui/run.test.tsx | `bun test test/ui/run.test.tsx` (fixture run renders every section; missing cost shows "not measured") | 02, 04, 05 | MEDIUM |
252
513
  | CPE-07 | Start-run endpoint POST /v1/runs | src/server/routes/start.ts, src/server/spawn.ts, test/server/start.test.ts | `bun test test/server/start.test.ts` (unknown repo, shell metacharacters, unknown flag, missing token, bad Origin all refused; argv exact) | 03 | HIGH |
253
514
  | CPE-08 | New run composer: one input, chips, Cmd+Enter, optimistic session row, empty state | ui/src/pages/compose/**, test/ui/compose.test.tsx | `bun test test/ui/compose.test.tsx` | 02, 07 | MEDIUM |
254
- | CPE-09 | Run control: supervisor writes <run>/run.pid (pid, start time, argv); stop, retry, resume endpoints | loki-ts/src/engine10/run_pid.ts, loki-ts/src/engine10/supervisor.ts, src/server/routes/control.ts, test/server/control.test.ts, loki-ts/tests/engine10/run_pid.test.ts | `bun test test/server/control.test.ts` and `cd loki-ts && bun test tests/engine10/run_pid.test.ts` (stale pid, reused pid, other run's pid refused) | 03 | HIGH |
515
+ | CPE-09 | Run control: supervisor writes <run>/run.pid (pid, start time, argv); stop, retry, resume endpoints | loki-ts/src/util/run_pid.ts, loki-ts/src/engine10/supervisor.ts, src/server/routes/control.ts, test/server/control.test.ts, loki-ts/tests/engine10/run_pid.test.ts | `bun test test/server/control.test.ts` and `cd loki-ts && bun test tests/engine10/run_pid.test.ts` (stale pid, reused pid, other run's pid refused) | 03 | HIGH |
255
516
  | CPE-10 | Run control UI: Stop (confirm), Retry, Resume with optimistic state and rollback | ui/src/pages/run-controls/** (mounted in the run header slot CPE-06 provides), test/ui/controls.test.tsx | `bun test test/ui/controls.test.tsx` | 06, 09 | LOW |
256
517
  | CPE-11 | Runs table page with filters and group rollup | ui/src/pages/runs/**, test/ui/runs.test.tsx | `bun test test/ui/runs.test.tsx` | 02 | LOW |
257
518
  | CPE-12 | Home: /v1/stats plus KPI tiles, recent runs, BLOCKED inbox | src/server/routes/stats.ts, ui/src/pages/home/**, test/server/stats.test.ts, test/ui/home.test.tsx | `bun test test/server/stats.test.ts test/ui/home.test.tsx` (numbers equal a hand-folded fixture) | 02, 03 | MEDIUM |
@@ -673,3 +673,44 @@ Source: the founder's words, relayed by the peer session (autonomi-dev-76) at 14
673
673
  1. 10.7.0 ships the LOKI_SPEED default flip with the D82-FIXREDS fix. D82-WALL0 is reverted for 10.7.0 because it fails the engine e2e done run (the stub writes no Wall file, so the run seals FAILED); it returns in 10.7.1 with the e2e stub writing a Wall check.
674
674
  2. The quiet-mode LiveLine moves from engine10/output.ts to e10ext/liveline.ts: it is presentation, and core was 5026 lines against the D29 5,000 cap. The cap is unchanged.
675
675
  3. Control Plane settings API (CPE-14): shell command fields (workspaces.*.integration.command, workspaces.*.repos[].setup) are read-only over HTTP and return 422; they are edited in loki.yaml directly. A browser must never be able to plant a command the engine later runs.
676
+
677
+ ## D85 (2026-10-03 16:30Z, CoS per D68/D69): train/102 reds fixed in place, not dropped
678
+ 1. train/102 Tests failed on registration and pin defects only: acp missing from help and completions, merge missing from zsh completion, `loki web --port` skipping the port validator after CP-LEGACY, a ProcessEnv type lost in CP-INGEST watch.ts, and the E-123 gitleaks baseline count after the reviewed Sentry fixture fingerprint.
679
+ 2. Dropping ACP, merge, CP-LEGACY and CP-INGEST would remove four headline 10.7.0 features and needs four reverts plus a dist rebuild, which is slower and riskier than five one-line registration fixes. The peer's "drop, do not fix forward" rule targets behaviour regressions; these are wiring gaps. Fixed in d9704dfc4 and every failing suite was rerun locally green before train/103.
680
+ 3. `loki web` routes to the Control Plane only in its bare form (optionally --no-open); any other flag reaches the classic validator.
681
+
682
+ ## D86 (2026-10-03 17:00Z, founder via the steering session, CoS records): Engine Laws are the engine constitution
683
+ 1. Merges the steering session's earlier "D76" message (harness never worse than raw) with its later "ENGINE LAWS" directive. The label clashed with our D76, so both are recorded here under one number.
684
+ 2. Trigger: FireLater#17. Plain claude took about 2 min; Loki took 11 min and $2.66 and ended in a FAILED draft. Root causes are classes, not one-offs:
685
+ - testmap runs fixed commands from repoDir;
686
+ - scope.ts reverts edits on keyword overlap;
687
+ - sizing.ts cascade pins implement to sonnet;
688
+ - verify has no ERROR versus FAIL split;
689
+ - pr_body prints "not recorded" over real data;
690
+ - there is no terminal-state invariant across sinks.
691
+ 3. docs/v10/ENGINE-LAWS.md (L1 to L7) is binding for every stage, present and future:
692
+ - L1 never below raw;
693
+ - L2 fail closed on trust, fail open on work;
694
+ - L3 the authority ladder;
695
+ - L4 the Project Model;
696
+ - L5 every failure has an owner;
697
+ - L6 every run terminates everywhere;
698
+ - L7 outputs are contracts.
699
+ 4. Steering rule, added to OPERATING-MODEL.md: no bug becomes a fix slice until it has a row in docs/v10/FAILURE-CLASSES.md. Each row answers what the user saw against raw, the law broken, a sibling sweep, the one shared mechanism, and a regression fixture. Reviewers reject stage-only patches when siblings exist.
700
+ 5. Sequencing:
701
+ - Wave 0 ships in 10.7.1, with five builders in flight plus a cascade-off builder and a PR-body golden builder:
702
+ - scope becomes advisory;
703
+ - the cascade is off and escalation goes up only;
704
+ - a load error or zero tests collected becomes harness ERROR, with no fix rounds and a ready PR;
705
+ - a golden PR body;
706
+ - run.completed ingest plus a reconciler.
707
+ - Waves 1 and 2 go to the next train. Wave 1 covers the Project Model, the result classifier, the authority ladder in seal, a lifecycle e2e and static checks. Wave 2 covers the Repo Shape Matrix and the Parity Gate against raw `claude -p`, gating latest.
708
+ - An opus Architect is checking the plan against the code and slicing it into EL-W0/W1/W2 rows.
709
+ 6. Acceptance: a FireLater#17 rerun ends VERIFIED with a ready PR, the route edits kept, within raw plus 30s and at most 1.2x raw cost. The real-model legs stay parked until the founder provides keys (FOUNDER-QUEUE 15/16). The parity leg runs once keys exist; until then, recorded replays gate.
710
+
711
+ ## D87 (2026-10-03 19:00Z, founder via the steering session, CoS records): parallel lanes today, usage stop raised to 95%
712
+ 1. For today this supersedes the one-lane governor, the 81% weekly stop and the 85% floor. Up to 4 sonnet builders run in separate worktrees, and opus D12 reviews only HIGH slices.
713
+ 2. Hard stop: no new dispatch at 95% of the weekly limit. The last 5% is reserved for releases, smoke checks and steering, because 100% stops everything, this session included, until Oct 7 12:59 ET.
714
+ 3. Never hold completed work. Every green slice ships on the next train, and nobody pushes during a running release.
715
+ 4. Usage readings are logged hourly in usage-readings.tsv from direct /usage readings. The pulse weekly projection is not used as a governor input while it reads 450%+.
716
+ 5. Order: 10.7.1, then 10.8.0 (UI, CPE-24 if green, else 10.8.1), then MW-1 to MW-3, which replace mods M0 to M3 per the research in autonomi-dev/research/2026-10-03-claude-mods, then EL-W1.