loki-mode 10.6.14 → 10.7.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 (123) hide show
  1. package/README.md +9 -5
  2. package/SKILL.md +2 -2
  3. package/VERSION +1 -1
  4. package/autonomy/acp-agent.py +128 -0
  5. package/autonomy/docker-run.sh +8 -0
  6. package/autonomy/issue-parser.sh +7 -7
  7. package/autonomy/issue-providers.sh +159 -1
  8. package/autonomy/lib/engine10-push.sh +4 -1
  9. package/autonomy/lib/review_risk.py +91 -0
  10. package/autonomy/loki +209 -19
  11. package/autonomy/mobile-verify.sh +66 -0
  12. package/autonomy/run.sh +44 -2
  13. package/completions/_loki +2 -0
  14. package/completions/loki.bash +1 -1
  15. package/dashboard/__init__.py +1 -1
  16. package/dashboard/api_runs_v1.py +80 -0
  17. package/dashboard/server.py +2 -0
  18. package/docs/INSTALLATION.md +5 -1
  19. package/docs/acp-editors.md +29 -0
  20. package/docs/api-runs-v1.md +12 -0
  21. package/docs/dev/architecture-reference.md +4 -0
  22. package/docs/merge-queue.md +13 -0
  23. package/docs/mobile-verify.md +11 -0
  24. package/docs/sentry-intake.md +13 -0
  25. package/docs/v10/BOARD.md +31 -6
  26. package/docs/v10/CONTROL-PLANE.md +7 -0
  27. package/docs/v10/CP-ENTERPRISE-UI.md +276 -0
  28. package/docs/v10/D61-SPEED.md +4 -0
  29. package/docs/v10/DECISIONS.md +115 -0
  30. package/docs/v10/ENGINE-LAWS.md +155 -0
  31. package/docs/v10/FAILURE-CLASSES.md +145 -0
  32. package/docs/v10/FOUNDER-QUEUE.md +1 -0
  33. package/docs/v10/GAP-RESEARCH-1003.md +32 -0
  34. package/docs/v10/GUIDE.md +4 -2
  35. package/docs/v10/L0-WAVE1.md +81 -0
  36. package/docs/v10/MORNING-BRIEF-1003.md +25 -0
  37. package/docs/v10/OPERATING-MODEL.md +1 -0
  38. package/docs/v10/PROGRESS.md +99 -0
  39. package/docs/v10/SWARM.md +32 -0
  40. package/docs/visual-evidence.md +5 -0
  41. package/loki-ts/dist/loki.js +805 -777
  42. package/loki-ts/package.json +1 -0
  43. package/mcp/__init__.py +1 -1
  44. package/package.json +1 -1
  45. package/packages/control-plane/dist/server.js +549 -21
  46. package/packages/control-plane/drizzle/0002_tiresome_fixer.sql +7 -0
  47. package/packages/control-plane/drizzle/0003_integrity.sql +4 -0
  48. package/packages/control-plane/drizzle/meta/0002_snapshot.json +409 -0
  49. package/packages/control-plane/drizzle/meta/0003_snapshot.json +437 -0
  50. package/packages/control-plane/drizzle/meta/_journal.json +14 -0
  51. package/packages/control-plane/src/db/migrate.ts +6 -2
  52. package/packages/control-plane/src/db/prune.ts +91 -0
  53. package/packages/control-plane/src/db/schema.ts +13 -0
  54. package/packages/control-plane/src/server/actions.ts +60 -0
  55. package/packages/control-plane/src/server/app.ts +59 -4
  56. package/packages/control-plane/src/server/integrity.ts +147 -0
  57. package/packages/control-plane/src/server/runs.ts +46 -4
  58. package/packages/control-plane/src/shipper/discover.ts +32 -3
  59. package/packages/control-plane/src/shipper/ship.ts +15 -0
  60. package/packages/control-plane/src/shipper/watch.ts +66 -0
  61. package/packages/control-plane/ui/dist/assets/index-DHDI_dHM.css +1 -0
  62. package/packages/control-plane/ui/dist/assets/index-DaQr0MPS.js +129 -0
  63. package/packages/control-plane/ui/dist/index.html +3 -3
  64. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  65. package/web-app/dist/assets/{AdminPage-oAFMNfKH.js → AdminPage-BJSU5hY1.js} +1 -1
  66. package/web-app/dist/assets/{Avatar-BA2gnzyf.js → Avatar-CSOSpw9c.js} +1 -1
  67. package/web-app/dist/assets/{Badge-Dsluv8n1.js → Badge-COr7vj0D.js} +1 -1
  68. package/web-app/dist/assets/{Button-WmW8A-iG.js → Button-DGoWFERp.js} +1 -1
  69. package/web-app/dist/assets/{CockpitPage-BR5o_RgL.js → CockpitPage-CBpWkNXY.js} +1 -1
  70. package/web-app/dist/assets/{ComparePage-3Eg-pKvO.js → ComparePage-BwT8vqrL.js} +1 -1
  71. package/web-app/dist/assets/{ErrorBoundary-DAfrnnsQ.js → ErrorBoundary-D7SicDDA.js} +1 -1
  72. package/web-app/dist/assets/{EvidenceReceiptPanel-wLZI4OTr.js → EvidenceReceiptPanel-bx-5liG2.js} +1 -1
  73. package/web-app/dist/assets/{GitHubIssuesPanel-BOuadisf.js → GitHubIssuesPanel-BAeeWLqY.js} +1 -1
  74. package/web-app/dist/assets/{GitHubPRsPanel-BTVoVpB3.js → GitHubPRsPanel-CssD8lGI.js} +1 -1
  75. package/web-app/dist/assets/{HomePage-s3GWdNEe.js → HomePage-SL5PT3m5.js} +2 -2
  76. package/web-app/dist/assets/{LoginPage-BfOZ566t.js → LoginPage-C8hFOZOM.js} +1 -1
  77. package/web-app/dist/assets/{MagicPage-9EZ83xOt.js → MagicPage-xHbHkrPf.js} +1 -1
  78. package/web-app/dist/assets/{MetricsPage-OJMOYhHP.js → MetricsPage-B_2CKFcC.js} +1 -1
  79. package/web-app/dist/assets/{NotFoundPage-_LoJ6KEv.js → NotFoundPage-CXwXMq35.js} +1 -1
  80. package/web-app/dist/assets/{ProjectPage-Duj5LSt6.js → ProjectPage-AaisMQI-.js} +3 -3
  81. package/web-app/dist/assets/{ProjectsPage-BBud3JrO.js → ProjectsPage-Cej5ResX.js} +1 -1
  82. package/web-app/dist/assets/{SettingsPage-C4zdgKno.js → SettingsPage-DKv4mn9H.js} +1 -1
  83. package/web-app/dist/assets/{ShowcasePage-Nb3ACjMR.js → ShowcasePage-Dkiyzne4.js} +1 -1
  84. package/web-app/dist/assets/{SystemSettingsPage-BDi49TDh.js → SystemSettingsPage-DaBLQ5dU.js} +1 -1
  85. package/web-app/dist/assets/{TeamsPage-HkcqkjLa.js → TeamsPage-B2yUr31k.js} +1 -1
  86. package/web-app/dist/assets/{TemplatesPage-CK796Y1F.js → TemplatesPage-CfYiANhU.js} +1 -1
  87. package/web-app/dist/assets/{TerminalOutput-BkvdNuT6.js → TerminalOutput-CMXoexLM.js} +1 -1
  88. package/web-app/dist/assets/{activity-DFgMgETR.js → activity-B0dzoZtY.js} +1 -1
  89. package/web-app/dist/assets/{bell-BInGGOMZ.js → bell-DFOTaSoo.js} +1 -1
  90. package/web-app/dist/assets/{bot-D43Yjsj4.js → bot-Dz-WSQyP.js} +1 -1
  91. package/web-app/dist/assets/{check-DFAGTLM9.js → check-L1QIRueJ.js} +1 -1
  92. package/web-app/dist/assets/{chevron-left-Drwin7n1.js → chevron-left-1TrnIEZS.js} +1 -1
  93. package/web-app/dist/assets/{circle-alert-DLWdb7V9.js → circle-alert-8Bf6xEDx.js} +1 -1
  94. package/web-app/dist/assets/{clock-Dsbi59u5.js → clock-DB8NE6P5.js} +1 -1
  95. package/web-app/dist/assets/{cloud-CUU-dXTP.js → cloud-DUSL3wZS.js} +1 -1
  96. package/web-app/dist/assets/{code-xml-CqIh7Wui.js → code-xml-DbjryWNl.js} +1 -1
  97. package/web-app/dist/assets/{database-DASN5Bfh.js → database-DrezrMSs.js} +1 -1
  98. package/web-app/dist/assets/{dollar-sign-ZvXzAihc.js → dollar-sign-CGbaLMzR.js} +1 -1
  99. package/web-app/dist/assets/{file-code-corner-ED_gN-N8.js → file-code-corner-Dfypa-r4.js} +1 -1
  100. package/web-app/dist/assets/{file-plus-BmBHndXt.js → file-plus-CzV5L2Gd.js} +1 -1
  101. package/web-app/dist/assets/{globe-Ck_iEzO4.js → globe-BoYjTwPQ.js} +1 -1
  102. package/web-app/dist/assets/{hammer-B8YKMard.js → hammer-WO-HuiyJ.js} +1 -1
  103. package/web-app/dist/assets/{index-D7SxmjVQ.js → index-CjIOUjnd.js} +3 -3
  104. package/web-app/dist/assets/{layers-CGVsj3wB.js → layers-Bn6jtKNk.js} +1 -1
  105. package/web-app/dist/assets/{loader-circle-FIH7UJDF.js → loader-circle-gERWRnmW.js} +1 -1
  106. package/web-app/dist/assets/{lock-vR8HoAnK.js → lock-BIiMLJq8.js} +1 -1
  107. package/web-app/dist/assets/{package-mZ6LFwXp.js → package-dLvDSVys.js} +1 -1
  108. package/web-app/dist/assets/{plus-CtnSVu0w.js → plus-BHM3ZLhZ.js} +1 -1
  109. package/web-app/dist/assets/{refresh-cw-BIapF6Gj.js → refresh-cw-BAp_alv6.js} +1 -1
  110. package/web-app/dist/assets/{rotate-ccw-LMkSsm21.js → rotate-ccw-CBhwq_MG.js} +1 -1
  111. package/web-app/dist/assets/{scroll-text-DQVlIhr9.js → scroll-text-DoS-6dfU.js} +1 -1
  112. package/web-app/dist/assets/{server-GqyhQxmz.js → server-5JgdDWQO.js} +1 -1
  113. package/web-app/dist/assets/{shield-alert-BrFTNJ-I.js → shield-alert-DjmlLT34.js} +1 -1
  114. package/web-app/dist/assets/{thumbs-up-lgwAEJFW.js → thumbs-up-BtiEXl3p.js} +1 -1
  115. package/web-app/dist/assets/{trash-2-C1cNysK4.js → trash-2-ClsWU_Vg.js} +1 -1
  116. package/web-app/dist/assets/{trending-down-DQFZ6j5s.js → trending-down-DPS4M7_X.js} +1 -1
  117. package/web-app/dist/assets/{trending-up-BJG_Zo8V.js → trending-up-D6OJ38-V.js} +1 -1
  118. package/web-app/dist/assets/{upload-BOY1aTpA.js → upload-DOCzLUpF.js} +1 -1
  119. package/web-app/dist/assets/{usePolling-DoAmsTNy.js → usePolling-CljQTWj_.js} +1 -1
  120. package/web-app/dist/assets/{user-iOfCe0_v.js → user-C0G82Weu.js} +1 -1
  121. package/web-app/dist/index.html +1 -1
  122. package/packages/control-plane/ui/dist/assets/index-CFfrqCx2.css +0 -1
  123. package/packages/control-plane/ui/dist/assets/index-Jt31nrK-.js +0 -114
