loki-mode 11.74.2 → 11.75.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/SKILL.md +2 -3
- package/VERSION +1 -1
- package/autonomy/completion-council.sh +10 -10
- package/autonomy/council-v2.sh +4 -4
- package/autonomy/grill.sh +1 -1
- package/autonomy/lib/browser-open.sh +1 -1
- package/autonomy/lib/chat.sh +1 -1
- package/autonomy/lib/cockpit-render.sh +1 -1
- package/autonomy/lib/done-recognition.sh +4 -4
- package/autonomy/lib/efficiency_cost.py +1 -1
- package/autonomy/lib/engine10-push.sh +2 -2
- package/autonomy/lib/prd-enrich.sh +1 -1
- package/autonomy/lib/proof-check.sh +1 -1
- package/autonomy/lib/proof-generator.py +3 -3
- package/autonomy/lib/proof-pr.sh +1 -1
- package/autonomy/lib/skill-link-heal.sh +1 -1
- package/autonomy/lib/voter-agents.sh +1 -1
- package/autonomy/loki +26 -37
- package/autonomy/prd-checklist.sh +1 -1
- package/autonomy/receipt_jwt.py +1 -1
- package/autonomy/run.sh +28 -28
- package/autonomy/trigger-schedule.py +6 -414
- package/autonomy/tui.sh +1 -1
- package/autonomy/verify.sh +4 -4
- package/completions/loki.bash +0 -5
- package/dashboard/__init__.py +1 -1
- package/docs/ARCHITECTURE.md +1 -2
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/COMPONENTS.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/ROUTING-EVIDENCE.md +1 -2
- package/docs/V10-RESEARCH.md +1 -1
- package/docs/dev/architecture-reference.md +3 -7
- package/docs/dev/project-structure.md +1 -4
- package/docs/dev/release-checklist.md +13 -31
- package/docs/research-2026-07/OBSERVABILITY-TOOL-SPEC.md +1 -1
- package/docs/v11/MARKET-SLICES.md +1 -1
- package/docs/v11/REGISTRIES.md +1 -1
- package/docs/v11/ROUTER-1.md +2 -2
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/skills/extending.md +2 -3
- package/skills/factory-operations.md +11 -18
- package/skills/release-cadence.md +2 -2
- package/web-app/dist/assets/{AdminPage-jkjilfbl.js → AdminPage-xKgtIhk2.js} +1 -1
- package/web-app/dist/assets/{Avatar-bd5JWkSJ.js → Avatar-Q14AHox9.js} +1 -1
- package/web-app/dist/assets/{Badge-DVRit2Xw.js → Badge-yk5M-lip.js} +1 -1
- package/web-app/dist/assets/{Button-BNAB-pVZ.js → Button-ynznk0At.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-DpG29h_w.js → CockpitPage-C8B765za.js} +1 -1
- package/web-app/dist/assets/{ComparePage-Dasg5V41.js → ComparePage-DqzmWKnf.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-DJojse6b.js → ErrorBoundary-DdBPd_Lq.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-Blxw7_u1.js → EvidenceReceiptPanel-jb4Tp38b.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-BBvSFj80.js → GitHubIssuesPanel-xJQiLcxs.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BCIKeSBg.js → GitHubPRsPanel-84W3Dhk_.js} +1 -1
- package/web-app/dist/assets/{HomePage-C7d__oNG.js → HomePage-St1Xl2tu.js} +2 -2
- package/web-app/dist/assets/{LoginPage-BXljL3yY.js → LoginPage-jRt0NUHb.js} +1 -1
- package/web-app/dist/assets/{MagicPage-Xjkts_yE.js → MagicPage-CQLFe7LR.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-kQvVp-j2.js → MetricsPage-zzX9eTC5.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-D-4ZlEaO.js → NotFoundPage-DDu023SY.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-DfzR5RXP.js → ProjectPage-D60UURaH.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DFDsWzkV.js → ProjectsPage-DqVsKxlt.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-CLPIoYT3.js → SettingsPage-G7pPKvo0.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-PZKkyGeY.js → ShowcasePage-CrU_aKgS.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-BsBlcnzo.js → SystemSettingsPage-ClKGQFsB.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-BSjgNhoU.js → TeamsPage-B530vSNe.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-W2KeAzbg.js → TemplatesPage-COmv_Cqd.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-BjroTiCC.js → TerminalOutput-CufG9YzF.js} +1 -1
- package/web-app/dist/assets/{activity-BXZ5YYes.js → activity-Ct1Updr6.js} +1 -1
- package/web-app/dist/assets/{bell-D1urp5pa.js → bell-rcvhQuGr.js} +1 -1
- package/web-app/dist/assets/{bot-Chedf2bF.js → bot-DzeqEI-b.js} +1 -1
- package/web-app/dist/assets/{check-DhaCuOCV.js → check-zacnZHyC.js} +1 -1
- package/web-app/dist/assets/{chevron-left-D7BpQyA6.js → chevron-left-Lxnkl8Qg.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DnGvQ_AQ.js → circle-alert-DoqSdQdB.js} +1 -1
- package/web-app/dist/assets/{clock-CqfxWhHM.js → clock-B7bJcVIC.js} +1 -1
- package/web-app/dist/assets/{cloud-BKxp5AWB.js → cloud-DdA9Bu6q.js} +1 -1
- package/web-app/dist/assets/{code-xml-BDQ6GBtt.js → code-xml-CAZEZ9T8.js} +1 -1
- package/web-app/dist/assets/{database-BmpEx1y_.js → database-Da2GkEIN.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-DYNY9R_C.js → dollar-sign-DjDiG-37.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-BJi0IBFd.js → file-code-corner-CSL-Jij-.js} +1 -1
- package/web-app/dist/assets/{file-plus-Dqyb2bcQ.js → file-plus-02DRA8pV.js} +1 -1
- package/web-app/dist/assets/{globe-DPh4RWfM.js → globe-CGyB90kK.js} +1 -1
- package/web-app/dist/assets/{hammer-B3xnuoA1.js → hammer-BaQB96TG.js} +1 -1
- package/web-app/dist/assets/{index-BpX8DcTr.js → index-lcoI1_Kk.js} +3 -3
- package/web-app/dist/assets/{layers-BRCmyCW8.js → layers-BWJBvoeg.js} +1 -1
- package/web-app/dist/assets/{loader-circle-n07Pky0M.js → loader-circle-CdcI0FeS.js} +1 -1
- package/web-app/dist/assets/{lock-BWqOuQmS.js → lock-BBkw5NJx.js} +1 -1
- package/web-app/dist/assets/{package-BJlB_Z-Z.js → package-BpPRO3LM.js} +1 -1
- package/web-app/dist/assets/{plus-oH17BZu2.js → plus-D7XbyK29.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-CPQ476LL.js → refresh-cw-DLG3hyAi.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-7hLvOcnS.js → rotate-ccw-Bqau4R_S.js} +1 -1
- package/web-app/dist/assets/{scroll-text-BCmLauQn.js → scroll-text-BtIL3cNk.js} +1 -1
- package/web-app/dist/assets/{server-DfTfvW84.js → server-tZCmZ4yH.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CaeGRq19.js → shield-alert-K5JXzFKg.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-Dz-l2GPC.js → thumbs-up-CHCVyJdw.js} +1 -1
- package/web-app/dist/assets/{trash-2-B-OsDmSo.js → trash-2-DncNxVq0.js} +1 -1
- package/web-app/dist/assets/{trending-down-CXTFOxzq.js → trending-down-D8Bp0azX.js} +1 -1
- package/web-app/dist/assets/{trending-up-FQEdqr3v.js → trending-up-AixETdKR.js} +1 -1
- package/web-app/dist/assets/{upload-CacWSNTg.js → upload-VCbjFn2H.js} +1 -1
- package/web-app/dist/assets/{usePolling-cIjZ9qd2.js → usePolling-CQvKD2Jj.js} +1 -1
- package/web-app/dist/assets/{user-DAouWFHi.js → user-SK-YguQ6.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/autonomy/company-seats.json +0 -82
- package/docs/COMPETITIVE-INTEL-2026-09.md +0 -444
- package/docs/FOUNDER-DECISIONS-TRUST-SEMANTICS-2026-08-01.md +0 -145
- package/docs/FOUNDER-STATUS-AND-DECISIONS-2026-07-01.md +0 -132
- package/docs/LOKI-10-BUILD-PROMPT.md +0 -350
- package/docs/STRATEGY-2026-2028.md +0 -124
- package/docs/V10-VISION.md +0 -161
- package/docs/v10/ADOPTION-PLAN.md +0 -375
- package/docs/v10/ARCHITECT-CUTS.md +0 -744
- package/docs/v10/BACKLOG.md +0 -231
- package/docs/v10/BOARD.md +0 -1403
- package/docs/v10/CONTROL-PLANE.md +0 -120
- package/docs/v10/CONTROL.md +0 -36
- package/docs/v10/CP-ASK-PLAN.md +0 -85
- package/docs/v10/CP-ENTERPRISE-UI.md +0 -537
- package/docs/v10/D51-PHASE-B.md +0 -120
- package/docs/v10/D61-SPEED.md +0 -105
- package/docs/v10/D63-CARDS.md +0 -354
- package/docs/v10/DECISIONS.md +0 -915
- package/docs/v10/E2E-D65.md +0 -123
- package/docs/v10/ENGINE-LAWS.md +0 -163
- package/docs/v10/ENGINE-MEASURE.md +0 -69
- package/docs/v10/ENGINE.md +0 -743
- package/docs/v10/FAILURE-CLASSES.md +0 -2026
- package/docs/v10/FC21B-FC22-PLAN.md +0 -107
- package/docs/v10/FIRST-RUN-GATE.md +0 -39
- package/docs/v10/FOUNDER-QUEUE.md +0 -29
- package/docs/v10/GAP-RESEARCH-1003.md +0 -32
- package/docs/v10/GUARDS.md +0 -883
- package/docs/v10/L0-WAVE1.md +0 -81
- package/docs/v10/LEGACY-REMOVAL.md +0 -408
- package/docs/v10/MEDIUM-ANALYSIS.md +0 -346
- package/docs/v10/METRICS.md +0 -645
- package/docs/v10/MODERNIZE.md +0 -437
- package/docs/v10/OPENCODE-PARITY-PLAN.md +0 -84
- package/docs/v10/OPERATING-MODEL.md +0 -60
- package/docs/v10/PLAN-V12.md +0 -896
- package/docs/v10/PROGRESS.md +0 -2735
- package/docs/v10/RELEASE-11.md +0 -77
- package/docs/v10/RETRO-2026.md +0 -650
- package/docs/v10/ROADMAP-D63.md +0 -35
- package/docs/v10/SCALE.md +0 -140
- package/docs/v10/SCORECARD-PLAN.md +0 -250
- package/docs/v10/SWARM-PROMPT.md +0 -98
- package/docs/v10/SWARM.md +0 -293
- package/docs/v10/cp-redesign/PARITY.md +0 -188
- package/docs/v10/cp-redesign/legacy/INDEX.md +0 -1167
- package/docs/v10/roadmap-10/01-measurement.md +0 -113
- package/docs/v10/roadmap-10/02-cost.md +0 -75
- package/docs/v10/roadmap-10/03-speed.md +0 -65
- package/docs/v10/roadmap-10/04-first-run.md +0 -61
- package/docs/v10/roadmap-10/05-deploy.md +0 -61
- package/docs/v10/roadmap-10/06-stability.md +0 -64
- package/docs/v10/roadmap-10/07-quality.md +0 -57
- package/docs/v10/roadmap-10/08-proof.md +0 -48
- package/docs/v10/roadmap-10/09-safety.md +0 -74
- package/docs/v10/roadmap-10/README.md +0 -1464
- package/skills/sdlc-fleet.md +0 -170
- package/tools/cockpit/SPEC.md +0 -275
- package/tools/cockpit/index.html +0 -146
- package/tools/cockpit/roi-basis.json +0 -33
- package/tools/cockpit/server.py +0 -946
package/docs/v10/BACKLOG.md
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
# Backlog
|
|
2
|
-
|
|
3
|
-
Ranked. Moat work and red-main fixes always rank first. Each item: milestone,
|
|
4
|
-
the metric it moves, status. Plans live in the item.
|
|
5
|
-
|
|
6
|
-
Status values: todo, in progress, shipped (version), parked (reason).
|
|
7
|
-
|
|
8
|
-
## Now
|
|
9
|
-
|
|
10
|
-
1. **Moat suite `tests/moat/` (M0).** Metric: moat properties proven (0 of 9 measured before this). Status: in progress (cycle 1).
|
|
11
|
-
Plan: one script per property emitting `CASE <id> PASS|FAIL`; runner enforces a shrink-only `pending.txt` ratcheted against the last release tag (D2); registered in the local-ci fast tier and a dedicated "Moat suite" job in the Tests workflow (tags fetched). Enforced now: P1 portable proof (with two fixes: Bun `--jwks` passthrough, stripped signature fails), P6 in-place brownfield, the P2 subset that holds. Everything else lands as real failing cases, pending with a milestone.
|
|
12
|
-
|
|
13
|
-
## Next (moat gaps the audits found, 2026-09-25)
|
|
14
|
-
|
|
15
|
-
2. **P7 no fabricated data (M7, pulled forward: moat).** Admin page mounts three sample-data panels (`web-app/src/pages/AdminPage.tsx:393,401,405`); unmeasured cost rendered as `$0.00` in `loki-fleet.js:52`, `loki-analytics.js:428`, `ProjectWorkspace.tsx:804`. Fix, rebuild bundles, promote the P7 cases.
|
|
16
|
-
3. **P9 Rule of Two (M3, pulled forward: moat).** `loki-issue-to-pr.yml` holds issue text, secrets and push in one step; no `author_association` gate on `/loki`; checkout persists credentials; provider env keeps `GH_TOKEN`. Split read and push jobs; scrub tokens from the provider env.
|
|
17
|
-
4. **P2 remaining honest-verdict gaps.** Council approval on inconclusive evidence exits 0 (M2 Seal verdict); `loki verify` and `--fast` exit-code renumber (v10.0.0, breaking).
|
|
18
|
-
5. **P3 the Wall + P8 load-bearing proof (M2).** Separate check-author context; freeze and hash checks; no-op ablation in the Seal with N/A path.
|
|
19
|
-
6. **P4 model freedom (M0).** Add `claude-opus-5-5` to the catalog after confirming the id; seeded-defect corpus (100+ mostly deterministic defects); floor vs top wrong-pass measurement.
|
|
20
|
-
7. **P5 sovereignty (M9).** Egress-blocked start, seal, verify; `doctor --airgap` false "air-gap ready" for opencode with a remote default.
|
|
21
|
-
|
|
22
|
-
## M0 measurement (after the moat suite)
|
|
23
|
-
|
|
24
|
-
8. Factory eval: greenfield and brownfield items with known-good outcomes; Seal rate, cost per sealed change, lead time, human touches; top, floor, routed.
|
|
25
|
-
9. Seeded-defect corpus (shared with item 6).
|
|
26
|
-
10. Adoption eval: scripted fresh-machine run, time to first sealed PR, decisions asked.
|
|
27
|
-
11. Head-to-head arms: raw Claude Code (Opus 5.5), raw Codex (through opencode/OpenAI route, or recorded as a gap), hidden tests.
|
|
28
|
-
12. Baselines into `METRICS.md`.
|
|
29
|
-
|
|
30
|
-
## Carried over from v9
|
|
31
|
-
|
|
32
|
-
13. `docs/INSTALLATION.md:446` pins `asklokesh/loki-mode:8.0.0` in a live `docker run` block; add the line to the release bump list, not just the value.
|
|
33
|
-
14. Work selector `select_next_work()` in worktree branch `worktree-agent-a8fad9a6e301fe297` (19/0 tests, 8 mutations verified). Candidate for M5 backlog mode.
|
|
34
|
-
|
|
35
|
-
## Found in cycle 1 (2026-09-25)
|
|
36
|
-
|
|
37
|
-
15. **P6 untracked files swept into the session commit (high, data risk).** `commit_session_changes` (`autonomy/run.sh:9207`) runs `git add -A`, committing the user's pre-existing untracked files onto the Loki branch; a later checkout of the base removes them from the working tree. Snapshot untracked files at session start and exclude them. Case `P6.untracked-not-swept`.
|
|
38
|
-
16. **py_compile artifacts land in brownfield commits.** Static-analysis gate (`autonomy/run.sh:10782`) writes `__pycache__/*.pyc` into the user's repo, then 9207 commits it.
|
|
39
|
-
17. **Dashboard focus POST fires with `LOKI_DASHBOARD=false`** (`autonomy/run.sh:22467-22474`).
|
|
40
|
-
18. **Caveman bootstrap makes an outbound attempt and installs a global `~/.claude` SessionStart hook by default** (`autonomy/lib/claude-flags.sh:787`). Sovereignty and simplicity: an air-gapped run still tries egress; a tool silently editing the user's global Claude Code config needs a default-off decision.
|
|
41
|
-
19. **Remote stripped signature passes.** `loki_remote_verify_receipt` treats an unattested remote receipt as UNSIGNED exit 0 even when the server publishes a JWKS (pinned by `tests/test-remote-attestation-verdict.sh` test 4).
|
|
42
|
-
20. **`loki_proof_attestation_check` accepts plain `http://` JWKS URLs** (MITM controls the key set). Require https or warn.
|
|
43
|
-
21. **Seatbelt test fails on this host** (D5). Exit 32 unexplained; investigate on macOS 27.
|
|
44
|
-
22. **Orphaned `sleep 300` from the resource monitor** after `loki start` exits.
|
|
45
|
-
23. **`tests/lib-extract-client-paths.mjs` / `lib-match-client-routes.py` hardcode the main checkout path**, so `tests/test-verify-client-routes.sh` checks the wrong tree from a worktree or CI.
|
|
46
|
-
24. **Bun route: `doctor --airgap` rejected** (case `P5.airgap-audit-default-route`), **`--session-model opus` rejected and per-tier `LOKI_CLAUDE_MODEL_*` ignored** (case `P4.three-setups-resolve`).
|
|
47
|
-
|
|
48
|
-
25. **`loki ci --report` crashes on large diffs** with "Argument list too long" (`autonomy/loki:33811` passes the diff to python3 as argv; exit 126). Seen on PR #216 and a 2026-08-30 PR via the "Loki CI Quality Gate" workflow, which runs the published package. Pass the diff on stdin or a file.
|
|
49
|
-
26. **Bun Parity `doctor-json` flake:** `disk.available_gb` read 94 vs 95 between the two routes on macOS (PR #216). Normalize or drop the value in the parity comparison.
|
|
50
|
-
27. **(Resolved in cycle 4: a measurement bug, not a product bug. FastAPI 0.141 keeps included routers as lazy entries in `app.routes`; the routes were serving all along, `app.openapi()` is identical on both versions.) Dashboard routes vanish on newer FastAPI:** a clean `requirements-test.txt` install resolves FastAPI 0.141.1 / Starlette 1.7.0, where `dashboard.server.app.routes` has 191 routes and zero `/api/v2` paths, against 218 and 24 on FastAPI 0.128.0 (slice Z measurement). Users installing today may get a dashboard missing its v2 API. Pin or fix.
|
|
51
|
-
|
|
52
|
-
28. **Moat: pending-failure fingerprints.** A pending case that starts failing for a different reason (for example its own positive control broke) stays green. Give each pending entry an expected failure reason and fail on a mismatch (council round 2).
|
|
53
|
-
29. **(Resolved in cycle 4: the P7 matcher asks the app router directly and fails closed per router.) P7 route count depends on the host** (9 missing on macOS, 21 on Linux CI) because optional routers do not mount there; tied to item 27.
|
|
54
|
-
30. **P4 results need provenance.** Once the corpus exists, a hand-written per-defect outcomes file could still pass; require a verifiable receipt per outcome.
|
|
55
|
-
31. **`proof-verify.py` reads "drift unverifiable" (not a git tree, no base_sha) as 1 (tampered)**; it should be 2 (could not check). (The Bun timeout part is fixed: exits above 128 map to 2.)
|
|
56
|
-
32. **Docs tell npm users to run `doctor --airgap`** (`docs/air-gapped.md:48`, `deploy/helm/README.md:413`), which the default route rejects. Note `LOKI_LEGACY_BASH=1` until `P5.airgap-audit-default-route` is fixed.
|
|
57
|
-
33. **Council member vote: `runner=none` counts as a positive signal while a suite that ran zero tests does not.** Decide one rule.
|
|
58
|
-
|
|
59
|
-
34. **M2 builders: P3 and P8 must be wired, not just present.** `P8` drives `autonomy/lib/ablation.py` directly and `P3.check-author-context-excludes-implementation` drives `check_author.py` directly. Before promoting either, add an assertion that a stub-provider `run.sh` session (as P5/P6 drive one) records `facts.ablation` and invokes the check-author step (council round 4).
|
|
60
|
-
35. **Moat runner self-test: 0-byte baseline file.** Dropping the `git grep -L` empty-file listing leaves the self-test green; the code path was checked by hand. Add a case.
|
|
61
|
-
36. **P7 scanners: refuse a zero-file scan** (`SCANNED>0`), so a moved directory cannot read PASS.
|
|
62
|
-
|
|
63
|
-
37. **Bun route passes an inconclusive test result (high, honest verdict).** `loki-ts/src/runner/quality_gates.ts:451-458` `runTestCoverage` returns `passed: true` for `pass: "inconclusive"` on the default route (council round 5). Same class as the council `pass` readers fixed in v9.52.0.
|
|
64
|
-
38. **Council: a missing `pass` key is labelled `no_tests_executed`**; use a distinct reason such as `no_pass_recorded` (`autonomy/completion-council.sh` ~1985).
|
|
65
|
-
39. **Attestation edge labels:** `{"keys": []}` reads FAILED (exit 1) rather than NOT CHECKED; `attestation: false` reads UNSIGNED on the remote render but FAILED locally. Neither is a false pass.
|
|
66
|
-
40. **P3 prompt case is phrase-based.** `P3.implementer-prompt-has-no-check-authoring` passes on the absence of phrases; pair it with a behavioral assertion (the implementer session does not write the checklist) before promoting.
|
|
67
|
-
41. **P1.different-tree-fails lacks an in-script no-edit control** (checked by hand: unedited copy verifies 0).
|
|
68
|
-
42. **`doctor --airgap` "local" is a substring match** (`ollama|localhost|127.0.0.1|lmstudio`) and ignores a remote `OLLAMA_HOST`.
|
|
69
|
-
|
|
70
|
-
43. **Audit every `python3 -c` / `python3 -` on a verdict path for cwd module shadowing (high, honest verdict).** Apply D7 (`python3 -E` plus the `sys.path` filter, or a neutral cwd); the four `completion-council.sh` test-results readers are `python3 -c` calls run from the agent's repo. Council round 6 proved a committed `hashlib.py` could print "attestation: VERIFIED" through the attestation heredocs (fixed in v9.52.0). The same class likely exists wherever the runner or council runs inline Python with the cwd inside the agent's repo (the evidence gate reading test results, checklist verification), where the agent under test can write `json.py`. Guard with `sys.path[:] = [p for p in sys.path if p not in ("", ".")]` or run from a neutral cwd, and add a shadow-module moat case.
|
|
71
|
-
44. **P9 injection case: also grep the run HOME and provider-visible files for the canaries** (credential helpers, `~/.config/gh/hosts.yml`), not only env and argv, before promoting.
|
|
72
|
-
45. **P4.three-setups-resolve pass bar:** a documented spelling that silently dispatches another model (for example `--session-model high` sending sonnet) must fail the case, not appear as a note.
|
|
73
|
-
|
|
74
|
-
46. **P2 advisory-only case: match the control.** Its positive control differs from the probe in two variables (gate type and tests yes/no); use an exogenous gate with no tests expecting VERIFIED WITH GAPS.
|
|
75
|
-
47. **Refuse bootstrap on release commits once any moat release exists on origin** (a hotfix branch cut before the first moat release has no carrying tag and runs in bootstrap; labelled, but unratcheted).
|
|
76
|
-
|
|
77
|
-
48. **Same-class hardening beyond D7:** `loki outcomes canary verify` and inline `python3 -` heredocs for `proof share`/`show` still run with the cwd importable; a PATH with an empty component lets a committed `gpg`/`git`/`python3` in the checkout answer (absolute tool paths or scrub empty PATH components on verify paths).
|
|
78
|
-
49. **Verifier stdout vs exit code:** on ABSENT / NOT CHECKED the base verifier's JSON (`ok: true`) is still printed while the exit is 1/2; a stdout-only consumer reads a pass. Emit the final verdict in the JSON too.
|
|
79
|
-
50. **Remote NOT CHECKED returns 0; local returns 2.** Align or document.
|
|
80
|
-
51. **With `-E`, cryptography supplied via `PYTHONPATH`/`PYTHONUSERBASE` reads NOT CHECKED**; say so in the NOT CHECKED message.
|
|
81
|
-
52. **CI check name:** "Moat suite" shows green at 0 of 9; consider a name that says "no rule failed" so the check mark is not read as "moat proven" (the step summary already carries the count).
|
|
82
|
-
|
|
83
|
-
53. **Checklist verification still imports from the agent repo:** `autonomy/prd-checklist.sh` (a script call near 994 and about 9 inline `python3 -c` sites) is outside the cycle-2 fix; apply D7 there next (cycle-2 slice S).
|
|
84
|
-
54. **Council helpers still unguarded:** `autonomy/lib/voter-agents.sh` (3 sites parse voter output), `autonomy/council-v2.sh` (7), `autonomy/lib/done-recognition.sh` (16), `autonomy/lib/proof-check.sh` (3); about 217 non-verdict inline sites in `run.sh`; script-form calls (claim_grounding, requirements helper, deadline.py) inherit `PYTHONPATH`. Managed council inserts `PROJECT_DIR or os.getcwd()` on `sys.path` behind experimental flags.
|
|
85
|
-
55. **Zero-test honesty on bash:** `enforce_test_coverage`'s #82 zero-test branch downgrades only the JSON record; `test_passed` stays true, so `run.sh` (~12533) still touches `quality/unit-tests.pass` and logs "passed". `evidence-gate-details.json` records `tests.pass: true` for every inconclusive outcome.
|
|
86
|
-
56. **Bun npm-test fallback has no zero-test detection**, and the Bun reader uses `passed`/`failed` while the bash writer emits `passed_count`/`failed_count` (the detail shows an unmeasured failed=0).
|
|
87
|
-
|
|
88
|
-
57. **Resume must re-snapshot untracked files (data risk).** The snapshot is taken only when a session branch is minted; on the resume and already-on-loki paths (`run.sh` ~9100-9119) a file the user created between sessions is swept into the commit and removed from disk on checkout of the base. Add the current untracked list to the snapshot on both reuse paths (cycle-2 council).
|
|
89
|
-
58. **Gitignored user files are swept when the agent rewrites `.gitignore` (data risk).** Also snapshot `git ls-files -z --others --ignored --exclude-standard --directory` and prefix-match directory entries in `workspace_diff` (cycle-2 council).
|
|
90
|
-
59. **Agent edits to pre-existing untracked files are omitted from the receipt (new in v9.53.0).** Store a blob hash per snapshot entry; list a path whose hash changed (for example `preexisting_modified`) while still never committing the user's file (cycle-2 council). Not a false pass: no verdict reads the list.
|
|
91
|
-
60. **Bun `runTestCoverage` accepts a stale `test-results.json`** (no freshness check against `.loki/quality/.test-results.iter`), and an inconclusive coverage still lands in `GateOutcome.passed[]` with an "(gate did not run)" log line.
|
|
92
|
-
|
|
93
|
-
61. **`evidence-block.json` still writes the raw `$test_pass`** (`completion-council.sh` ~2792, block path), so `tests.pass` can read true for an inconclusive test axis when another axis blocks.
|
|
94
|
-
62. **`enforce_test_coverage` monorepo-custom-rejected path** records `pass: true` / `verified` and touches `unit-tests.pass` when `LOKI_MONOREPO_TEST_CMD` is rejected and the gate is skipped.
|
|
95
|
-
63. **`council_augment_from_managed_memory`** (`completion-council.sh` ~228) runs `cd "${PROJECT_DIR:-$(pwd)}"` then `python3 -m memory.managed_memory.retrieve`; with `PROJECT_DIR` unset it can run the agent repo's own `memory/` package into the council prompt.
|
|
96
|
-
64. **A test script like `exit 0` still reads as a pass on both routes** (the zero-test detector acts only on positive evidence of zero tests); `node --test` behind an npm script is not detected. The Bun freshness marker is agent-writable.
|
|
97
|
-
65. **(Fixed for interrupt and kill in cycle 3 via `.loki/state/session-created.z`; see 86 for limits.) Previous-session leftovers become "pre-existing" after a crash** (cycle-3 disclosure): files left uncommitted by a crashed or secret-scan-aborted session are recorded as pre-existing on the next run and stay on disk, uncommitted.
|
|
98
|
-
|
|
99
|
-
66. **Ignored `dir/` snapshot entries hide agent files under them.** If the agent un-ignores `build/` and creates `build/agent.js`, the literal `build/` reset unstages it and the receipt's coverage check hides it; an agent edit to a user file under that entry is not disclosed (no per-file hash for dir entries). At least report new or changed paths covered only by a dir entry (cycle-3 council).
|
|
100
|
-
67. **Deletions and ignored edits are not disclosed.** An agent `rm` of a pre-existing untracked user file, or an edit to a still-ignored pre-existing file (`.env.local`), leaves the receipt silent; iterate the recorded hash map (missing = deleted, changed = modified), with care for gate-regenerated noise (cycle-3 council).
|
|
101
|
-
68. **The resume union never prunes entries that became tracked**: a file the user committed between sessions is still unstaged by the session commit while the receipt lists it as modified. Drop union entries present in `git ls-files -z --cached`.
|
|
102
|
-
69. **Snapshot hashing cost on large untracked data trees**: every file entry is sha256'd at every session start (30k small files: 1.9s; tens of GB of untracked parquet or weights would stall for minutes). Add a size cap or a size+mtime+inode fingerprint.
|
|
103
|
-
70. **Snapshot and hash files live in agent-writable `.loki/state`**: an agent can add entries (hide or uncommit files) or delete the hash file (suppress `preexisting_modified`). Predates cycle 3; matters for adversarial agents.
|
|
104
|
-
71. **`evidence-gate-details` `tests.ok` stays true for an inconclusive test axis**; `surface_evidence_gate_details` prints `tests_ok=True` next to `tests_inconclusive`.
|
|
105
|
-
|
|
106
|
-
72. **Refused resume keeps the old `base-branch.txt` and says too little.** Now that `--no-overwrite-ignore` makes the mint fallback a normal path, session 2 keeps session 1's recorded base (wrong PR `--base` advice if it started elsewhere), and the warning does not name the ignored file or where session 1's commits live.
|
|
107
|
-
|
|
108
|
-
73. **Bash records a test run that exits 0 but reports failures as a pass** (a jest printing "Tests: 1 failed, 2 passed" with exit 0 wrote `pass: true`, `verified`). Parse the runner's own summary for failures (cycle-3 council round 2).
|
|
109
|
-
74. **Agent self-commits bypass the snapshot (data risk).** The snapshot guards only Loki's session commit: an agent that rewrites `.gitignore` and runs `git add -A && git commit` itself puts the user's untracked and ignored files on the session branch, and a base checkout removes them from disk. The RARV prompt tells every provider to checkpoint-commit; only `providers/claude.sh` (and the Bun override) forbids `git add -A`. Intersect `git diff --diff-filter=A <base>..HEAD` with the snapshot in `commit_session_changes`, `git rm --cached` hits, warn, and add the hygiene line to codex/cline/opencode/aider prompts. Also: an agent moving a user file to a new path gets the user's bytes committed under an agent-created name.
|
|
110
|
-
75. **Unregistered suites:** `tests/council/test_managed_completion_flag.sh`, `tests/council/test_managed_review*`, `tests/test-voter-agents-json.sh` and `tests/test-evidence-gate-no-tests.sh` are never run by `tests/run-all-tests.sh` (named only in comments).
|
|
111
|
-
|
|
112
|
-
76. **`done-recognition.sh` tests_axis (434-479): a zero-test record falls through** to an affirmative branch (predates cycle 3; council round 3).
|
|
113
|
-
77. **Every Bun test-results.json is stale by construction:** only bash `enforce_test_coverage` writes `.test-results.iter`, so the Bun gate always re-runs `npm test` or reports inconclusive, and an unknown zero-test detector result makes every exit-0 npm run inconclusive. Fails safe; decide whether Bun should write its own marker.
|
|
114
|
-
78. **Leading-directory pathspec mismatch:** a pre-existing untracked file `a` also matches `a/b` in the literal reset, but `workspace_diff._covered` only treats `a/` entries as covering children, so the commit omits `a/b` while the receipt lists it (the receipt is the honest side).
|
|
115
|
-
79. **A previous session's `static-analysis.pass` survives iteration 0** and reads as a pass of the exogenous static_analysis gate when the new session never runs static analysis (cannot produce VERIFIED alone). Add it to the iteration-0 drop.
|
|
116
|
-
80. **Refused resume on a paused or interrupted state keeps session 1's `start-sha`** while the new branch is minted from the current base, so base commits made between sessions can appear in the receipt diff (extends 72).
|
|
117
|
-
|
|
118
|
-
81. **Two more verdict-relevant inline Python sites without D7:** `run.sh` `_declared_test_script` (~11981) and `_ws_script` (~12101) run plain `python3 -c` with the cwd in the agent repo (extends 54).
|
|
119
|
-
82. **`proof-generator._collect_quality_gates` reads `test-results.json` status with no freshness check** against `.test-results.iter` (the iteration-0 drop covers the new-session case; a stale file mid-session is still read).
|
|
120
|
-
83. **An embedded git repo with no commits under an un-ignored directory makes `git add -A` fail as a whole**; `commit_session_changes` then silently commits nothing with no "Left uncommitted" warning (fails safe, predates cycle 3).
|
|
121
|
-
84. **`-E` also drops `PYTHONDONTWRITEBYTECODE`/`PYTHONIOENCODING`/`PYTHONUTF8`** for the guarded helpers; the council-v2 swarm imports may write `__pycache__` into the install dir (cosmetic).
|
|
122
|
-
|
|
123
|
-
85. **The test gate's pytest writes `__pycache__/*.pyc` into the user's repo**, and the session commit includes them when the repo does not ignore `__pycache__` (seen in a receipt: `__pycache__/helper.cpython-313.pyc`). `P6.no-gate-artifacts-committed` covers only the static-analysis gate; run tests with `PYTHONDONTWRITEBYTECODE=1` or a pycache prefix under `.loki` (cycle-3 interrupt fix).
|
|
124
|
-
86. **Session-created record limits:** the provider turn in flight when the process dies is not recorded (SIGHUP is not trapped, like SIGKILL), so those files are treated as the user's (kept, never committed); a refused resume starts an empty record (warns by name); a path created then deleted by the agent and later re-created by the user is committed as the session's; the snapshot now requires python3 (fails closed without it).
|
|
125
|
-
|
|
126
|
-
87. **Resume rehash hides earlier edits:** the union deletes and rehashes `.sha.z`, so after a SIGKILL or pod loss (no session-1 receipt) session 1's edit to a pre-existing untracked file never appears as `preexisting_modified`. Keep existing hashes for entries already in the base list; hash only new paths.
|
|
127
|
-
88. **Old git (< 2.18) receipt attribution:** a failed mint snapshot deletes the list, so the receipt names every user untracked file as the run's work (names and counts only; the commit path fails closed). Keep an `ls-files --others --exclude-standard` fallback list for the receipt.
|
|
128
|
-
89. **Bash and Bun read `failed_count` differently:** the bash evidence gate reads `pass: true` as PASS whatever `failed_count` says; Bun now fails it.
|
|
129
|
-
|
|
130
|
-
90. **Data risk, next in line: `LOKI_BRANCH_PROTECTION=false` on a leftover `loki/session-*` branch** returns before any snapshot (`run.sh` ~9073), and `commit_session_changes` then commits with the earlier session's stale snapshot, so a file the user made since is committed and lost from disk on checkout of the base (also in v9.53.0; breaks the LOCK A1 opt-out promise). One guard: commit nothing unless this run took a snapshot, or skip the session commit when branch protection is off (cycle-3 council round 6).
|
|
131
|
-
91. **Zero-test stage events:** a zero-test run still returns 0 from `enforce_test_coverage`, so the loop emits `stage_complete test_suite pass` (~24590) although the result is inconclusive.
|
|
132
|
-
92. **Receipt path bases mix under a subdirectory `TARGET_DIR`:** tracked entries are repo-top-relative, untracked and `preexisting_modified` entries are cwd-relative.
|
|
133
|
-
|
|
134
|
-
93. **`test-hard-deadline-confinement.sh` "zero-exit leader" case is load-sensitive:** the leader waits only 0.2s for the forked child to write its PID file, so under CI load the child PID is empty and the case fails although the product behaved correctly (rc 125, no mutation). Seen once, shard 2 at `1dd799f9` (v9.54.0 release run), passed 3/3 locally and on rerun. Wait for the PID file with a bounded, generous timeout.
|
|
135
|
-
|
|
136
|
-
94. **Scope-audit tests walk `app.routes`** (`test_all_data_gets_scoped`, `test_fleet_observability`, `test_fleet_retry`, `test_memory_read_scope_auth`), so on FastAPI >= 0.141 they never see a v2 or operator route: their v2 coverage is vacuous on CI. Use the same router-matching approach as the P7 case (cycle 4, slice D).
|
|
137
|
-
95. **(Fixed: cycle 4 nulled the dashboard fleet runs/summary and project totals; the P7 sweep nulled the web-app `/api/session/status` cost and its status push through one shared `_measured_state_cost` reader.) Servers still seed unmeasured cost as 0:** `web-app/server.py` `/api/session/status` seeds `cost_usd = 0.0` (~2932) and `dashboard/registry.py` does the same, so the UI can only treat values above 0 as readings. Send null when nothing was recorded.
|
|
138
|
-
96. **(Fixed in cycle 4: gauge and health grade removed, BuildInsights nulls, scanner rules 4 and 5.) More fabrications in `ProjectWorkspace.tsx`:** `testCoverage={buildStatus.iteration > 2 ? 60 : 20}`, `gatePassRate={0.8}` (~1559) and hardcoded zeros for `filesModified`/`linesGenerated` passed to BuildInsights. The P7 sample-data scanner misses assignment-form fallbacks and unconditional fakes; widen it.
|
|
139
|
-
97. **(Fixed in the P7 sweep: `run_check` call site, `skip_check` and `_FAST_KEEP` entry "webapp admin console renders honestly" in `scripts/local-ci.sh`, and a `run_test` line in `tests/run-all-tests.sh`; the harness now also drives the Teams page.) Register `scripts/run-webapp-admin-honesty.sh`** in `scripts/local-ci.sh` (~1850) and `tests/run-all-tests.sh` (~295) next to its sibling harnesses.
|
|
140
|
-
98. **Headline vs gate listing:** the stale-results fix (82) changes the unit_tests gate listing only; the headline comes from `facts.tests`, which should get the same freshness rule. The council member vote and `_council_convergence_evidence_green` still read `pass: true` as green whatever `failed_count` says, and the Bun npm fallback still reads an exit-0 run printing "Tests: 1 failed" as passed.
|
|
141
|
-
|
|
142
|
-
99. **The commit-hygiene prompt line does not reach the main build loop for codex, cline or aider:** the bash loop calls `codex exec ... "$prompt"` directly and uses run.sh's own `invoke_cline`/`invoke_aider`; the Bun providers push the raw prompt. Only opencode gets it. The untrack commit is the real guarantee; the cycle-4 commit message overstated the wiring.
|
|
143
|
-
100. **Interrupted self-commit loses user files:** the untrack step runs only at the normal end of a session (`commit_session_changes`); an agent self-commit followed by an interrupt and a base checkout still deletes the user's files. Run the untrack check in the interrupt path and on resume.
|
|
144
|
-
101. **Nested repo gitlink stays on the tip:** an untracked `vendor/lib/` with its own `.git` that the agent's `git add -A` records as a gitlink is not matched (`vendor/lib` vs snapshot entry `vendor/lib/`); nothing is lost (checkout keeps the directory).
|
|
145
|
-
102. **`.loki/state/agent-committed-user-files.z` has no reader** outside the lifecycle test and is never cleared by a later session with no hits.
|
|
146
|
-
103. **Bash failure-count gaps:** jest "Test Suites: 1 failed" with "Tests: 2 passed" (a suite that failed to compile), and vitest "Test Files 1 failed", still read as passed (`run.sh` ~12697-12707).
|
|
147
|
-
104. **Pre-existing failing node test:** `legacy-ui/tests/loki-overview-issue-journey.node.test.mjs` fails 5/5 at v9.54.0 and before; not registered in any runner.
|
|
148
|
-
|
|
149
|
-
105. **User-committed files on the session branch are misattributed (council S4c):** a file the user deliberately commits on the session branch between sessions is taken off the tip by the next session's untrack step and reported as "the agent committed". It stays on disk. Needs a session-end marker written at every clean session end to tell user commits from an interrupted agent's.
|
|
150
|
-
106. **Unmeasured spend in the CLI and the budget breaker:** `loki cost` (autonomy/loki) reports `budget_used = 0.0` when unmeasured (ok/0%); `check_budget_limit` writes `0.0` to `budget.json` for a run it measured nothing for; the bash and Bun breakers treat unmeasured cost as $0 and never warn. Proposed default: warn (never pause) when a cap is set and spend is unmeasured, and show unknown in the CLI.
|
|
151
|
-
107. **(Mostly fixed in the P7 sweep: rule 4 now matches the whole file, so a multi-line ternary is one prop, and `tests/e2e/webapp-admin-honesty.mjs` renders the MetricsPage budget tile against a $10 cap with no spend and asserts "Not recorded". Open: rule 4 still only knows its listed metric names.) Test coverage for two honesty surfaces:** the web-app MetricsPage "Not recorded" budget label has no committed rendering test, and P7 rule 4 (hardcoded metric props) scans one line at a time (misses multi-line ternaries and metric names outside its list).
|
|
152
|
-
|
|
153
|
-
108. **High (secret exposure, opt-in path): `LOKI_AUTO_PR=1` pushes a branch whose history still holds user files.** After the untrack step warns "do not push <branch> as-is", `create_session_pr` prints push advice and, under `LOKI_AUTO_PR=1`, pushes the branch with the user's files (for example `.env.local`) still in history. Read `.loki/state/agent-committed-user-files.z` in `create_session_pr`; when non-empty, print the `git reset --soft <fork> && git commit` cleanup first and refuse the auto-push (also gives item 102 its reader). Predates cycle 4.
|
|
154
|
-
109. **The untrack step's global `git reset -q` drops force-staged ignored agent files** (`git add -f dist/bundle.js`) from the session commit with no warning (file stays on disk). Build the untrack commit on a temporary `GIT_INDEX_FILE` and force-remove only those paths from the real index.
|
|
155
|
-
110. **A resumed session minted by an older Loki (no `session-start-sha`) whose recorded base does not resolve fails closed on every resume**, even when the agent committed nothing, and the warning tells the user to run `git rm --cached` with nothing swept. When no fork resolves, intersect HEAD's tree with the snapshot's exact entries on disk and proceed if empty.
|
|
156
|
-
111. **pytest "1 passed, 1 error" parses as failed_count 0 and passes** (only "N failed" is counted in the bd39d359 summary parser).
|
|
157
|
-
|
|
158
|
-
112. **(Partly fixed in the P7 sweep: web-app `/api/session/status` and its status push, dashboard `/api/context` with no `tracking.json`, and the timeline per-iteration token counts and model now send null; `current_run` and the budget snapshot carry a `partial` flag; pinned in P7.unmeasured-cost-never-zero's server and web-app legs, except the WebSocket status push, which shares `_measured_state_cost` and `_max_iterations_or_none` with the pinned GET but whose own payload no test drives. Open: `/metrics` `loki_cost_usd`, the `/api/cost` tracker fallback, the per-run partial flag, and the R3 design doc.) Remaining server paths that send 0 for unmeasured cost:** `web-app/server.py` `/api/session/status` (~2932, ~2956) and its status push (~6292, ~6315); dashboard `/api/context` with no `tracking.json` (~8804, ~8810); `/metrics` `loki_cost_usd` (~10048, sums with no "measured" check; Prometheus needs its own decision); the `/api/cost` tracker fallback when tokens were seen but no cost (~7914, ~7919); timeline per-iteration token counts; a fleet run with mixed priced and unpriced records has no per-run partial flag. `docs/R3-COST-OBSERVABILITY-DESIGN.md` still describes `project_total_usd` as a plain sum.
|
|
159
|
-
113. **(Fixed in cycle 4, `3a139d81`: `get_proof` adds a computed `integrity_check`; the receipt panel and audit viewer render only computed verdicts; new case P2.console-verdict-needs-computed-result.)** **Critical (moat P1/P2, not P7): two panels state a verification verdict nothing computed.** Found by the P7 sweep; a different property, so not fixed there. `web-app/src/components/EvidenceReceiptPanel.tsx` `classify()` (~43, ~50, ~70-76) labels a receipt "Proven: internally consistent with its own integrity hash" although the browser never recomputes the hash (`dashboard/server.py` `get_proof` returns the raw proof.json with no verification result), labels a receipt with NO hash the same way (`!v.hash`), and can never return "tampered". `legacy-ui/components/loki-audit-viewer.js` prints "[VALID] ... verified" for `valid !== false`, so `dashboard/audit.py` returning `valid: True, files_checked: 0` reads as verified, and its catch (~169) turns a failed request into "[TAMPERED]". Fix: a server verify endpoint (or the `loki proof verify` result) behind the receipt label; require `valid === true && files_checked > 0`; a failed request is NOT VERIFIED, never TAMPERED.
|
|
160
|
-
114. **False empty on a failed fetch (class, P7-adjacent).** A request that fails renders the same "nothing here" copy as a real empty result. Sites: `web-app/src/components/NLSearch.tsx` (~140-143, "No results found"), `CommandPalette.tsx` (~171-173), `pages/ProjectsPage.tsx` (~65, ~166-168 ignore the poll hook's error), `ProjectWorkspace.tsx` SecretsPanel (~248-256, ~366-372) and DocsPanel (~431-442, ~589-592), the cockpit (`cockpit/useCockpitState.ts` ~119-123 swallows git status and checkpoint failures, so `ChangeReview.tsx` says "The working tree is clean", `FinalActions.tsx` "Nothing to push", `RiskPanel.tsx` "No checkpoints were recorded"), `DeployConnections.tsx` (~353-370), `CICDPanel.tsx` (unknown conclusions shown as "Failed"), `AIChatPanel.tsx` (~543, ~622 "Done." with no output); dashboard `loki-checkpoint-viewer.js` (~95-106), `loki-task-board.js` (~164-169 hides the error when local tasks exist), `loki-log-stream.js` (~152-181), `loki-council-transcripts.js` (~111-114), `loki-managed-memory-panel.js` (~138-141 ignores `data.error`), `loki-migration-dashboard.js` (~94-98), `loki-api-keys.js` (~557-558). Fix per site: keep the error and render "Could not load ..."; a scanner rule for `.catch(() => [])` followed by an empty-state string would pin the class.
|
|
161
|
-
115. **Status inference presents a guess as a state.** `web-app/server.py` `_infer_session_status` (~3603-3666) returns "completed" for a failed or paused run once its state file is five minutes old, and for any directory with a top-level source file; the cockpit then shows "Run finished" with every step ticked. `cockpit/useCockpitState.ts` (~209-218) also falls back to "completed" for unknown statuses, and (~118) shows `/api/session/checklist`, which reads the globally running project, as a historical session's gates. `ProjectWorkspace.tsx` (~1403-1412) labels REASON/REFLECT and unknown phases "building"; `PhaseVisualizer.tsx` styles earlier RARV steps as done. Fix: an explicit "unknown"/"stale" status and a per-session checklist (or none).
|
|
162
|
-
116. **Key misreads that hide or zero real data.** `web-app/src/components/GitHubPRsPanel.tsx` reads `statusCheckRollup.contexts` (~204, ~713) although gh returns an array, so failing CI shows "No status checks"; `reviewDecision || "PENDING"` (~222); uppercase gh `state` never equals `'open'` (~751), which also hides the Close button that only posts a comment yet says "PR #N closed" (~592-606); `GitHubIssuesPanel.tsx`/`GitHubPRsPanel.tsx` comment counts read a number where gh sends an array. `EvidenceReceiptPanel.tsx` (~211, ~219) reads `detail.cost_usd`/`detail.files_changed` where proof.json stores `cost.usd` and `files_changed.count`, so a measured cost reads "unknown". `loki-memory-browser.js` episodes read camelCase keys (`actionLog`, `taskId`, `phase`) where the store writes snake_case, so episode details never open and every episode is titled "Task"; `/api/memory/stats` sends `episode_count`, the panel reads `episodes_count`. `loki-overview.js` `_renderCouncilGateCard` (~394) keys on `g.status`, which `/api/council/gate` never sends (it sends `blocked`), so a blocked gate reads "Not evaluated".
|
|
163
|
-
117. **Stale or false static copy.** `WhatsNew.tsx` `CURRENT_VERSION = '6.73.1'` and `Footer.tsx` `v6.73.0` (current 9.x); `SettingsPage.tsx` says License "MIT" (the LICENSE is BUSL-1.1) and a hardcoded build date; `ComparePage.tsx` lists Gemini as supported (runtime removed v7.5.18) and "9 automated quality gates", `BenefitCards.tsx` "10 quality gates" and Gemini (the canonical count is 8); `ProductTour.tsx`, `DocsSidebar.tsx` promise Railway deploys (only Vercel, Netlify, GitHub Pages exist) and a coverage gate; `ContextualHelp.tsx`, `SettingsPage.tsx` and `CostEstimator.tsx` still list Gemini; `Roadmap.tsx` hardcodes Q2 2026 as "Current"; `ChangelogWidget.tsx` shows March 2026 tags as "Recent Changes"; `TrustedBy.tsx` asserts "Trusted by developers building the future". The P7 scanner cannot see module-level copy tables (the deleted testimonials were one); a narrow rule for invented person/company rows would close that gap.
|
|
164
|
-
118. **Fabrications the P7 sweep found and did not fix (outside its enumerated shapes or needing a design).** Per-run `cost.cost_partial` is dropped by `/api/cost/timeline` `runs[]` and `/api/proofs`, so a partly priced run shows as complete (`legacy-ui-static/cost.html` ~287, ~301, `proofs.html` ~145, the dashboard receipts list); `workspace_diff.py` returns count 0 when the folder is not a git repo (feeds the receipt hash, so needs care); `trust.html` says "Stable" when no axis has two data points, and `trust_trajectory.py` maps any non-PASS verdict to 0.0; `/cost` prices a record with tokens but no `cost_usd` at Sonnet rates when the model is unknown, with no "estimate" label; `loki metrics --json` (`autonomy/loki` cmd_metrics) sends `tokens.total` 0 and `agent_activity.total_iterations` 0 when nothing was recorded; server-side zero or "not blocked" sentinels the panels now render as unknown only where the client can tell: the council-state fallback `total_votes: 0` (`dashboard/server.py` ~8617), a corrupt `notifications/active.json` answered with a zero summary (~8883), a waivers read error answered 200 (~10321), a corrupt app-runner state answered `{"status":"error"}` (~11240), `prompt_optimizer.py` (~73-84) never-ran sentinel zeros, `migration_engine.py` (~770-793) 0/0 progress; the dashboard `StatusResponse` model (~594-607) defaults iteration/pending to 0 and provider/complexity to "claude"/"standard", and the skill-session WS fallback hardcodes `running_agents: 0` (~1042); `loki-analytics.js` counts days outside the returned log window as 0 activities; `CostEstimator.tsx` prices the whole iteration cap as the estimate once a real cap (e.g. 1000) is known; the web-app "Replay Build" button can never appear (`buildPhase` is "idle" whenever no build runs) and the StatusBar "Built in" line no longer receives a value; the dashboard shell has two elements with `id="budget-banner"` (`build-standalone.js` ~1200, ~1801), reverses a newest-first receipts list under a "Newest first" label (~2510), and colours "VERIFIED WITH GAPS" as success (`/^VERIFIED/`).
|
|
165
|
-
119. **(Fixed in cycle 4, `3a139d81`: `validate_token` rejects a key past `rotation_expires_at`; `cleanup_expired_rotating_keys` still has no caller.)** **High (security, found by the P7 sweep): a rotating API key past its grace period still authenticates.** `dashboard/auth.py` `validate_token` (~346-390) checks `revoked` and `expires_at` but never `rotation_expires_at`, and `dashboard/api_keys.py` `cleanup_expired_rotating_keys` (~291) has no callers. The key panel now derives "rotating" from the timestamps, which still understates it. Fix: reject in `validate_token` once `rotation_expires_at` has passed, with a test.
|
|
166
|
-
120. **Two legacy-ui test files do not test the shipped code.** `legacy-ui/tests/ui-components.test.js` asserts hand-copied versions of `formatGateTime`, `summarizeGates` and `formatRunDuration` that still encode the old "Never" / "pending" / growing-duration behaviour, and jest is not installed, so nothing runs it. `legacy-ui/tests/loki-overview-issue-journey.node.test.mjs` fails 0/5 at 61af5915 and after this change (the disconnected view hides the journey since 1a871725 and the test never sets `_data.connected`); it is registered in no runner. Import the real functions or delete the copies; fix and register the journey test.
|
|
167
|
-
121. **Browser-only settings still read like live config.** `web-app/src/pages/SettingsPage.tsx` stores provider API keys in plain text in localStorage, and "Budget limit" and "Auto-deploy on success" describe effects nothing implements; each category now carries a "saved in this browser only" note, but removing or wiring them is a product decision. `DeployConnections.tsx` still starts from `{connected:false}` and, if its own fetch fails, pushes those defaults up to `DeployPanel` on the next connect or disconnect.
|
|
168
|
-
|
|
169
|
-
122. **Receipt field `first_result_verified_patch` is `True` for any first code change** (`autonomy/lib/proof-generator.py:1164`, from `first-artifact.json`), so the name claims a verification nothing ran. The overview now labels it "first code change"; rename the field additively (`first_result_kind` already carries the kind) or set it only from a verified result.
|
|
170
|
-
123. **More verdict-class leftovers from the 113 sweep:** the `audit.py verify` CLI and `compute_chain_tip_in_dir` still report valid, exit 0, when nothing was checked (the cross-chain verifier reads them, so changing them needs its own review); the cockpit, overview, checklist, gate-card, standalone, proofs.html and cost.html verdict relabels have no test of their own (only the receipt and audit surfaces are pinned by the moat case); the standalone receipt list shows the oldest receipts first (see 118).
|
|
171
|
-
124. **Dashboard innerHTML audit:** the standalone receipt and learning panels interpolated run-written text into innerHTML unescaped (fixed in cycle 4, `f6050ef1`, with hostile-input tests). No systematic audit of the other `innerHTML` sites in `legacy-ui/components` and `build-standalone.js` has been done; add a guard that flags a template literal or string concatenation of a response field into innerHTML without an escape.
|
|
172
|
-
|
|
173
|
-
125. **P7 scanner (`tests/moat/p7-no-fabricated-data.sh`) bypass shapes found by PF-2 round 5's review but not fixed there (pre-existing before and after `fa5de15f`, not a regression -- each is a candidate for its own small slice):**
|
|
174
|
-
- **B-1 reassignment fallback:** `let rows = data; if (!rows.length) rows = [rows]; setRows(rows);` -- `DECL_ARR` only matches the `const/let/var x = [` declaration, never a later bare `x = [` assignment.
|
|
175
|
-
- **B-2 destructuring / parameter defaults:** `const { rows = [rows] } = data;` or `function load(rows = [rows]) {}` -- neither is a declaration of the form `name = [`.
|
|
176
|
-
- **B-3 object-property value on `this.x` outside a setter:** `this._state = { phases: [rows] };` -- `THIS_ARR` needs `this.x = [` directly, misses a literal nested inside an object RHS.
|
|
177
|
-
- **B-4 paren-wrapped `||`/`??` outside a setter:** `this._rows = d.rows || ([rows]);` -- `FALLBACK_ARR` requires `[` immediately after the operator; a wrapping `(` defeats it (the setter-argument span arm already catches this shape inside a setter call).
|
|
178
|
-
- **B-5 module-level named fallback table:** `const FALLBACK_ROWS = [rows];` at column 0, used later as `data.length ? data : FALLBACK_ROWS` -- the column-0 exemption plus the identifier-branch ternary both let it through; rule 7's name-based catch only fires if the constant name contains sample/mock/demo/fake/placeholder.
|
|
179
|
-
- **B-6 ternary against `null`/`undefined`:** `const r = loading ? null : [rows];` -- `is_literal(null)` is true, so the both-branches-literal exemption suppresses it; should only treat an array/object literal (never null/undefined/empty-string) as the "literal other branch."
|
|
180
|
-
- **B-7 fabricated data returned from a helper:** `function getRows(d) { if (!d) return [rows]; return d; }` then `setRows(getRows(d))` -- no arm follows a function's return value.
|
|
181
|
-
- **B-8 `Array.from` generator producing invented rows:** `Array.from({ length: 3 }, (_, i) => ({ id: i, action: 'Deployed', user: 'Admin' }))` -- the `Array.from` arm only checks a literal first argument, not a generator callback whose body invents field values.
|
|
182
|
-
- Two more from the same review, not yet given IDs: a positive-control risk (a real typed options list chosen against live data, e.g. `isAdmin ? adminOpts : [{value:'view',...}]`, could false-positive under the ternary/setter-span arms -- fix with an allow-annotation if it ever fires on real code, don't weaken the arm); and re-running `tests/moat/p6-*.sh` in isolation to confirm its 300s timeout during the PF-2 review was purely a load artifact (load average ~30 from concurrent session agents), not a real regression the merge introduced.
|
|
183
|
-
|
|
184
|
-
126. **(CORRECTED and CONFIRMED as a real CI-breaking bug, not just a local artifact -- see the retraction below.) `tests/test-airgap-ollama-host.sh` does not isolate `.loki/state/`, so a stale `.loki/state/provider` file written by an EARLIER test IN THE SAME CI SHARD's shared checkout silently overrides the test's own `LOKI_PROVIDER=opencode` env var** (the CLI's own precedence rule: saved project state wins over the env var, by design). This actually broke `Tests` (shard 3/4) in CI on `ba6610dc` -- root-caused by reproducing the exact CI shard-3 sequence locally: `tests/test-iteration-grace.sh` sources `autonomy/run.sh` from the shared repo checkout's CWD (not its own isolated `$SCRATCH` dir) at two call sites (`probe()`, ~line 42 and ~109), and `autonomy/run.sh:1741-1744`'s provider auto-detection writes `.loki/state/provider` as an unconditional side effect of sourcing. Every later test in the same shard's shared checkout inherits that leftover file. Removing it reproduces the airgap test passing again; the CI failure is not a local-checkout coincidence. **Retraction**: an earlier draft of this item concluded the opposite (called it "not a product bug", attributed it purely to local manual-testing residue, and proposed fixing only `test-airgap-ollama-host.sh`'s own isolation) -- that conclusion was WRONG. It was drawn from a local reproduction where I had ALSO independently left a stray `.loki/state/provider` in my own manual testing, which coincidentally matched the CI symptom and stopped the investigation short of finding the real cross-test contamination source. Lesson: a reproduced symptom is not the same as a verified mechanism -- confirm the EXACT trigger, not just that removing the artifact makes the symptom go away. Two fixes landed and merged: `test-iteration-grace.sh` (`b3d7cdda`) and `test-exit-code-contract.sh` (`e05e09fb`), both isolating CWD before sourcing `run.sh`. Verifying the shard is now clean surfaced a THIRD contaminator: `tests/test-code-review-self-copy.sh` sources a self-copy of `run.sh` with NO `cd` at all. Fix dispatched. This bug class (source `run.sh`, or a copy of it, before `cd`ing into an isolated scratch dir) has now appeared in at least 3 registered-in-CI files; `test-review-diff-moat.sh` also reproduces it standalone but is not registered in any CI path today (orphaned test, latent bug, not a current shard contributor). A systematic repo-wide sweep for this exact pattern (`source .*run\.sh` or a self-copy of it, with no preceding isolating `cd`) is now clearly warranted as its own slice, rather than continuing to discover instances one CI failure at a time -- each new fix's own verification pass keeps finding the next one. **FIXED (2026-09-27, merge 41c2f604):** the repo-wide sweep closed 22 more files (19 originally scoped plus 3 new instances found mid-sweep: `test-doc-scope-generator.sh`, `test-p0-gate-behavior.sh`, `tests/council/test_managed_review_flag.sh`, the last of which sources the bug via a real `bash run.sh --help` subprocess, not just `source`). Verified: all 22 run clean in sequence with no `.loki/state/provider` left behind, the victim test then passes 4/4, moat suite matches main exactly (3 of 9, no rule failed), shellcheck clean. Also independently isolated at the victim side: `test-airgap-ollama-host.sh` now sets its own `LOKI_DIR` (`0f056336`), so it is immune regardless of any remaining, still-undiscovered contaminator elsewhere in the suite. **Retroactive quorum (2026-09-27):** this MEDIUM-tier merge shipped without its 2-reviewer quorum first (a real process gap, self-caught and disclosed in PROGRESS.md). Reviewer 2/2 (Sonnet) returned APPROVE: independently re-derived the root cause (found it is actually UNCONDITIONAL, firing even when `LOKI_PROVIDER` was explicitly set, not just on auto-detect -- a stronger bug than originally described), redid the 23rd-instance search after an advisor-caught blind spot in the first pass (~35 additional call sites found repo-wide, all already isolated or targeting unrelated scripts, none a missed instance), and added a RED-check not in the original ask: removed one file's `cd` fix in an isolated worktree, reproduced the exact original bug (`.loki/state/provider` written into the worktree root), then confirmed reverting the fix restored green. No blocking findings. Reviewer 1/2 (Opus) independently also returned APPROVE: byte-diffed pre/post output across all 22 files (differs only by the 2 new isolation lines), confirmed the sleep-plus-`-nt` mutation harness is genuinely load-bearing (found `test-exit-code-contract.sh` passes VACUOUSLY on real bash 3.2 without the sleep, even while contaminated -- so the sleep is not cosmetic there), ran all 22 through a real 4-shard parallel `tests/run-all-tests.sh` invocation matching local-ci's own sharding with no leaks, and confirmed the moat suite's 2-of-9 (vs. 3-of-9 on a fully-provisioned checkout) is a fresh-worktree `node_modules`-absence artifact, not a regression. **Retroactive quorum: 2/2 APPROVE, no blocking findings from either reviewer -- gap closed.** Both reviewers flagged the same non-blocking point independently: `test-airgap-ollama-host.sh` no longer actually detects this bug class (it was isolated separately via `LOKI_DIR` in `0f056336`), so the real regression detectors going forward are each of the 22 files' own new `-nt` checks, not the original victim test.
|
|
185
|
-
|
|
186
|
-
127. **(CORRECTED 2026-09-26: an earlier draft of this item claimed `56eb866f` was already merged and fixed. It was reviewed and unanimously approved same-session as S-22 but never actually merged -- a real gap on main until now. Now genuinely fixed and merged: `56eb866f` merged via a dedicated merge commit, pushed. `council_should_stop`'s shadow-write block is now skipped entirely when `PROJECT_DIR` is unset, plus -E on the python3 call; real code-execution RED/GREEN confirmed via a live marker-file demonstration, polled across the backgrounded+disowned call.) Sibling of BACKLOG 63 (S-22): `council_should_stop` (~line 4635 in `autonomy/completion-council.sh`) had the identical unguarded `cd "${PROJECT_DIR:-$(pwd)}"` pattern feeding `python3 -m memory.managed_memory.shadow_write` -- more severe than S-22's own retrieve-path bug since this one EXECUTES a module, not just imports it for reading.** Two more copies of this pattern remain open: `autonomy/run.sh:19861` has the identical unguarded `cd "$PROJECT_DIR" && python3 -m memory.managed_memory.shadow_write` (found during the `56eb866f` fix, not fixed there, out of that slice's file set -- same fix shape needed); `autonomy/completion-council.sh:4204` (`council_managed_should_stop`) has `project_dir="${PROJECT_DIR:-$(pwd)}"` but only feeds a `git diff` read, not a python module execution, gated behind the narrower `LOKI_EXPERIMENTAL_MANAGED_AGENTS` flag -- lower severity, still worth the same guard for consistency.
|
|
187
|
-
|
|
188
|
-
128. **Stale documentation asserts a `{"runner":"none","pass":true}` writer shape that doesn't exist.** Found while fixing S-07's rework #2 (BACKLOG 33): `references/core-workflow.md:81` and `docs/VERIFIED-COMPLETION-PLAN.md:90,315,316` assert the same false shape corrected in D20 (the real writer, `enforce_test_coverage` at `run.sh:12691-12692`, writes `pass:"inconclusive"`, a string, never boolean `true`). Not behaviorally load-bearing (nothing parses these docs at runtime) but misleading to a future reader. Also: `tests/test-council-devils-advocate.sh` Case 2, `tests/test-da-veto.sh`, `tests/test-council-convergence-floor.sh:92` use synthetic `pass:true` fixtures instead of the real writer shape -- harmless today since `runner=='none'` is unconditional at every site that reads them, but should be replaced with the real shape for honesty.
|
|
189
|
-
|
|
190
|
-
129. **FIXED.** S-24's tamper-detection seal (BACKLOG 70) only hardened the DIGEST computation, not the snapshot WRITER/READER paths. Found by the adversarial reviewer of the awk-bypass fix (c315cbe9): `_loki_untracked_merge` (writes `preexisting-untracked.z`), `_loki_covered_paths` (reads it after verify), and `_loki_untracked_status`'s `git` invocation were all still bare PATH lookups (`python3 -E`, not `-I` + absolute path; `git` unresolved). An agent that plants a malicious `.pth` file or a fake `python3`/`git` earlier on PATH during one session could forge the CONTENT of the snapshot file itself before the (correctly hardened) seal ever computed its digest over that already-forged content -- the seal then faithfully approved the forgery. Reproduced both classes empirically before fixing: (a) a `.pth` in user site-packages fired arbitrary code during `_loki_untracked_merge`'s and `_loki_covered_paths`'s `python3 -E` calls and could rewrite their declared output after the legitimate write; (b) a fake `git` shadowing the real one on PATH caused `_loki_untracked_status` to omit a real untracked path from its output, which then propagated all the way into the sealed snapshot as if that path never existed. Fixed by adding `_loki_snapshot_py_tool` and `_loki_snapshot_git_tool` (same fixed-root-path-first pattern as `_loki_snapshot_hash_tool`, each candidate probed with a real run, not just `-x`) and routing every python3/git call in the writer chain through them: `_loki_untracked_merge`, `_loki_covered_paths` (both now `-I -S`, not just `-E`/`-I` -- `-S` is required to skip `import site` entirely: `-I` implies `-s` and already skips USER site-packages, but not the resolved interpreter's OWN site-packages directory, which on a Homebrew-installed python3 is itself user-writable; `/usr/bin/python3`'s own site-packages is root-owned, so `-I` alone would suffice there specifically, but `-S` is the correct universal fix since the resolver can fall back to a PATH interpreter), `_loki_untracked_status`, `_loki_tracked_by_user_since_anchor` (feeds the writer's "tracked" exclusion set), `_loki_snapshot_preexisting`'s own `rev-parse --show-toplevel`, and the `hash-snapshot` invocation that writes `.sha.z` (the sibling sealed file). Post-fix, both reproduced bypasses were re-run and confirmed closed (the `.pth`/fake-git have zero effect on the writer/reader's actual output). **Explicitly out of scope, left as BACKLOG 131**: `_loki_untrack_agent_committed_user_files`'s five bare `git` calls (feed the READER, `_loki_covered_paths`, with the paths it checks) and the bare `git reset`/`git commit`/`git update-index` calls in the commit path itself -- a fake git already defeats the commit gate directly at commit time regardless of what the snapshot says, so resolving only the reader's git feed would not change that attacker's achievable outcome; a real fix needs a process-wide resolved-git convention, tracked separately rather than folded into this change.
|
|
191
|
-
130. **S-24 follow-up, non-blocking, from the same review round:** (a) `_loki_snapshot_verify`'s `SNAPSHOT_TAMPERED` audit log doesn't record the live vs. sealed digest values, so an operator can't distinguish a genuine content change from a flaky hash-tool failure (both produce the identical message) -- add both digests to the audit line; (b) a verify-then-read race exists between `_loki_untrack_agent_committed_user_files`/`commit_session_changes`'s verify call and their later file read, where a background process could swap the file in between (compounded by BACKLOG 129's reader-side exposure, now narrowed by the BACKLOG 129 fix but not closed for the git-fed paths -- see BACKLOG 131); (c) `.loki/state/session-created.z` is not covered by the seal at all -- an agent could add a user's pre-existing files to it, causing a later resume to leave those files out of the snapshot and commit them as session work.
|
|
192
|
-
131. **Process-wide resolved-git convention needed (split out of BACKLOG 129's fix scope); reviewed 4 times total across two rounds (2/2 then a 2/2 top-up, all four APPROVE), with corrections from both rounds folded in below.** `_loki_untrack_agent_committed_user_files` (autonomy/run.sh:9969-10022; CORRECTED 2026-09-27: 9 bare `git` calls in this one function, not "5" as an earlier draft said -- `git rev-parse --verify` (9982), `git merge-base` x2 (9984, 9988), `git cat-file` (9989), `git rev-parse --show-toplevel` (9999), `git -C diff` (10000), `git reset` (10013), `git -C update-index` (10014), `git commit` (10015); the reset/update-index/commit trio is INSIDE this same function, not in `commit_session_changes` as an earlier draft misattributed -- `commit_session_changes` starts at line 10024 and has its own separate `git reset -q` at 10127) still use unresolved `git`, along with roughly 290+ other bare `git` invocations across `autonomy/run.sh`. (a) **Understated, per the first round's reviewers**: framed as "low-value to fix since a fake git already defeats the commit gate directly" -- true, but that argument only excuses NOT fixing the commit-time calls; the reader's own git feed still means BACKLOG 129's git-side hardening protects the snapshot's stored CONTENT, not what the commit outcome actually is, until this lands -- say that plainly rather than "closed" or "already covered elsewhere." A fake `git` shadowing the real one already defeats the commit gate directly (it can no-op `git commit`, or lie about what `git reset` did) independent of anything the snapshot says, so this is a materially larger fix than BACKLOG 129's writer/reader scope and was deliberately left out of it. (b) `_loki_snapshot_digest`'s python3 fallback (used only when neither sha256sum nor shasum resolves anywhere) is not yet routed through `_loki_snapshot_py_tool`/`-S`; a top-up reviewer independently reproduced that Homebrew python3 `-I` alone (without `-S`) still fires a `.pth` planted in its own site-packages, confirming this gap is real, not theoretical. (c) **Understated, per the first round's reproduction attempt, then widened by the top-up round**: `.git/config`'s agent-writable `core.fsmonitor`/`core.untrackedCache` settings don't just "shape" what a correctly-resolved `git status` reports -- `core.fsmonitor` makes git run a command the agent CHOSE on every status call and trust what it reports, which could be a full bypass of the git-side hardening entirely (an attempted untracked-cache/directory-mtime PoC did not succeed, so the full bypass is not yet proven either way -- treat as open, not dismissed). A top-up reviewer separately confirmed `core.worktree` is not yet named here and is a related agent-writable vector (it can redirect `rev-parse --show-toplevel` and `status` to point at a different tree entirely) -- add it to this enumeration; the same reviewer tried setting it as an attack and found the writer currently fails closed (`rev-parse --show-prefix` fails outside the worktree) rather than being fooled, so this specific vector is not yet a proven bypass, only a named one. Mitigate `core.fsmonitor`/`core.untrackedCache` with `-c core.fsmonitor=false -c core.untrackedCache=false` on the status call, or investigate and disclose definitively; mitigate or investigate `core.worktree` separately.
|
|
193
|
-
|
|
194
|
-
132. **Mutant-detection test relies on bash-version-specific `cd ""` behavior, found during the BACKLOG 127/S-22 shadow-write fix's quorum top-up.** `tests/test-council-shadow-write-project-dir.sh`'s mutant check (strip only the `-n PROJECT_DIR` guard, leave the `cd "$PROJECT_DIR"` rewrite in place) stays GREEN on bash 5.3 (Homebrew) because bash 5.3's `cd ""` hard-fails with `cd: null directory` and short-circuits the `&&` chain -- but the identical mutant reproduces RED on real bash 3.2.57 (macOS system `/bin/bash`, what `#!/usr/bin/env bash` resolves to on a plain macOS machine), because bash 3.2's `cd ""` is a silent success that leaves cwd unchanged. The merged fix itself is correct on both interpreters (verified directly by two independent reviewers); only the test's mutant discriminator is interpreter-luck under bash 5. Fix: run the GREEN/mutant comparison under `/bin/bash` explicitly, not `#!/usr/bin/env bash`, so a future edit that dropped only the `-n PROJECT_DIR` guard cannot look safe locally while shipping a live hole on the macOS default interpreter.
|
|
195
|
-
|
|
196
|
-
133. **`scripts/v10-pulse.sh`'s `PULSE_MOAT_RESULT` file isn't tied to the commit it was measured against.** Found by a reviewer during S-26's rework re-review: the moat-regression check now correctly requires a supplied, actually-measured `tests/moat/run.sh` capture (fixing the original structural blindness), but nothing yet verifies that capture was taken against the SAME commit the rest of the pulse's metrics are computed for. A stale capture from an earlier commit would read as clean today, reintroducing a narrower version of the original false-clean problem through the input side rather than the inference side. Not blocking S-26's merge (nothing writes this file yet -- it's a manual/future-hook input), but the hook-wiring work (docs/v10/PROGRESS.md's still-open `.claude/settings.local.json` item) must have whatever writes `PULSE_MOAT_RESULT` also record the SHA it was measured against, and `scripts/v10-pulse.sh` should reject (report UNKNOWN, not clean) a capture whose recorded SHA doesn't match `$PULSE_MAIN_REF`'s current HEAD.
|
|
197
|
-
|
|
198
|
-
134. **`autonomy/completion-council.sh`'s test-result readers (`council_heuristic_review`, `council_evaluate_member`, `council_devils_advocate_review`) run a bare PATH-resolved `python3 -E -c` with no `-I`/`-S` and no fixed-path resolution -- lighter hardening than the equivalent fix already shipped for `autonomy/run.sh` (BACKLOG 129's `_loki_snapshot_py_tool`), with the identical bypass class it closed.** Found by an S-17 HIGH-tier reviewer (out of scope for that slice, which is test-coverage-only and does not touch this production code -- a bucket-(b) pre-existing gap the diff doesn't worsen, per D21, not a veto on S-17). `-E` ignores PYTHONPATH but does not stop Python from loading `.pth` files in the resolved interpreter's own site-packages directory at startup, which runs BEFORE this file's `sys.path` scrub ever executes. Reproduced live: with HOME pointed at a scratch directory holding a planted `.pth` in user site-packages that swaps `sys.modules['json']` to always report `pass:true`, `council_devils_advocate_review` flipped a genuinely failing test-results.json from `OVERRIDE_CONTINUE` to `CONFIRMED_COMPLETE`. Same fix shape as BACKLOG 129: route these 3 call sites (and any sibling `python3 -c` sites in the same file not already covered) through a resolved-interpreter helper matching `_loki_snapshot_py_tool`'s pattern (fixed root-owned paths first, `-I -S`, PATH-walk fallback with the same accepted residual gaps 129 already documents). Pair the fix with a new moat case that plants a user-site `.pth` under a scratch HOME and confirms it no longer flips the verdict.
|
|
199
|
-
|
|
200
|
-
135. **`council_managed_should_stop` (autonomy/completion-council.sh:4280) is a 6th test-result reader not covered by S-17/BACKLOG 43's shadow-import moat case.** It already has the D7 hardening (sys.path filter present, confirmed by direct read), and is gated behind three default-false experimental flags (`LOKI_EXPERIMENTAL_MANAGED_COUNCIL`/`LOKI_EXPERIMENTAL_MANAGED_AGENTS`/`LOKI_MANAGED_AGENTS`), so it is not currently exploitable in production. Found by an S-17 HIGH-tier reviewer during a full-repo grep for every function reading `.loki/quality/test-results.json`. Non-blocking on S-17 itself (out of that slice's scope), but the case's name (`P2.council-readers-not-shadowed`) and its description now read as covering all readers when one remains untested. Extend the case to also drive this 6th reader under its experimental flag, mirroring the existing mutation-cycle pattern.
|
|
201
|
-
|
|
202
|
-
136. **`scripts/v10-pulse.sh` trusts LOCAL git tags for its release-tag lookup, which can silently lag the real npm-published version by however long it takes this checkout to `git fetch --tags`.** Found operationally: 90 minutes after v9.55.0 shipped and was live on npm, the pulse still reported "106 commits since v9.54.2" because the local checkout had never fetched the new tag. A `git fetch origin --tags` immediately corrected it to the true "26 commits since v9.55.0". This is not a code bug in the pulse script itself (its `--match "v[0-9]*"` lookup is correct given what tags it can see) but an operational gap: nothing prompts a tag fetch before the pulse runs, so a stale local checkout silently under-reports how overdue a release actually is, or over-reports it if a newer tag genuinely doesn't exist yet. Fix direction: the pulse should cross-check its local tag-derived answer against `npm view loki-mode version` (which it already fetches for the release-count metric) and report UNKNOWN, not a confident number, when the local tag and the npm-published version disagree in a way that indicates a stale local `git fetch`.
|
|
203
|
-
|
|
204
|
-
137. **S-02's fix (client-route helpers now resolve their own repo root dynamically instead of a hardcoded path) breaks `tests/moat/p7-no-fabricated-data.sh`'s own workaround for the same bug.** `P7.webapp-client-routes-exist` copies `tests/lib-extract-client-paths.mjs`/`tests/lib-match-client-routes.py` into a temp dir and sed-rewrites their (formerly hardcoded) `REPO`/root literal to retarget them at whatever tree P7 is scanning. With the hardcode removed (S-02's fix), there's nothing left for the sed to find, and the copied files now self-locate to the temp dir instead of the intended scan target. Confirmed by S-02's own builder: `REPO_ROOT` is not exported/passed to these subprocess calls anywhere in the moat harness, so this cannot be fixed from S-02's own file set. Fix: update `tests/moat/p7-no-fabricated-data.sh:477-501` to either run the two helpers in place (no copy-and-rewrite) or pass the intended root explicitly as an argument/env var, matching how the helpers now expect to receive it.
|
|
205
|
-
|
|
206
|
-
138. **A TOCTOU credential-exposure gap in GF-3's GitHub-token withholding: an agent can plant a `.git/hooks/pre-push` (or set `credential.helper`/`core.fsmonitor`/`core.sshCommand` in agent-writable `.git/config`) during its session, and Loki's own wrapped push later runs that hook WITH `GH_TOKEN` exported.** Reproduced live by TWO independent GF-3 reviewers using different harnesses: reviewer 3 confirmed a child process during the agent session correctly saw no token, but a planted pre-push hook saw `GH_TOKEN=ghp_SECRET` when the wrapped push ran; reviewer 2 independently reproduced the same mechanism in the `default` scenario (`LOKI_DELEGATE_PR=1`, the product default) with 17 of 18 push-env-dumps showing no token and exactly the one dump during Loki's own trusted push showing both `GH_TOKEN`/`GITHUB_TOKEN` present, confirmed via a canary value to be Loki's push and not the provider's. Does not affect CI (both workflows set `LOKI_DELEGATE_PR=0`, and CI tokens are read-only) and is a strict improvement over the pre-GF-3 state (the agent held the token outright before), so this is bucket-(b) per D21, not a veto on GF-3. The P9 case's own header/scope language is accurate (it scopes its claim to "provider environment or argv," not to hooks/config in the working tree); only a shorthand in the case's plain-English one-line description could be read more broadly than the actual guarantee. Fix direction (confirmed independently by both reviewers): trusted git calls should ignore agent-controlled hooks/config -- e.g. `-c core.hooksPath=/dev/null -c credential.helper= -c core.sshCommand=` on Loki's own push, or push from a Loki-owned clone rather than the agent's working tree, rather than relying on `--no-verify` alone (which does not cover `credential.helper`/`core.fsmonitor`/`core.sshCommand`).
|
|
207
|
-
139. **Shipped composite GitHub Actions (`.github/actions/issue-to-pr/action.yml`, root `action.yml`) still put `GH_TOKEN` in the SAME step as the agent invocation.** Found by the same GF-3 reviewer as BACKLOG 138. The new GF-3 tripwire only checks for a persisted checkout token (the `extraheader` git-config mechanism), not the token's actual permission scope, and on hosted Linux an agent can read another process's environment via `/proc/<ppid>/environ` regardless of what its OWN environment shows. Ranked by the reviewer as the top follow-up from this review round. Fix direction: fetch the issue content in an earlier, separate step and hand the agent step only a file, never a step that also holds the token.
|
|
208
|
-
140. **`docs/environment-variables.md`'s description of `LOKI_ALLOW_AGENT_GITHUB_TOKEN` says tokens are "used only by Loki's own push and PR steps" -- imprecise on two counts, per a second reviewer's independent read.** True for the bash route's push/PR step, but (a) the Bun route (GF-3's `github_token.ts`) drops the token outright and has no push/PR step of its own, and (b) even on the bash route the withheld tokens are ALSO re-granted for direct `gh` CLI calls and `autonomy/lib/proof-check.sh`'s network calls, not just the push/PR step the doc names. The doc also omits the two enterprise-token variables (`GH_ENTERPRISE_TOKEN`, `GITHUB_ENTERPRISE_TOKEN`) entirely. Minor doc-precision gap, not behaviorally load-bearing; fix by naming all 4 re-grant sites and distinguishing the two routes' handling explicitly.
|
|
209
|
-
141. **GF-3's P9 injection moat case (`tests/moat/p9-rule-of-two.sh`) unsets `LOKI_SDK_LOOP`/`LOKI_SDK_MODE` for its injection scenarios, so `P9 PROVEN` in the moat registry is currently bash-route-only.** The Bun route's token-withholding protection rests solely on `loki-ts/tests/runner/github_token_withheld.test.ts` (a unit test), not on the moat suite's own real-injection harness. Follow-up: extend (or add a sibling to) the existing P9 injection case to drive the Bun route through the same real-injection harness, once loki-ts/dist is confirmed rebuilt and current.
|
|
210
|
-
|
|
211
|
-
142. **Found while building S-40's Bun-route P9 leg (BACKLOG 141): `loki-ts/src/providers/claude_flags.ts:186`'s `ensureClaudeHelpCache()` calls `Bun.spawn(["claude", "--help"], {stdout: "pipe", stderr: "pipe"})` with no explicit `env` option, and on Bun 1.3.13 a bare `Bun.spawn` uses Bun's own environment snapshot taken at process startup, not the live mutated `process.env` -- so `withholdGithubTokens()`'s `delete process.env["GH_TOKEN"]` (etc.) never reaches this spawn.** Reproduced two ways: a minimal `PROBE_VAR`-set-then-delete-then-bare-spawn repro, and an end-to-end run of the real `loki-ts/dist/loki.js` inside the same sandboxed harness `tests/moat/p9-rule-of-two.sh`'s `inj_run` builds -- the main `-p <prompt>` provider call (via `shell.ts run()`, which explicitly passes `env: {...process.env}`) came back clean, but the `--help` capability-detection probe leaked both canary tokens. Scope-checked every bare `Bun.spawn`/`spawnSync`/`execFileSync` in `loki-ts/src` outside `.test.` files: `council/voter_agents.ts` and `util/bash_delegate.ts` both already pass `env` explicitly and are clean; `claude_flags.ts:186` is the only bare spawn that both omits `env` and launches the literal `claude` binary. `P9.injection-cannot-reach-token` is a proven case in `tests/moat/cases.txt` (not pending), so a correct Bun-route sub-case would go RED on current main from this real gap. Fix direction: pass `env: process.env` (match whichever exact convention `shell.ts run()`/`voter_agents.ts` use) at the spawn call, rebuild `loki-ts/dist/loki.js`, verify the fix is present in the built artifact (grep a unique string, not the function name, since minification renames it), and land the fix together with the new Bun-route P9 sub-case as its regression guard. **FIXED (S-40, merged 2f506f3e).** A reviewer found 2 additional out-of-scope bare spawns (`doctor.ts`, `quality_gates.ts`) and confirmed both are unreachable from `withholdGithubTokens()`'s call path (loki doctor never calls runAutonomous()), so genuinely out of scope, not silently missed.
|
|
212
|
-
|
|
213
|
-
143. **CONFIRMED STRUCTURAL (4 occurrences, all the SAME shard index): GitHub Actions "Shell tests (shard 2/4)" has now hung 4 times (23min, 22m42s, 23m50s, 20m22s) against a configured `timeout-minutes: 20`, well past GitHub's own enforcement point, while every other shard/job on the same runs finished in under a minute.** All 4 manually cancelled and a fresh push retriggered a clean run each time. This is no longer "watch for a third occurrence" -- 4 hangs on the identical shard index across one session is structural, not noise. Possible causes to investigate: a specific suite in shard 2's partition hanging on a resource wait (network, lock file, background process not exiting), a GitHub-side runner/queue issue unrelated to this repo's code, or `timeout-minutes` not being honored correctly for this job's shape (e.g. a step-level timeout vs job-level, or a step that traps/ignores the timeout signal). Fix direction: add a per-suite or per-step timeout inside the shard runner itself (not just the job-level `timeout-minutes`) so a single hanging suite can't consume the whole shard's budget silently, and instrument which specific suite was running when the hang occurred (a log timestamp before/after each suite in the shard).
|
|
214
|
-
|
|
215
|
-
144. **P7's fabricated-return-from-helper scanner arm (S-29 BACKLOG 125 B-7's fix, merged/in-review) only recognizes function declarations, arrow functions, function expressions, and typed variants -- not class methods.** Found by S-31's builder during their own honest ceiling-disclosure while building the fix: a neutrally-named class method (`_getRows() { return [{...fabricated...}]; } ... this._rows = this._getRows();`) is caught by no rule, including the pre-existing rule 5 (`this.x =` direct-literal arm), because the fabrication is one level removed through the method call. Flagged as the DOMINANT uncovered shape in `legacy-ui`'s `LokiElement`-based components, which use this exact class-method pattern extensively. No known live instance confirmed yet (a full-repo scan diff was empty both before and after S-31's fix), so this is a real, structurally-plausible gap, not yet a proven live bypass. Fix direction: extend the helper-return-tracking arm to also recognize a class method declaration (`methodName(...) { ... return [literal]; ... }`) as a trackable helper head, with the same sink-resolution logic already built for standalone functions.
|
|
216
|
-
|
|
217
|
-
145. **P7's `Array.from` generator scanner arm (S-32 BACKLOG 125 B-8's fix, merged) loses an outer scope's loop variable when Array.from generators are nested.** Found by S-32's reviewer 2: `Array.from({length}, (_, r) => Array.from({length}, (_, c) => ({...fabricated...})))` -- the inner generator's parameter substitution only zeroes its own immediate arrow's params, not the outer enclosing generator's index variable it references by closure (e.g. `r`). That leftover free identifier makes `is_literal` reject the whole row as non-literal, so a real fabricated field sitting next to it goes undetected. A different mechanism from BACKLOG 144's class-method gap and from a separately-found destructured-params gap (both already disclosed as this arm's ceiling) -- this one is specifically about nested-scope variable leakage through the substitution step. No known live instance confirmed. Fix direction: when substituting arrow params with 0 for the fabrication check, also substitute any enclosing (outer) generator's own parameters if the inner callback is itself inside another Array.from generator's callback body.
|
|
218
|
-
|
|
219
|
-
146. **P7's entire fabricated-data scanner (`FLOWS_TO_STATE_TMPL`/`SETTER` regex, used by every detection arm) only recognizes a literal setter name (`\bset[A-Z]\w*\(`) or `useState(` as a data sink -- a computed/dynamic sink call bypasses every arm, not just one.** Found and re-verified by S-31's rework builder while fixing the useMemo bypass: `window[sinkName](rows)` or `this[dynamicKey](rows)` (rows being fabricated) reproduces identically with S-31 fully reverted, confirming this is scanner-wide and pre-existing, not introduced by any of the P7 sibling slices (S-27 through S-32) built this session. No known live instance confirmed in web-app/legacy-ui today (computed sink names are an unusual/obfuscated pattern, not mainstream React idiom). Fix direction: broaden the sink-matching regex to also resolve a bracket-indexed or computed member-expression call when the property/key resolves to a name already known to be a setter-like binding (harder than the literal-name case; likely needs its own dedicated slice rather than a quick regex tweak, given the scope of every arm that would need updating).
|
|
220
|
-
|
|
221
|
-
147. **P7's `DECL_USEMEMO` arm (S-31 BACKLOG 125 B-7's rework, in review) only detects a `useMemo` factory that returns a literal directly (`useMemo(() => [...], deps)`), not one that calls ANOTHER already-registered fabricator (`useMemo(() => helperCall(), deps)`, where `helperCall` is itself a HELPER_HEAD-registered function that returns a fabricated literal).** Found during S-31's own second-round review: the rework's comment initially claimed this composed form was "covered by DECL_USEMEMO," which is inaccurate -- DECL_USEMEMO only inspects the factory body for a direct literal return, never a call expression, so this shape is invisible to both DECL_USEMEMO (no direct literal) and HELPER_HEAD's own call-site machinery (the useMemo-bound name is a value, never itself called as `name(args)`). No known live instance confirmed. Fix direction: `HELPER_LOCAL_DECL_TMPL` already matches `{name}\s*\(` with `fabricators` populated -- adding an optional `(?:React\.)?useMemo\(\s*\(\)\s*=>\s*` prefix ahead of the fabricator-call pattern is a plausible one-line close for the concise-arrow form, offered as a candidate by a reviewer, not a requirement.
|
|
222
|
-
|
|
223
|
-
148. **`tests/moat/run.sh`'s baseline-detection (`read_baselines()`, and now `unreached_release()` too since S-20 mirrors it) has a real blind spot on symlinked baseline files: `git grep -l`/`-L` both return rc=1 ("no match") on a mode-120000 blob even when it has real content.** Found by S-20's reviewer 2 while stress-testing the rework: a symlinked `tests/moat/pending.txt` at a normal, reachable release tag is invisible to the existing (pre-S-20) `read_baselines()` too, not something S-20 introduced -- confirmed via direct reproduction. This falsifies the code's own comment claiming the `-l`/`-L` union covers "exactly every tag whose tree has the file at all" (true only for regular-file blobs). No known live instance in this repo's actual tag history. Fix direction: add a third check for a symlinked baseline file (`git ls-tree` mode 120000) at the tags already being walked, treating it the same as a real baseline (fail closed, don't silently miss it) rather than leaving the gap unaddressed.
|
|
224
|
-
|
|
225
|
-
149. **REAL, LIVE, CONFIRMED-EXPLOITED GAP (escalated from BACKLOG 44's test-coverage framing): Rule-of-Two's GH-token withhold (`_loki_withhold_github_tokens`/Bun's `withholdGithubTokens()`) strips only 4 env vars, never the GitHub CLI's own `hosts.yml` credential store, which the provider's genuinely-live `$HOME` still exposes.** Found by S-18's builder, reproduced empirically on BOTH routes (bash and the real shipped `loki-ts/dist/loki.js`, no mocks): a planted `~/.config/gh/hosts.yml` canary was read and exfiltrated by the real `gh` CLI in the DEFAULT scenario, while the existing GH_TOKEN/GITHUB_TOKEN env-var canary checks stayed correctly green in the same run -- proving the env-var withhold works exactly as intended and this is a wholly separate, currently-uncovered vector, not a weaker instance of the same one. Root cause: the provider's real `$HOME` is intentionally kept live (documented at `autonomy/run.sh:1310`) so Claude's own OAuth continues to work between iterations; nothing scopes that HOME exposure away from the GitHub CLI's own credential resolution (`$GH_CONFIG_DIR`/`$XDG_CONFIG_HOME`/`~/.config/gh/hosts.yml`, keyring or plaintext depending on `gh auth login --insecure-storage` and platform keyring availability). Severity is highest on machines using `--insecure-storage`, headless/containerized Linux without a keyring backend, or any dev machine where `gh auth login` was run interactively -- CI runners that only ever export `GH_TOKEN`/`GITHUB_TOKEN` (never `gh auth login`) are unaffected, since there is no `hosts.yml` to read there. Fix direction (builder's own recommendation, least invasive): scope `$GH_CONFIG_DIR` to an empty, per-run directory before the provider session starts, on both routes, so `gh`'s own credential resolution finds nothing -- this does NOT touch `$HOME` itself, so Claude's own OAuth continues to work untouched. Must not be a blanket HOME sandbox. Extend `tests/moat/p9-rule-of-two.sh`'s existing `P9.injection-cannot-reach-token` case (same case ID, additive) with the hosts.yml-canary probe the builder already built and validated, once the fix lands -- landing the test before the fix would correctly flip the case red on a known, already-tracked gap. **PARTIALLY FIXED (S-18 first attempt, REJECTED by review 2026-09-27): GH_CONFIG_DIR scoping alone is confirmed insufficient -- macOS Keychain-backed gh auth and git's default `credential.helper = !gh auth git-credential` both survive it. Rework in flight, see D23.**
|
|
226
|
-
|
|
227
|
-
150. **BACKLOG 143's fix (S-44) revealed the true root cause of every "shard 2/4 hangs" incident this session (10+ occurrences): it was never a hang.** `tests/test-ci-json-argmax.sh` legitimately takes 5-22 minutes (builds a real ~29K-116K-line finding diff to exercise `loki ci --format json` against Linux's ARG_MAX), and the workflow's own `cancel-in-progress` concurrency group killed shard 2 mid-run every time a new push landed before that suite finished -- the exact push-storm-cancels-CI pattern this session already knew about at the commit level (see PROGRESS.md's turn-12-era incident), just never connected to the shard-level symptom until S-44's builder traced it via `gh run view --log` on the actual cancelled runs. S-44's fix (per-suite timeout + logging) correctly makes a TRUE hang fail loudly and name itself, but does NOT stop `cancel-in-progress` from killing shard 2 on a fast push cadence -- that requires shard 2 finishing inside the push interval, and argmax alone can consume most of a 20-25 minute window. Fix direction: shrink the argmax fixture's finding-diff size (does it need to be 29K-116K lines to genuinely exercise ARG_MAX, or would a smaller value that still crosses the real OS limit suffice), or move `test-ci-json-argmax.sh` out of the sharded, cancel-in-progress-affected job entirely into its own non-cancelled workflow/job.
|
|
228
|
-
|
|
229
|
-
## Later milestones
|
|
230
|
-
|
|
231
|
-
M1 one command, M2 Seal and Wall, M3 assign like a teammate, M4 system map, M5 the line, M6 ship and operate, M7 one screen, M8 legacy lane, M9 enterprise readiness, M10 simplify and ship v10.0.0. Items get broken out here when their milestone comes up.
|