@@ -0,0 +1,276 @@
1
+ # Control Plane enterprise UI (D83)
2
+
3
+ Status: STEP 1 design, architect output. STEP 2 is the slice plan in section 6. Ships as 10.8.0.
4
+ Package: packages/control-plane (server in src/server, UI in ui/src). Sources cited as path:line on main e6d6c362f.
5
+
6
+ ## 0. Guiding principle (founder addendum, 15:24Z, binding)
7
+
8
+ "i want fully controllable loki mode of sessions, configurations and anything from UI, but keep it super clean and lean like claude.ai UI and chatgpt UI, but with loki mode's old dashboard look, should feel amazing for users".
9
+
10
+ 1. FULL CONTROL. Everything the CLI does is doable in the UI: start, stop, answer, retry and resume a run; choose repo, issue, model, provider and budget; edit loki.yaml through forms that write back to the file; connect integrations; manage workspaces (and schedules and the merge queue once their backends exist); view and verify receipts. No feature is CLI-only. Section 3.3 is the CLI-to-UI parity table and is a release gate.
11
+ 2. CLEAN AND LEAN. One primary surface, like Claude.ai and ChatGPT:
12
+ - Left sidebar = wordmark, a "New run" button, and the session list (runs as conversations, grouped Today, Yesterday, Earlier). Nothing else at the top level.
13
+ - Main pane = either the New run composer or one run as a single readable thread.
14
+ - New run = one input, "Paste an issue link or describe a task", with inline chips for repo, model, provider and budget.
15
+ - A run = live steps stream in like messages; diff, evidence and receipt expand inline; a BLOCKED question renders as a reply prompt.
16
+ - Everything else (Home, Runs table, Work board, Workspaces, Plans, Receipts, Cost, Models, Integrations, Notifications, Audit log, Settings) sits behind ONE menu entry at the sidebar foot, not 15 sidebar items. Progressive disclosure everywhere.
17
+ 3. OLD LOOK on that lean structure: Fraunces serif wordmark and page titles, Inter UI, JetBrains Mono numbers, the purple accent, cards, KPI tiles, badges, status dots, light and dark themes, exactly from section 2 tokens.
18
+ 4. FEEL AMAZING: instant navigation (client router, cached list), optimistic updates with rollback, Cmd+K, Cmd+Enter to start, empty states that give the single next action, and no dead or placeholder panel. A page whose backend does not exist is not rendered at all.
19
+ 5. HONESTY (D83 item 3): every number comes from ingested events or run artifacts. A missing value renders as "not measured", never 0. Partial cost shows measured_sessions/total_sessions.
20
+
21
+ ## 1. Legacy inventory (KEEP / REWORK / DROP)
22
+
23
+ Shell: dashboard-ui/scripts/build-standalone.js (generates dashboard/static/index.html). Nav groups at build-standalone.js:1266-1347 (Build, Quality and Trust, Insights, Ops, Wiki). Pages at :1358-1882. RARV, Council, gates, checkpoints and app runner are legacy engine concepts with no v10 producer (docs/v10/LEGACY-REMOVAL.md:36-37), so they DROP or remap to v10 stages (events stage.started/completed/failed/skipped, loki-ts/src/engine10/status.ts:9).
24
+
25
+ | Legacy page or control | Source | Decision | v10 home |
26
+ |---|---|---|---|
27
+ | Overview (spec, tasks, RARV timeline, diff) | components/loki-overview.js, loki-spec-panel.js, loki-rarv-timeline.js, loki-session-diff.js, loki-task-board.js; build-standalone.js:1358-1415 | REWORK | Home (KPI row, recent runs, BLOCKED inbox). RARV timeline becomes the v10 stage timeline in the run thread. Task board DROP (no v10 task queue). Diff KEEP inside the run thread. |
28
+ | First-run hero ("loki quickstart") | build-standalone.js:1365-1387 | REWORK | Empty state of the New run composer (one action: paste an issue). |
29
+ | App Runner | loki-app-preview.js, loki-app-status.js (/api/app-runner/*) | DROP | Screenshots and evidence in the run thread replace it. |
30
+ | Checkpoints | loki-checkpoint-viewer.js (/api/checkpoints, rollback) | DROP | No v10 checkpoints; rollback deleted (LEGACY-REMOVAL.md:37). |
31
+ | Context | loki-context-tracker.js (/api/context) | DROP | Token counts per run (input_tokens, output_tokens) shown in the run cost card. |
32
+ | Fleet | loki-fleet.js (/api/fleet/*) | REWORK | Runs table (all repos, filters, group_id rollup). Its table styling is the Table primitive. |
33
+ | Quality (score, gates, prompt optimizer) | loki-quality-score.js, loki-quality-gates.js, loki-prompt-optimizer.js | DROP | v10 verify stage plus NOT PROVEN list in the run thread. |
34
+ | Trust trajectory and receipts panel | dashboard/static/trust.html, proofs.html; build-standalone.js:1811-1828 | KEEP on v10 data | Receipts page (list, inline verify, verified-rate trend from runs). |
35
+ | Completion Council | loki-council-dashboard.js, loki-council-transcripts.js | DROP | Remapped: the v10 verify stage and receipt verdict. |
36
+ | Spec Checklist | loki-checklist-viewer.js (/api/checklist) | REWORK | Plans and traceability (plan.json, issue.json, receipt claims). |
37
+ | Insights: logs | loki-log-stream.js (/api/logs) | KEEP | Streaming log inside the run thread (events.jsonl). |
38
+ | Insights: memory, learnings, USAGE.md | loki-memory-browser.js, loki-learning-dashboard.js; build-standalone.js:1427-1590 | DROP now | Memory page deferred until a v10 memory read API exists (section 3.2). USAGE.md becomes a Help link. |
39
+ | Analytics | loki-analytics.js (/api/activity) | REWORK | Home trends (runs per day, verified rate) from the runs table. |
40
+ | Cost | loki-cost-dashboard.js, loki-cost-waterfall.js, dashboard/static/cost.html; spend-cap banner build-standalone.js:1800-1806 | KEEP on v10 data | Cost and usage page; the "no cap" banner is kept and fed by loki.yaml budgets. |
41
+ | Notifications | loki-notification-center.js | REWORK | Derived from events: BLOCKED, FAILED, budget.hit, tampered, conflict. |
42
+ | Escalations | loki-escalations.js | REWORK | BLOCKED inbox on Home plus the reply prompt in the thread. |
43
+ | Migration | loki-migration-dashboard.js | REWORK | Runs filtered to `loki modernize` runs once they ship events (engine10/modernize); hidden until then. |
44
+ | Wiki | loki-wiki-browser.js | DROP | Wiki deleted (LEGACY-REMOVAL.md:45). |
45
+ | Session panel: Start build, spec textarea | loki-session-control.js:443-500 (/api/control/start, loki-api-client.js:1109) | REWORK | New run composer. |
46
+ | Session panel: model picker (start-time) | loki-session-control.js:453-495 | KEEP | Model chip on the composer. |
47
+ | Session panel: mid-run model switch | loki-session-control.js:362-437 (/api/session/model) | DROP | v10 has no mid-run switch; Retry with another model instead. |
48
+ | Session panel: advisor picker | loki-session-control.js:464-490 | DROP | No v10 advisor. |
49
+ | Session panel: Pause, Resume, Stop | loki-session-control.js:19-22 (/api/control/pause, resume, stop) | REWORK | Stop, Retry, Resume on the run header (no pause in v10). |
50
+ | Right status sidebar (288 px, 48 px rail) | build-standalone.js:1885-1958, layout :116-140 | REWORK | Run details become an inline collapsible "Details" card in the thread; no permanent third column. |
51
+ | Settings disclosure (API URL, theme) | build-standalone.js:1905-1935 | REWORK | Settings page; theme toggle lives in the menu. |
52
+ | Project picker and per-app Stop list | build-standalone.js:1244-1258 (/api/running-projects) | REWORK | Repo chip on composer plus a repo filter on the session list. |
53
+ | Receipts badge | build-standalone.js:1227-1238, CSS :334-351 (/api/proofs/summary) | KEEP | Sidebar header badge, fed by /v1/stats receipts count. |
54
+ | Mascot presence | loki-mascot-presence.js | KEEP | Next to the wordmark, state from "any run running". |
55
+ | Budget banner | build-standalone.js:1200-1203 | KEEP | Top banner when a budget is hit (budget.hit event). |
56
+ | Run manager, audit viewer | loki-run-manager.js, loki-audit-viewer.js | REWORK | Runs table actions; Audit log page (control-plane actions). |
57
+ | API keys, tenant switcher, managed memory | loki-api-keys.js, loki-tenant-switcher.js, loki-managed-memory-panel.js | DROP | Local single user; the bearer token is set by env (src/server/auth.ts). |
58
+ | Onboarding (start.html) | dashboard/static/start.html (/api/onboarding/*, /api/backlog/*) | REWORK | Integrations page (GitHub connect status) plus the composer empty state. |
59
+
60
+ ## 2. Design system (extracted, binding)
61
+
62
+ Two legacy layers exist and disagree on ground colors. The SHELL layer in build-standalone.js:113-185 is documented as the founder-approved identity (light-grey ground, comment at :113) and is what users saw around every page; the COMPONENT layer in dashboard-ui/core/loki-unified-styles.js:20-146 (also loki-theme.js:44-124) supplies the scales, status colors and component specs. Decision: shell ground and accent per theme from the shell layer; scales, radii, shadows, model colors and component recipes from the component layer. (Open question 1.)
63
+
64
+ Package: packages/control-plane/ui/src/design/ with tokens.css (custom properties below), fonts.css (Google Fonts link, build-standalone parity: Fraunces opsz 9..144 wght 400/500/600, Inter 300-700, JetBrains Mono 400/500; static/index.html:11), tailwind.preset.ts (maps Tailwind colors, radius, spacing, fontFamily to the vars, so existing Tailwind classes keep working), and primitives/*.tsx.
65
+
66
+ ### 2.1 Tokens (tokens.css)
67
+
68
+ ```css
69
+ :root, [data-theme="light"] {
70
+ /* ground: build-standalone.js:116-139 */
71
+ --cp-bg: #F1F2F6; --cp-bg-2: #E6E8EE; --cp-bg-3: #DBDEE6;
72
+ --cp-card: rgba(255,255,255,0.86); --cp-hover: #E6E8EE;
73
+ --cp-glass: rgba(255,255,255,0.7); --cp-glass-border: rgba(255,255,255,0.4);
74
+ --cp-glass-shadow: 0 4px 24px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
75
+ --cp-text: #201515; --cp-text-2: #4A4640; --cp-text-muted: #8A857C; --cp-text-inverse: #ffffff;
76
+ --cp-border: rgba(0,0,0,0.08); --cp-border-light: rgba(0,0,0,0.05);
77
+ /* accent: shell :124-126, hover/active unified-styles.js:33-35 */
78
+ --cp-accent: #553DE9; --cp-accent-hover: #4432c4; --cp-accent-active: #3828a0;
79
+ --cp-accent-glow: rgba(85,61,233,0.15); --cp-accent-muted: rgba(85,61,233,0.10);
80
+ /* status text: shell :131-134 (AA on light ground); fills: unified-styles.js:51-58 */
81
+ --cp-success: #1f8a52; --cp-warning: #9a6a12; --cp-error: #b23a3a; --cp-info: #2F71E3;
82
+ --cp-success-fill: #1FC5A8; --cp-success-muted: rgba(31,197,168,0.12);
83
+ --cp-warning-fill: #D4A03C; --cp-warning-muted: rgba(212,160,60,0.12);
84
+ --cp-error-fill: #C45B5B; --cp-error-muted: rgba(196,91,91,0.12);
85
+ --cp-info-muted: rgba(47,113,227,0.12);
86
+ /* models: unified-styles.js:72-75 */
87
+ --cp-opus: #d97706; --cp-sonnet: #553DE9; --cp-haiku: #1FC5A8;
88
+ --cp-shadow-sm: 0 1px 2px rgba(32,21,21,0.04); --cp-shadow-md: 0 4px 6px rgba(32,21,21,0.06);
89
+ --cp-shadow-lg: 0 10px 15px rgba(32,21,21,0.08); --cp-focus: 0 0 0 3px rgba(85,61,233,0.25);
90
+ }
91
+ [data-theme="dark"] { /* build-standalone.js:164-185; unified-styles.js:86-146 */
92
+ --cp-bg: #17161C; --cp-bg-2: #1E1D25; --cp-bg-3: #27262F;
93
+ --cp-card: rgba(35,34,43,0.82); --cp-hover: #27262F;
94
+ --cp-glass: rgba(23,22,28,0.7); --cp-glass-border: rgba(255,255,255,0.08);
95
+ --cp-glass-shadow: 0 4px 24px rgba(0,0,0,0.25), 0 1px 2px rgba(0,0,0,0.12);
96
+ --cp-text: #F0ECF8; --cp-text-2: #B8B0C8; --cp-text-muted: #8B85A0; --cp-text-inverse: #17161C;
97
+ --cp-border: rgba(255,255,255,0.08); --cp-border-light: rgba(255,255,255,0.04);
98
+ --cp-accent: #8b7bf5; --cp-accent-hover: #9c8ff7; --cp-accent-active: #6258D0;
99
+ --cp-accent-glow: rgba(139,123,245,0.2); --cp-accent-muted: rgba(123,107,240,0.18);
100
+ --cp-success: #2ED8B6; --cp-warning: #E8B84A; --cp-error: #E07070; --cp-info: #5A9CF5;
101
+ --cp-success-fill: #2ED8B6; --cp-success-muted: rgba(46,216,182,0.18);
102
+ --cp-warning-fill: #E8B84A; --cp-warning-muted: rgba(232,184,74,0.18);
103
+ --cp-error-fill: #E07070; --cp-error-muted: rgba(224,112,112,0.18);
104
+ --cp-info-muted: rgba(90,156,245,0.18);
105
+ --cp-opus: #f59e0b; --cp-sonnet: #8b7bf5; --cp-haiku: #2ED8B6;
106
+ --cp-shadow-sm: 0 1px 2px rgba(0,0,0,0.4); --cp-shadow-md: 0 4px 12px rgba(0,0,0,0.5);
107
+ --cp-shadow-lg: 0 10px 25px rgba(0,0,0,0.6); --cp-focus: 0 0 0 3px rgba(123,107,240,0.30);
108
+ }
109
+ @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { /* same as [data-theme="dark"] */ } }
110
+ :root {
111
+ --cp-font-serif: 'Fraunces', Georgia, 'Times New Roman', serif; /* unified-styles.js:358-362 */
112
+ --cp-font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
113
+ --cp-font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', Menlo, monospace;
114
+ --cp-text-xs: 10px; --cp-text-sm: 11px; --cp-text-base: 12px; --cp-text-md: 13px;
115
+ --cp-text-lg: 14px; --cp-text-xl: 16px; --cp-text-2xl: 18px; --cp-text-3xl: 24px;
116
+ --cp-space-xs: 4px; --cp-space-sm: 8px; --cp-space-md: 12px; --cp-space-lg: 16px; /* :333-341 */
117
+ --cp-space-xl: 24px; --cp-space-2xl: 32px; --cp-space-3xl: 48px;
118
+ --cp-radius-sm: 2px; --cp-radius-md: 4px; --cp-radius-lg: 5px; --cp-radius-nav: 8px; --cp-radius-full: 9999px; /* :346-353, nav :400-406 */
119
+ --cp-ease: cubic-bezier(0.4,0,0.2,1); --cp-dur-fast: 100ms; --cp-dur: 200ms; --cp-dur-slow: 300ms; /* :390-405 */
120
+ --cp-sidebar-w: 240px; /* build-standalone.js:126 grid track */
121
+ --cp-detail-w: 288px; --cp-rail-w: 48px; /* :120-121, used only by the optional Details drawer */
122
+ --cp-main-pad: 28px 32px; /* .main-content :917-923 */
123
+ --cp-thread-max: 820px; /* NEW: reading width of the run thread (Claude.ai-like) */
124
+ --cp-z-dropdown: 100; --cp-z-sticky: 200; --cp-z-modal: 300; --cp-z-popover: 400; --cp-z-toast: 600; /* :419-427 */
125
+ }
126
+ ```
127
+
128
+ Breakpoints (unified-styles.js:408-414): 640, 768, 1024, 1280, 1536. Below 768 px the sidebar becomes a drawer (legacy mobile-menu-btn, build-standalone.js:1210 and media :240-266).
129
+
130
+ ### 2.2 Typography and wordmark
131
+ - Wordmark: "Loki Mode" in --cp-font-serif 22px weight 400, letter-spacing -0.02em, line-height 1.1; subtitle "powered by Autonomi" Inter 9px uppercase 0.08em weight 500 muted (build-standalone.js:312-328). Logo: the 34 px purple rounded-square SVG with the teal dot (:1218-1224), copied verbatim.
132
+ - Page and thread titles: serif 1.8rem weight 400, -0.02em (.section-page-title :949-955). Section headings: serif 1.15rem weight 400 (:1432).
133
+ - Body: Inter 13px, line-height 1.5, font-feature-settings 'cv02','cv03','cv04','cv11', antialiased (:283-296).
134
+ - Numbers (KPI values, cost, seq, SHA): mono. KPI value 28px (compact 20px) (loki-kpi-card.js:258-262).
135
+
136
+ ### 2.3 Primitives (ui/src/design/primitives)
137
+ | Primitive | Recipe (source) |
138
+ |---|---|
139
+ | Card | --cp-card bg, 1px --cp-border, radius 5px, padding 16px, hover border --cp-border-light; interactive variant lifts 1px with --cp-shadow-md (unified-styles.js:746-767) |
140
+ | KpiTile | Card at 14px 16px (compact 10px 12px), gap 10px, icon chip radius 6px, trend pill 11px radius 3px, mono value, 11px label, optional sparkline SVG from real series only (loki-kpi-card.js:180-293) |
141
+ | Badge | inline-flex, 2px 8px, radius 2px, 10px uppercase 0.025em weight 500; variants success, warning, error, info, neutral use muted bg plus solid text (unified-styles.js:799-835). Verdict map: VERIFIED success, PARTIAL warning, FAILED error, SPEC_CONFLICT (BLOCKED) info, running neutral with pulse dot. |
142
+ | Pill | receipts badge recipe: radius 999px, 3px 8px, 10px, card bg, 1px border (build-standalone.js:334-351) |
143
+ | StatusDot | 12x6 px, radius 2px; active = success with 2s pulse; idle muted; paused warning; error error (unified-styles.js:723-742) |
144
+ | Button | 8px 12px, radius 4px, 13px weight 500; primary accent/hover/active; secondary, ghost, danger; sm and lg sizes; disabled opacity 0.5 (:646-722) |
145
+ | Input, Textarea, Select | --cp-bg-3 bg, 1px border, radius 4px, focus border accent plus --cp-focus ring (:768-797) |
146
+ | Chip | Pill shape with a leading icon and a popover menu (composer repo, model, provider, budget). NEW, built from Pill and Input tokens. |
147
+ | Table | wrapper Card radius 5px overflow auto; 12px rows; th 11px weight 600 uppercase 0.05em muted on --cp-bg-3, padding 10px 14px (loki-fleet.js:279-300) |
148
+ | NavItem | 8px 12px, radius 8px, 13px weight 500, text-2; hover --cp-hover; active accent text on --cp-accent-glow with a 3x16 px left accent bar (build-standalone.js:400-458) |
149
+ | GroupHead | 9.5px weight 600 uppercase 0.09em muted, padding 4px 12px 5px (:389-398); used for Today, Yesterday, Earlier |
150
+ | Timeline | vertical stage track (loki-session-timeline.js:328-400): a dot per stage colored by status, connector line --cp-border, label plus mono duration |
151
+ | Message | NEW thread item: 32 px gutter icon, serif-free body, mono meta line; expandable body (diff, evidence, receipt) using Card |
152
+ | Glass surface | sidebar: --cp-glass with backdrop-filter blur(16px) saturate(1.4), right border --cp-glass-border (:268-280) |
153
+ | EmptyState, Spinner, Toast, Dialog, Drawer, Kbd | unified-styles.js:836-880 for empty and spinner; others NEW on the same tokens |
154
+
155
+ Motion: page fade-in 0.2s translateY(6px) (build-standalone.js:925-940); respect prefers-reduced-motion.
156
+
157
+ ## 3. Feature set and information architecture
158
+
159
+ ### 3.1 Shell
160
+ - Sidebar (240 px, glass): wordmark plus mascot plus receipts Pill; "New run" primary button (Cmd+Enter submits, Cmd+N focuses); search field (opens Cmd+K); session list grouped Today, Yesterday, Earlier, each row = title (issue ref or first line of task), repo, StatusDot, verdict Badge; footer = Menu button (opens the menu sheet), theme toggle, connection dot.
161
+ - Menu sheet (progressive disclosure, like the Claude.ai account menu): Home, Runs, Work board, Workspaces, Plans, Receipts, Cost and usage, Models and providers, Integrations, Notifications, Audit log, Settings. Entries whose backend is missing are not listed.
162
+ - Main pane: composer (route /) or run thread (/r/:source/:run) or a menu page.
163
+
164
+ ### 3.2 Pages (data backing; "BACKEND" names the slice that must land first)
165
+ | Page | Inspired by | Content | Data |
166
+ |---|---|---|---|
167
+ | New run composer | Claude.ai, Devin | One input "Paste an issue link or describe a task"; chips repo, model, provider, budget (max-cost), deep, no-pr; recent issues suggestions | BACKEND CPE-07 (start), CPE-15 (providers), CPE-03 (repos) |
168
+ | Run thread | Devin session | header (title, repo, verdict Badge, elapsed, cost, Stop, Retry, Resume); stage messages streaming; streaming log; diff; evidence and screenshots; receipt with sha256, signed flag, inline Verify; NOT PROVEN list; PR link; BLOCKED reply prompt; Details drawer | exists: /v1/runs/:s/:r, answer. BACKEND CPE-04 (artifacts), CPE-05 (stream), CPE-09 (control) |
169
+ | Home | Factory | KPI tiles: runs today, verified rate 7d, cost 7d (measured/partial), BLOCKED waiting; recent runs; BLOCKED inbox | BACKEND CPE-12 (/v1/stats) |
170
+ | Runs | Factory fleet | Table with filters verdict, repo, since, group; group_id rollup | exists: /v1/runs filters |
171
+ | Work board | Vorflux, Linear | Kanban: Issue (issue_ref) to Running to PR open to Verified or Not proven | exists: runs fields issue_ref, pr_url, verdict |
172
+ | Workspaces | Factory | loki.yaml workspaces, per-group status, run a workspace | BACKEND CPE-14 (config read), CPE-07 (start with workspace) |
173
+ | Plans and traceability | 8090 | requirement (issue.json, plan.json) to stage to changed file to test to receipt claim; NOT PROVEN highlighted | BACKEND CPE-04 |
174
+ | Receipts | trust.html | list, verify in place, verified-rate trend | BACKEND CPE-04, CPE-16 |
175
+ | Cost and usage | cost.html | per day, model, repo, provider; tokens; measured vs partial; budgets and "no cap" banner | BACKEND CPE-13 |
176
+ | Models and providers | session-control | detected CLIs with version, auth present (boolean only), model catalog, default model | BACKEND CPE-15 |
177
+ | Integrations | Vorflux | GitHub (gh auth or git.token_env present), GitLab, Slack (notifications.slack_webhook_env), Jira, Linear, Sentry, MCP: real probe status; connect = write the env var NAME into loki.yaml, never a secret | BACKEND CPE-20 |
178
+ | Notifications | legacy center | BLOCKED, FAILED, budget.hit, tampered, ingest conflict; unread state local | BACKEND CPE-21 (derived from events) |
179
+ | Audit log | enterprise | every UI action (start, stop, retry, resume, answer, config write) with time, actor, result | BACKEND CPE-03 (actions table) |
180
+ | Settings | Claude.ai settings | loki.yaml forms per schema section (provider, models, git, repos, concurrency, budgets, knowledge_sources, workspaces, notifications; schemas/loki-yaml.schema.json); appearance; server token | BACKEND CPE-14 |
181
+ | Merge queue, PR reviews with risk, Schedules and triggers | Vorflux | NOT BUILT: backends parked (BOARD.md D64-MERGE :725, D64-REVIEW :726, D64-SERVE :724). Hidden until those land; UI slices are cut then. | none today |
182
+ | Memory | Devin knowledge | NOT BUILT: no v10 memory read API (repomemory.ts is engine-internal). Hidden. | none today |
183
+ | Cmd+K, search | Linear | jump to run, page, action ("New run", "Toggle theme", "Stop current run") | client side over cached lists |
184
+ | Light/dark, mobile, accessibility | | data-theme toggle persisted (localStorage, try/catch), system default; drawer at < 768 px; WCAG AA contrast, focus rings, aria-live for streaming steps, full keyboard path | CPE-23 tests |
185
+
186
+ ### 3.3 CLI-to-UI parity table (release gate for 10.8.0)
187
+ | CLI | UI control | API |
188
+ |---|---|---|
189
+ | `loki "<task>"` | composer input | POST /v1/runs (CPE-07) |
190
+ | `loki <issue-url or owner/repo#N>` | composer input (issue link detected) | POST /v1/runs |
191
+ | `--provider <name>` | provider chip | POST /v1/runs body.provider |
192
+ | model (loki.yaml models.default, LOKI_SESSION_MODEL) | model chip | POST /v1/runs body.model |
193
+ | `--max-cost <usd>` | budget chip | POST /v1/runs body.max_cost_usd |
194
+ | `--deep`, `--no-pr` | toggles in the composer "More" chip | POST /v1/runs body.deep, body.no_pr |
195
+ | `loki status [run-id]` | session list plus run thread | GET /v1/runs, GET /v1/runs/:s/:r |
196
+ | `loki answer <run>` | BLOCKED reply prompt, Resume | POST /v1/runs/:s/:r/answer (exists), POST .../resume (CPE-09) |
197
+ | Ctrl+C on a run | Stop | POST /v1/runs/:s/:r/stop (CPE-09) |
198
+ | re-run the same ref | Retry | POST /v1/runs/:s/:r/retry (CPE-09) |
199
+ | `loki verify [run-id or receipt.json]` | Verify button on receipt | POST /v1/runs/:s/:r/verify (CPE-16) |
200
+ | `loki keys export` | Receipts page "Public key" | GET /v1/keys (CPE-16) |
201
+ | `loki workspace list, show, run, status` | Workspaces page | GET /v1/config, POST /v1/runs body.workspace (CPE-19) |
202
+ | `loki config` (loki.yaml edit, validate) | Settings forms | GET, PUT /v1/config (CPE-14) |
203
+ | `loki provider` | Models and providers | GET /v1/providers (CPE-15) |
204
+ | `loki control` | (this UI) | n/a |
205
+ | `loki modernize <repo> --to <target>` | composer "Modernize" mode | DEFERRED: modernize does not emit v10 run events yet (open question 3) |
206
+ | `loki merge`, `loki review --risk`, `loki serve` schedules | none until built | DEFERRED with D64 backends |
207
+
208
+ ## 4. API: what exists and what is new
209
+
210
+ Exists (packages/control-plane/src/server): GET /health, /ready; POST /v1/ingest; GET /v1/runs (verdict, repo, since, until, group_id, limit, cursor); GET /v1/runs/:source/:run and /v1/runs/:id (summary, stages, receipt sha256/signed/verdict/path, not_proven, blocked_question, current_stage, files_touched); POST /v1/runs/:source/:run/answer (app.ts:46-75, runs.ts, answer.ts). Guards: hostGuard (loopback), tokenGuard (bearer on /v1/*) (auth.ts). Store: SQLite via Drizzle, tables sources, events, runs (db/schema.ts). Shipper backfills and tails .loki/runs/*/events.jsonl (shipper/*). Run dir artifacts (engine10): events.jsonl, issue.json, plan.json, task.md, receipt.json, receipt.md, report.json, report.md, status.json, eta.json, estimate.json, failures.jsonl.
211
+
212
+ Gap: the server stores events only. Artifacts live in the local repo, and source_id is a hash (ship.ts:16-21), so the server cannot find the repo. CPE-03 adds a LOCAL-ONLY table local_repos (source_id, realpath) filled by local discovery, never by /v1/ingest, never returned over the API beyond a display name.
213
+
214
+ | New endpoint | Slice | Tier | Notes |
215
+ |---|---|---|---|
216
+ | GET /v1/runs/:s/:r/events?after=seq | CPE-04 | HIGH | paged events for the log |
217
+ | GET /v1/runs/:s/:r/artifact/:name | CPE-04 | HIGH | fixed allowlist of names (issue.json, plan.json, receipt.json, receipt.md, report.md, task.md, diff.patch, evidence/*.png); realpath must stay under <repo>/.loki/runs/<run>; size cap |
218
+ | GET /v1/runs/:s/:r/stream, GET /v1/stream | CPE-05 | MEDIUM | SSE of new events and run-row changes, heartbeat 15s |
219
+ | GET /v1/stats?since= | CPE-12 | MEDIUM | counts, verified rate, cost measured and partial, receipts count |
220
+ | GET /v1/stats/cost?group=day,model,repo,provider | CPE-13 | MEDIUM | from runs table |
221
+ | GET /v1/repos | CPE-03 | MEDIUM | display names of discovered local repos |
222
+ | POST /v1/runs | CPE-07 | HIGH | start: repo must be a local_repos entry; ref or task text validated; flags whitelisted; spawns `loki` with argv array (no shell), detached, env scrubbed to an allowlist; JSON content type plus Origin check; audit row |
223
+ | POST /v1/runs/:s/:r/stop, /retry, /resume | CPE-09 | HIGH | stop signals only the pid recorded in <run>/run.pid whose start time and run id match; retry re-uses the recorded argv; resume = existing answer file plus `loki answer <run>` spawn; audit row |
224
+ | GET /v1/config, PUT /v1/config | CPE-14 | HIGH | read and validate against schemas/loki-yaml.schema.json; write atomic (temp plus rename), comment-preserving (adopt the `yaml` package Document API), backup to loki.yaml.bak, optimistic concurrency via sha256 If-Match; secrets refused (env var names only) |
225
+ | GET /v1/providers | CPE-15 | MEDIUM | CLI detection with timeout, versions, auth present boolean, providers/model_catalog.json |
226
+ | POST /v1/runs/:s/:r/verify, GET /v1/keys | CPE-16 | MEDIUM | calls the existing verify_cmd and keys_cmd in process, read-only |
227
+ | GET /v1/integrations | CPE-20 | MEDIUM | status probes only |
228
+ | GET /v1/notifications | CPE-21 | LOW | derived query over events |
229
+ | GET /v1/audit | CPE-21 | LOW | actions table, newest first |
230
+
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
+
233
+ ## 5. Parity checklist (gate for CPE-24)
234
+ 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
+ 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
+ 3. Visual parity: screenshots of wordmark, nav, card, KPI, badge, table in light and dark compared against legacy captures (CPE-23).
237
+ 4. No route under the old dashboard is reachable except the CP-LEGACY redirects (7b701d238).
238
+ 5. Lighthouse accessibility at or above 95 on composer, thread, Home; axe zero serious violations.
239
+
240
+ ## 6. STEP 2 slice plan
241
+
242
+ 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.
243
+
244
+ | ID | Goal | File set | Wall check | Depends | Tier |
245
+ |---|---|---|---|---|---|
246
+ | CPE-01 | Design token package: tokens.css, fonts.css, tailwind.preset.ts, primitives (Card, KpiTile, Badge, Pill, StatusDot, Button, Input, Chip, Table, NavItem, GroupHead, Timeline, Message, EmptyState, Spinner, Toast, Dialog, Drawer, Kbd) | ui/src/design/**, ui/tailwind.config.js, test/ui/design.test.tsx | `bun test test/ui/design.test.tsx` (every token in 2.1 present in both themes; hex values match the cited sources; primitives render) | none | MEDIUM |
247
+ | CPE-02 | Lean shell: glass sidebar with wordmark, mascot, receipts Pill, New run, grouped session list, Menu sheet, theme toggle, mobile drawer; client router; page registry with stubs | ui/src/App.tsx, ui/src/shell/**, ui/src/pages/registry.ts, ui/src/pages/*/index.tsx (stubs), ui/src/main.tsx, ui/src/index.css, test/ui/shell.test.tsx | `bun test test/ui/shell.test.tsx` (Today, Yesterday, Earlier grouping from fixture; hidden entries for stub pages) | 01 | MEDIUM |
248
+ | CPE-03 | Server scaffold: routes/index.ts with stub modules, schema tables local_repos and actions plus migration, audit helper, local discovery fills local_repos, GET /v1/repos | src/server/routes/index.ts, src/server/routes/*.ts (stubs), src/server/audit.ts, src/server/repos.ts, src/db/schema.ts, drizzle/**, src/server/app.ts, src/shipper/discover.ts, test/server/scaffold.test.ts | `bun test test/server/scaffold.test.ts` (ingest never writes local_repos; /v1/repos returns names only) | none | MEDIUM |
249
+ | CPE-04 | Run artifacts read API: events page, artifact allowlist, path containment | src/server/routes/artifacts.ts, test/server/artifacts.test.ts | `bun test test/server/artifacts.test.ts` (traversal, symlink escape, oversize, unknown name all refused) | 03 | HIGH |
250
+ | CPE-05 | SSE stream for one run and for the runs list | src/server/routes/stream.ts, test/server/stream.test.ts | `bun test test/server/stream.test.ts` | 03 | MEDIUM |
251
+ | 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
+ | 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
+ | 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 |
255
+ | 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
+ | 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
+ | 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 |
258
+ | CPE-13 | Cost and usage: /v1/stats/cost plus page with measured vs partial and budget banner | src/server/routes/cost.ts, ui/src/pages/cost/**, test/server/cost.test.ts, test/ui/cost.test.tsx | `bun test test/server/cost.test.ts test/ui/cost.test.tsx` | 02, 03 | MEDIUM |
259
+ | CPE-14 | Settings: GET, PUT /v1/config with schema validation, comment-preserving atomic write, If-Match; forms per schema section | src/server/routes/config.ts, ui/src/pages/settings/**, package.json (yaml dep), test/server/config.test.ts, test/ui/settings.test.tsx | `bun test test/server/config.test.ts` (comments survive round trip; invalid rejected; stale If-Match 409; secret-looking value refused) | 02, 03 | HIGH |
260
+ | CPE-15 | Models and providers: /v1/providers plus page | src/server/routes/providers.ts, ui/src/pages/models/**, test/server/providers.test.ts | `bun test test/server/providers.test.ts` (probe timeout honored; no secret value returned) | 02, 03 | MEDIUM |
261
+ | CPE-16 | Receipts: list, in-place verify, public key, verified-rate trend | src/server/routes/verify.ts, ui/src/pages/receipts/**, test/server/verify.test.ts | `bun test test/server/verify.test.ts` (tampered fixture fails verify) | 04 | MEDIUM |
262
+ | CPE-17 | Plans and traceability matrix from issue.json, plan.json, stages, files, receipt | ui/src/pages/plans/**, test/ui/plans.test.tsx | `bun test test/ui/plans.test.tsx` | 04 | MEDIUM |
263
+ | CPE-18 | Work board kanban from runs (issue to running to PR to verified or not proven) | ui/src/pages/board/**, test/ui/board.test.tsx | `bun test test/ui/board.test.tsx` | 02 | LOW |
264
+ | CPE-19 | Workspaces page: list from config, group status, run a workspace via POST /v1/runs body.workspace | ui/src/pages/workspaces/**, test/ui/workspaces.test.tsx | `bun test test/ui/workspaces.test.tsx` | 07, 14 | MEDIUM |
265
+ | CPE-20 | Integrations: /v1/integrations status probes plus page; connect writes env var names through /v1/config | src/server/routes/integrations.ts, ui/src/pages/integrations/**, test/server/integrations.test.ts | `bun test test/server/integrations.test.ts` | 14 | MEDIUM |
266
+ | CPE-21 | Notifications and Audit log: derived notifications, actions view | src/server/routes/notify.ts, src/server/routes/audit.ts, ui/src/pages/notifications/**, ui/src/pages/audit/**, test/server/notify.test.ts | `bun test test/server/notify.test.ts` | 03 | LOW |
267
+ | CPE-22 | Cmd+K palette, global search, shortcuts (Cmd+Enter, Cmd+N, Cmd+Shift+D, Esc) | ui/src/palette/**, test/ui/palette.test.tsx | `bun test test/ui/palette.test.tsx` | 02 | LOW |
268
+ | CPE-23 | Accessibility, mobile and visual parity: axe, keyboard path, 375 px layout, light and dark screenshot comparison to legacy captures | test/e2e/cp-ui.spec.ts, test/e2e/legacy-baseline/**, ui/playwright.config.ts | `bunx playwright test test/e2e/cp-ui.spec.ts` (headless, LOKI_NO_BROWSER=1) | 06, 08, 12 | MEDIUM |
269
+ | CPE-24 | Delete legacy dashboard at parity: dashboard-ui/, dashboard/static/, legacy server routes, their tests and package entries | dashboard-ui/**, dashboard/static/**, dashboard/server.py (UI routes), package.json files list, tests naming them | section 5 checklist all green plus `bash scripts/local-ci.sh` | all, section 5 | MEDIUM |
270
+
271
+ Parallelism: CPE-01 and CPE-03 start at once; after them up to 12 builders run in parallel (04, 05, 07, 09, 11, 12, 13, 14, 15, 18, 21, 22). HIGH slices (04, 07, 09, 14) carry the security review the founder asked for.
272
+
273
+ ## 7. Open questions
274
+ 1. Ground color: the shell's light-grey #F1F2F6 (founder-approved per build-standalone.js:113) or the components' warm cream #FFFEFB with midnight-purple dark #1A0F2E (unified-styles.js:24, :88)? This spec picks the shell; one screenshot pair for Loki settles it.
275
+ 2. Mascot: keep it beside the wordmark (it was part of the old look) or drop it for a cleaner Claude.ai-like header?
276
+ 3. Modernize, merge queue, PR risk review, schedules and memory have no v10 run events or API today. They stay hidden in 10.8.0 and get UI slices when their backends land; confirm that is acceptable for "no feature is CLI-only".
@@ -85,3 +85,7 @@ With `LOKI_SPEED=1` (default off), the implement, fix, wall and plan stage promp
85
85
  ## Slice 4 status: already-done check off the critical path (LOKI_SPEED=1)
86
86
 
87
87
  With `LOKI_SPEED=1` (default off), intake no longer waits on the cheap-model already-done check. Implement starts at once; the check runs only when deterministic hits exist, and its confirmation session runs in a pinned copy of the base tree extracted to a temporary directory outside the repo (`git archive -o` then `tar -x`, each exit code checked), so in-flight edits cannot satisfy it. A run stops as ALREADY_SATISFIED only when that session cites files unchanged since base; a bad base SHA or any extract failure fails closed (no session, not satisfied). Code: `loki-ts/src/features/speed/already_done_async.ts`, tests in `loki-ts/tests/engine10/already_done.test.ts`. Known follow-up (D61-04-F): the temporary copy can outlive a SIGTERM exit, and four race tests leave one copy each.
88
+
89
+ ## D82-FLAGS status: default on
90
+
91
+ Per the D82 founder directive, `LOKI_SPEED` is on unless set to `0` (decomposer routing, warm engine on a unix socket, stage prefix, deferred already-done check, lean keyword fallback, unit mode when `LOKI_UNIT_SPEC` is set). `LOKI_SPEED=0` restores the previous behaviour byte for byte. The other D82 opt-outs are `LOKI_VISUAL_EVIDENCE=0`, `LOKI_CONTRACT=0`, `LOKI_SLACK_INBOUND=0` (Slack stays inert until its credential is configured), `LOKI_CONTROL=0` and `LOKI_WORKSPACES=0`. Test: `loki-ts/tests/features/d82_default_on.test.ts`.
@@ -599,3 +599,118 @@ The r9 reviewer amended D80 and the CoS adopts the amendment as binding. The rea
599
599
  - The exit/abort/kill scan remains as defense in depth and is not the trust boundary.
600
600
  - The truncation check keeps its own unit test.
601
601
  The CTO ratifies this in the r10 HIGH review.
602
+
603
+ ## D80 amendment 2 (2026-10-03T13:26Z, CoS per D69, from the SEAL r10 opus HIGH review)
604
+ The r10 reviewer reproduced four forged PASS results ("Verified by Loki" on a repo with broken code) under the 13:14Z amendment. Each one used an npm test script that passed the allowlist:
605
+ - a node_modules/.bin/node shim
606
+ - `--test-reporter=<the package's own name>`
607
+ - a reporter in node_modules
608
+ - npm_config_node_options, a user ~/.npmrc, or a quoted .npmrc key
609
+ That amendment is NOT ratified. It is replaced by this rule, which the CoS adopts as binding:
610
+ 1. Coverage is granted only from a runner that loki-seal launches itself. The npm test script must be exactly `node --test` plus allowlisted flags and plain relative file paths. loki-seal then does NOT run `npm test`. It spawns `process.execPath` (an absolute path, no PATH lookup) with those exact arguments, with cwd set to the project root and NODE_OPTIONS, NODE_PATH, NODE_TEST_CONTEXT and every `npm_*` variable removed from the environment. No npm config file (project, user or global) is consulted.
611
+ 2. Allowlisted flags:
612
+ - `--test-reporter=` one of spec, tap, dot, junit or lcov (built-ins only, so a bare package name gives NOT VERIFIED)
613
+ - `--test-reporter-destination=stdout`
614
+ - `--test-isolation=process`
615
+ - `--test-concurrency=<n>`
616
+ - `--test-timeout=<n>`
617
+ 3. A pretest or posttest script, any other token, or any shell metacharacter gives NOT VERIFIED, with a stated reason.
618
+ 4. jest, vitest and any other runner resolved from the project (node_modules/.bin, or reporters and setup files defined in config) does not grant coverage. It gives NOT VERIFIED with a stated reason, and its red/green result still counts. Over-refusing is accepted (fail closed).
619
+ 5. The exit/abort/kill scan stays as defense in depth; it is not the trust boundary. The truncation check keeps its own unit test.
620
+ 6. Every case in 1 to 4 has a negative test that asserts its specific reason. That includes the six reproduced forges above.
621
+
622
+ ## D81 (2026-10-03T14:43Z, CoS per D68/D69): train/101 red is fixed forward with a revert deadline
623
+ - train/101 (e14834e53) Tests run 37129766523 failed on two reproducible, deterministic causes. Neither is the P9 flake.
624
+ - Shard 2: seal.test.js:1031 runs `node --test-isolation=none`, which the CI Node rejects ("bad option").
625
+ - Shard 3: cloud-dispatch R2-3. On GNU the writer overwrote a duplicated BOARD row (rc 0, want 15).
626
+ - Decision: two sonnet builders fix them forward on main, with a deadline of about 15:05Z.
627
+ - Any slice not fixed and TL-approved by then is reverted for train/102, and the rest ships as v10.6.15. This is the D68 rule "drop red slices".
628
+ - A failed rerun is not attempted, because both failures are deterministic.
629
+ - Each fix must keep fail-closed semantics: no skip, no weakened assertion, and nothing added to tests/moat/pending.txt.
630
+
631
+ ## D82 (2026-10-03T14:54Z, CoS per D69): founder directive 14:55Z, all features on by default, cost-cap rework, 10/10 program
632
+ Source: the founder's words, relayed by the peer session (autonomi-dev-76) at 14:55Z. Recorded as given; executed without founder waits.
633
+ 1. Default-on: visual evidence, spec-to-contract, D61 parallel/speed, Slack two-way, MCP tools, Control Plane and workspaces become default-on in the next train. Each env var stays as an opt-out (=0).
634
+ - A feature still in D12 review ships the same day its review passes.
635
+ - CTO guardrails, from security, which outranks speed:
636
+ - A default-on network listener binds loopback only.
637
+ - Anything that sends data off the machine (for example a Slack webhook) stays inert until its credential is configured. Default-on means "on when configured", never "prompt for or read stored secrets".
638
+ 2. Cost cap: the $20 default is removed.
639
+ - Subscription runs (CLI login, no API key) have no dollar cap and print one info line: "subscription: no dollar cap; usage counts against your plan limits".
640
+ - API-key runs default to a $100 cap.
641
+ - --max-cost and loki.yaml budgets.per_run override both. BUDGET_STOP stays exit 3.
642
+ - The start line, docs and tests are updated.
643
+ 3. 10/10 program, built in order (a) to (j):
644
+ - (a) browser e2e with a Playwright video and trace
645
+ - (b) loki merge queue
646
+ - (c) loki review with a deterministic risk score
647
+ - (d) project memory across runs
648
+ - (e) Control Plane mobile layout, roles and sign-in (single-admin token, then OIDC)
649
+ - (f) mobile emulator tests when the tools are installed
650
+ - (g) a REST API for runs
651
+ - (h) VS Code and JetBrains via ACP
652
+ - (i) Sentry intake
653
+ - (j) the D50 Sonnet lift fixes
654
+ - Plus a fresh gap-research pass (Devin, Factory, 8090, Vorflux, Claude Code). New items join the queue.
655
+ - An architect slices each item into small slices that keep CI green.
656
+ 4. Amended by the founder at 15:00Z and 15:02Z, relayed by the peer: "no testing", "10 releases every hour", "use least tokens".
657
+ - Until about 17:00Z, LOW and MEDIUM slices merge as built, with no agent-side review round. CI Tier A and Tier B are the gate, because nothing reaches npm without a green Tier B on its exact tree (D55).
658
+ - HIGH slices (moat, Seal, verifier, auth/sign-in, security) keep one opus D12 review. A peer relay cannot waive it.
659
+ - Models (D52): haiku for docs, flag flips, pins and mechanical edits; sonnet for feature code; opus only for HIGH review. Fresh agents get small briefs and return short results.
660
+ - Trains: cut one from whatever has merged as soon as the previous train's push has registered its CI runs. Never push while a release is running: a push during a release cancels its Tests (GUARD, memory "Pushing during a release cancels its Tests"). Never cancel a releasing train.
661
+ - The real ceiling is about 12 min per Tests run plus the release, so roughly 4 releases per hour. The achieved rate is reported honestly.
662
+ 5. Usage: the 85% weekly floor stands. At the floor, stop starting new work and record what is left in the handoff.
663
+
664
+ ## D83 (2026-10-03 15:20Z, founder via peer relay): enterprise-grade Control Plane UI
665
+ 1. Founder words: "i want enterprise grade UI, not just a dummy simple page ... make sure the previous UI design is used, I meant fonts, colors, UI looks and design ... even if it's a rewrite, I like Old UI".
666
+ 2. Supersedes the minimal CP-UI-SHELL look. The Control Plane reuses the legacy dashboard design system (fonts, serif wordmark, purple palette, light and dark themes, sidebar and right panel, card, KPI, badge, table and timeline components).
667
+ 3. Step 1: an opus architect writes docs/v10/CP-ENTERPRISE-UI.md (legacy inventory with KEEP/REWORK/DROP, design tokens, feature set drawn from Devin, Factory, 8090, Vorflux and Claude.ai, and the v10 API each page needs). Step 2: parallel sonnet builders, one per page, on a shared token package. Every number from real ingested data. Start-run and stop endpoints get an opus security review. Ships as 10.8.0; legacy dashboard code is deleted at parity.
668
+ 4. Does not hold 10.7.0, which ships at its cutoff. D82 also waived the D61 gate E evidence for the LOKI_SPEED default flip.
669
+ 5. Addendum (15:24Z, founder via peer relay): "i want fully controllable loki mode of sessions, configurations and anything from UI, but keep it super clean and lean like claude.ai UI and chatgpt UI, but with loki mode's old dashboard look, should feel amazing for users". Guiding principle of CP-ENTERPRISE-UI.md: full CLI parity in the UI, a lean conversation-style structure (session list plus one main pane, one New run input, run as a thread, everything else behind one settings entry), the legacy look on top, and no placeholder panels. loki.yaml write-back and the run control endpoints are HIGH.
670
+ 6. Spec open questions decided by the CoS under D69 (15:28Z): ground color is the shell light grey #F1F2F6, the mascot stays beside the wordmark (both are the old look the founder asked for; one screenshot pair goes to FOUNDER-QUEUE for a later veto). Merge queue (`loki merge`) and PR risk review (`loki review --risk --json`) DO have backends as of 10.7.0, so they get UI slices CPE-25 and CPE-26 wrapping those commands instead of staying hidden; schedules, memory and modernize stay hidden until a v10 backend exists.
671
+
672
+ ## D84 (2026-10-03 16:14Z, CoS per D68/D69): 10.7.0 re-cut content, CP shell fields read-only
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
+ 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
+ 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.
@@ -0,0 +1,155 @@
1
+ <!-- Engine constitution. Source: founder plan 2026-10-03 (autonomi-dev research/2026-10-03-engine-laws/PLAN.md), adopted as D86. -->
2
+
3
+ # Engine Laws: from one-off fixes to an enterprise-grade engine
4
+
5
+ Founder directive, 2026-10-03: "Use all intelligence in any session from the model and provider as needed, so our issues in Loki Mode won't impact users. Plan and ultrathink to make it enterprise grade. Not just one-offs: every issue and learning should be thought about at 100k feet."
6
+
7
+ ## 1. The trigger and the diagnosis
8
+
9
+ On FireLater#17, plain Claude Code fixed the issue and opened a good PR in about 2 minutes. Loki 10.6.14 took 11 minutes and $2.66, ended STALLED and opened a FAILED draft PR (#25). Six defects showed up in that one run. Read from the code, they come from four root classes. None of them is specific to FireLater.
10
+
11
+ | Symptom on FireLater#17 | Code root | Root class |
12
+ |---|---|---|
13
+ | Verify "Failed Suites 1" three times; the code passed 43/43 from backend/ | testmap.ts: fixed `npx vitest run <files>` strings, always run from repoDir | A. The harness assumes a repo shape instead of learning it |
14
+ | "visual evidence skipped: no package.json" | root-only package.json probe | A |
15
+ | Two fix rounds plus STALLED spent on a non-bug | verify does not separate "runner could not load" from "test failed"; fix.ts treats every vitest signature as a test failure | B. Failures are not attributed to an owner (code, env, harness, provider) |
16
+ | Route edits the issue required were reverted | e10ext/scope.ts: keyword overlap of plan and task text decides "unrelated", then `git restore` | C. A heuristic holds destructive authority |
17
+ | Implement ran below the user's raw intelligence | sizing.ts: cascadeImplementModel = wallModel = sonnet by default; implement brief and limitS 480 replace the agent's own exploration | D. Loki silently gives the user less intelligence than raw |
18
+ | PR body: "not recorded" for issue, why, scope and tests | pr_body.ts output not checked against real run data | E. Output contracts are untested on real runs |
19
+ | Control Plane stuck "in progress" after completion | no guarantee that every sink reaches a terminal state | F. No run-lifecycle invariant |
20
+
21
+ Each class has a law. Each law has one mechanism, plus one enforcement check that fails CI if the law is broken anywhere, not only in the stage the bug report named.
22
+
23
+ ## 2. The Engine Laws (constitution for every stage, present and future)
24
+
25
+ ### L0. The model decides, the harness proves (above L1 to L7; founder directive 2026-10-03, permanent)
26
+ - The model owns all knowledge and judgment about the user's repo and task: layout and package roots, the runner, command and cwd, whether there is a UI and how to boot it, files in scope, impacted tests, task size, failure ownership, and what the issue asks.
27
+ - The harness owns only mechanism: running what the model proposed and recording cwd, exit code, output and counts; sandboxing, budgets and process control; signing, receipts and integrity; terminal I/O; deterministic tamper checks, because the model never grades its own work.
28
+ - When execution contradicts the model, the output goes back to the model once. The verdict comes from execution evidence plus a separate reviewer call, never from the author.
29
+ - Review rule: reject any change that adds an `if` or a regex about the user's repo shape, language, framework or task wording. The fix is a prompt or schema change plus an execution check. Hardcoded tables are deleted once the model path is green on the Repo Shape Matrix. Slices: docs/v10/L0-WAVE1.md.
30
+
31
+ ### L1. Never below raw
32
+ A Loki run never gives the user less intelligence, a worse result or a meaningfully slower one than the same provider run raw.
33
+ - The default implement model and effort are the provider's best default for the user's account (what bare `claude` would use), or higher. Cheap models are only for mechanical sub-steps (repo map summaries, PR body prose, docs).
34
+ - Any downgrade (model, effort, context, time limit) is printed on the start line and recorded in the receipt. Nothing is silently reduced.
35
+ - Escalation goes UP: a repeated code failure escalates to the strongest model and effort the provider offers, with the full failure output and the agent's own diagnosis. This happens before STALLED, for every provider.
36
+ - Enforcement: the Parity Gate (section 4) blocks promotion to `latest` when Loki is below raw on the corpus.
37
+
38
+ ### L2. Fail closed on trust, fail open on work
39
+ - Trust surfaces fail CLOSED and may block: signing, receipt integrity, secrets, sandbox and permission boundaries, policy the user configured, and tests or CI config being deleted or weakened.
40
+ - Work surfaces fail OPEN: scope, the Wall, impacted-test selection, sizing, visual evidence, repo detection. A harness heuristic that is unsure keeps the agent's work, annotates it, and lowers the claim (NOT PROVEN). It never reverts, stalls or drafts.
41
+ - Enforcement: a static test lists every code path that calls `git restore`, `git checkout --`, `git reset` or file deletion on user files, or sets outcome STALLED, FAILED or draft. Each one must be classified trust or work, and work paths may not do it. A new destructive call fails CI until it is classified.
42
+
43
+ ### L3. Evidence outranks heuristics (authority ladder)
44
+ 1. Executed evidence: a command Loki ran, with its output, cwd and exit code.
45
+ 2. The agent's executed evidence: commands the agent ran in its session, taken from the transcript or tool log.
46
+ 3. Model judgment: the agent or a reviewer.
47
+ 4. Deterministic heuristics: keyword scope, sizing, repo-map overlap.
48
+
49
+ A lower rung may never override a higher one. A keyword heuristic cannot revert what a passing test run supports. A Loki check that ERRORED (not failed) yields to the agent's successful run of the same suite.
50
+
51
+ ### L4. Know the repo before judging it (Project Model)
52
+ At intake, one model discovery session reads the repo like a senior engineer and returns a schema-checked Project Model that cites the files behind each answer (L0). Every stage consumes it. No stage may re-derive repo shape on its own, and no harness table or probe is authoritative; the items below are what the model reads, not code the harness runs.
53
+ - Packages: every package root (package.json, pyproject, go.mod, Cargo.toml, pom or gradle, composer, Gemfile), its runner, and its exact test, lint, build and start commands.
54
+ - Workspace kind: single, npm/pnpm/yarn workspaces, turbo, nx, multi-root with no root manifest (FireLater), polyglot.
55
+ - Sources of truth, in order:
56
+ 1. loki.yaml overrides;
57
+ 2. AGENTS.md, CLAUDE.md, CONTRIBUTING and README test instructions;
58
+ 3. CI workflow files (.github/workflows: how the project's own CI actually runs tests);
59
+ 4. manifests and config files;
60
+ 5. conventions.
61
+ - Self-calibration: run each package's test command once as a baseline (this is also the Wall base run). If the runner fails to LOAD (0 tests collected, config not found, module resolution error), ask the agent once, cheaply: "how are tests run in this package?". Store the answer, rerun, and cache it per repo in .loki/project.json, keyed by manifest hashes. Users can edit it.
62
+ - Every command records its cwd. A test path is resolved to its nearest package root and made relative to it.
63
+ - Enforcement: no stage may spawn a test, lint or build command except through the Project Model API (a grep check in CI).
64
+
65
+ ### L5. Every failure has an owner
66
+ Every check result is one of PASS, FAIL, ERROR or SKIP, with an owner: code, env, harness or provider.
67
+ - Only FAIL owned by code drives fix rounds and counts toward STALLED.
68
+ - ERROR owned by harness or env triggers one self-repair (recalibrate the Project Model). If that does not fix it, the check is NOT PROVEN with a plain reason ("test runner could not load in backend/: <first error line>"). No paid fix rounds.
69
+ - ERROR owned by provider (billing, quota, auth, overload) goes to the existing fatal classifier.
70
+ - The receipt and PR list every NOT PROVEN item with its owner, so a user can tell "your code is broken" from "Loki could not check".
71
+ - Enforcement: a fixture set of runner outputs (load error, 0 collected, missing config, real assertion failure, timeout, OOM) for vitest, jest, node:test, pytest, go and cargo. The classifier must label each correctly.
72
+
73
+ ### L6. Every run terminates everywhere
74
+ Every sink reaches the same terminal state: events, receipt, PR, Control Plane, Slack and the CLI summary.
75
+ - The supervisor writes run.completed on every exit path, including crash and kill (signal handlers, plus a sweeper for dead PIDs).
76
+ - Control Plane ingest is idempotent and reconciles: a run with no live worker PID and no terminal event becomes ABORTED (with a reason) after a grace period.
77
+ - Enforcement: an e2e test kills a run at each stage and asserts terminal state in every sink.
78
+
79
+ ### L7. Outputs are contracts
80
+ The PR body, receipt, `--json` envelope and CLI summary have schemas. "not recorded" when the data exists is a test failure.
81
+ - Golden tests are built from real recorded runs (FireLater#17 included), not hand-made stubs.
82
+
83
+ ## 3. The learning system (how every future issue is handled at 100k feet)
84
+
85
+ No bug becomes a fix slice until the CoS has written its row in docs/v10/FAILURE-CLASSES.md, answering five questions:
86
+
87
+ 1. What did the user see, and how does it compare with raw provider output on the same task?
88
+ 2. Which law did it break (L1 to L7)? If none fits, propose a new law. That is a founder-level decision; record it in DECISIONS.
89
+ 3. Sibling sweep: which other stages, commands or providers share the same assumption? Grep and list them. The fix covers all of them, at the shared layer.
90
+ 4. Mechanism: the one shared place the fix lives (Project Model, the result classifier, the authority ladder, the lifecycle reconciler, the output schema).
91
+ 5. Regression: the corpus fixture or real-run golden that would have caught it, added in the same PR.
92
+
93
+ A one-off patch that answers question 4 with "this stage only" when siblings exist is rejected in review.
94
+
95
+ ## 4. Proof: the Parity Gate and the Repo Shape Matrix
96
+
97
+ - Repo Shape Matrix (the corpus). At least one real public repo or faithful fixture per shape:
98
+ - single npm;
99
+ - npm, pnpm and yarn workspaces;
100
+ - turbo;
101
+ - nx;
102
+ - multi-root with no root manifest (FireLater);
103
+ - python with uv, poetry and plain pip;
104
+ - go multi-module;
105
+ - rust workspace;
106
+ - java gradle and maven;
107
+ - polyglot (TS frontend plus Python backend).
108
+
109
+ Each shape has one small, one medium and one cross-cutting issue (FireLater#17 is the cross-cutting monorepo case).
110
+ - Parity Gate (extends the D49 first-run gate for `latest` promotion). Loki is compared with raw `claude -p` on the same issues, with hidden tests judging correctness.
111
+ - Correctness: Loki is at least raw on every shape.
112
+ - Time: small tasks within raw + 30s; medium and large tasks within raw x 1.3.
113
+ - Cost: at most raw x 1.2, unless the user turned on deeper checks.
114
+ - Zero harness-owned FAILED or STALLED outcomes.
115
+ - Results go to METRICS.md. A regression blocks `latest`; `next` keeps shipping.
116
+ - Field signal, which stays free and private: `loki report <run-id>` builds a redacted bundle the user can attach to an issue. Nothing is sent automatically.
117
+
118
+ ## 5. Enterprise posture (what a platform team needs before adopting)
119
+
120
+ - Predictability: published SLOs, the Parity Gate numbers per release, and the same result on the same input (models are pinned and recorded in the receipt).
121
+ - Explainability: every outcome has one plain sentence of cause and an owner. Nothing is "not recorded".
122
+ - Policy without friction: loki.yaml `scope: advisory|enforce`, where advisory is the default and enforce is opt-in for regulated repos. Enforce runs on the Project Model and the contract, never on keywords alone, and its reverts are listed with a one-command restore.
123
+ - Audit: the receipt carries the Project Model hash, the commands with their cwd, the owner attribution and any model or effort changes.
124
+ - No silent degradation, anywhere.
125
+
126
+ ## 6. Implementation order (delete first, then build the shared layer)
127
+
128
+ Wave 0, same day. Flips and deletions, each small:
129
+ 1. The scope default becomes advisory: annotate, never revert (L2). Keep enforce behind loki.yaml.
130
+ 2. Cascade default off: implement runs on the provider's best default model and effort (L1). Fix-round escalation goes up to the strongest model.
131
+ 3. A load-error or 0-collected verify result is ERROR with owner harness. It never feeds fix rounds or STALLED (L5, minimal form).
132
+ 4. PR body fields come from intake, plan, diff and evidence, with a golden test from the FireLater#17 recording (L7).
133
+ 5. Control Plane: ingest run.completed, plus a dead-PID reconciler (L6, minimal form).
134
+
135
+ Wave 1. Shared layers, built in parallel by sonnet builders with opus review for anything touching trust:
136
+ 6. Project Model module (L4) with AGENTS.md, CLAUDE.md and CI-workflow parsing, a baseline calibration run and the .loki/project.json cache. Testmap, verify, the Wall, visual evidence, the first-run gate and deep all consume it.
137
+ 7. Result classifier with owner attribution, plus the runner fixture set (L5).
138
+ 8. Authority ladder in seal: the agent's own passing test commands count as evidence when Loki's check errored (L3).
139
+ 9. Lifecycle invariant across all sinks, plus the kill-at-each-stage e2e (L6).
140
+ 10. The static checks from L2 and L4.
141
+
142
+ Wave 2. Proof:
143
+ 11. The Repo Shape Matrix corpus and the Parity Gate wired into promotion to `latest`.
144
+ 12. FAILURE-CLASSES.md seeded with the FireLater#17 rows and every past class from MEDIUM-ANALYSIS.md.
145
+
146
+ ## 7. Acceptance
147
+
148
+ - FireLater#17 rerun on the new build:
149
+ - VERIFIED, with a ready (not draft) PR;
150
+ - the route edits kept;
151
+ - visual evidence found in backend/ or frontend/;
152
+ - time within raw + 30s and cost at most raw x 1.2.
153
+ - The Parity Gate is green on the matrix, and the table is published in METRICS.md.
154
+ - Every law has its enforcement check in CI.
155
+ - The CoS steering rule (section 3) is written into OPERATING-MODEL.md, and new bug reports follow it.