loki-mode 9.55.0 → 9.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/actions/issue-to-pr/action.yml +165 -29
- package/.github/workflows/loki-issue-to-pr.yml +137 -24
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/proof-check.sh +9 -0
- package/autonomy/lib/proof-generator.py +12 -3
- package/autonomy/lib/workspace_diff.py +18 -7
- package/autonomy/loki +133 -3
- package/autonomy/run.sh +385 -22
- package/dashboard/__init__.py +1 -1
- package/dashboard/api_keys.py +12 -5
- package/dashboard/build_supervisor.py +25 -1
- package/dashboard/server.py +46 -24
- package/dashboard/static/index.html +57 -57
- package/docs/VERIFIED-COMPLETION-PLAN.md +7 -5
- package/docs/dev/architecture-reference.md +99 -0
- package/docs/dev/project-structure.md +134 -0
- package/docs/dev/release-checklist.md +157 -0
- package/docs/dev/research-foundation.md +29 -0
- package/docs/dev/tmp-cleanup.md +157 -0
- package/docs/environment-variables.md +1 -0
- package/docs/v10/BACKLOG.md +33 -0
- package/docs/v10/BOARD.md +97 -27
- package/docs/v10/DECISIONS.md +43 -0
- package/docs/v10/OPERATING-MODEL.md +47 -0
- package/docs/v10/PROGRESS.md +893 -0
- package/loki-ts/dist/loki.js +326 -325
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/providers/claude.sh +1 -1
- package/providers/model_catalog.json +12 -5
- package/providers/models.sh +1 -1
- package/references/core-workflow.md +1 -1
- package/web-app/dist/assets/{AdminPage-CZrBkzRF.js → AdminPage-Oyx-w2Ch.js} +1 -1
- package/web-app/dist/assets/{Avatar-gQIp6FBI.js → Avatar-D60m65JB.js} +1 -1
- package/web-app/dist/assets/{Badge-D2_fBTFY.js → Badge-CqfZNaem.js} +1 -1
- package/web-app/dist/assets/{Button-D5qDd2ef.js → Button-BqjzE4fz.js} +1 -1
- package/web-app/dist/assets/CockpitPage-Czk7o_ou.js +47 -0
- package/web-app/dist/assets/ComparePage-BEfTrTb1.js +1 -0
- package/web-app/dist/assets/{ErrorBoundary-BRABI-BT.js → ErrorBoundary-BrLk5nkO.js} +1 -1
- package/web-app/dist/assets/EvidenceReceiptPanel-9vEpi5ir.js +1 -0
- package/web-app/dist/assets/{GitHubIssuesPanel-BC5GzKUN.js → GitHubIssuesPanel-D6izZx0w.js} +1 -1
- package/web-app/dist/assets/GitHubPRsPanel-BTkG2FgA.js +17 -0
- package/web-app/dist/assets/{HomePage-D_CDMoen.js → HomePage-nsr4kpN1.js} +2 -2
- package/web-app/dist/assets/{LoginPage-BBNA_N9t.js → LoginPage-BVblQrr9.js} +1 -1
- package/web-app/dist/assets/{MagicPage-CnFRZCMx.js → MagicPage-CmnSyLq7.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-CPfLMRlh.js → MetricsPage-BVfwU81j.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-lA0XSGTz.js → NotFoundPage-AYQ6uqqI.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-CNAPbr9z.js → ProjectPage-DMnbw9X9.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-CMtm8goN.js → ProjectsPage-CNVTAF2N.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-BhIjVMYE.js → SettingsPage-D1_qasFD.js} +3 -3
- package/web-app/dist/assets/{ShowcasePage-BndtGeYo.js → ShowcasePage-2dBCjLXn.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-euXI-KXE.js → SystemSettingsPage-Djo6IE4u.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-ClUKecun.js → TeamsPage-CY8p-yxD.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-BWHWVk0L.js → TemplatesPage-B6iFgH6t.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Cv3N3Szf.js → TerminalOutput-B3yzZe-h.js} +1 -1
- package/web-app/dist/assets/{activity-dEhz-bXR.js → activity-CNfAjtRv.js} +1 -1
- package/web-app/dist/assets/{bell-B3XUMq1t.js → bell-CMETsHPH.js} +1 -1
- package/web-app/dist/assets/{bot-X-ssNlwR.js → bot-C9kXvk1i.js} +1 -1
- package/web-app/dist/assets/{check-C_9Nx7kb.js → check-BRK-zLB5.js} +1 -1
- package/web-app/dist/assets/{chevron-left-tvNswo3A.js → chevron-left-CxI5uD4g.js} +1 -1
- package/web-app/dist/assets/{circle-alert-CSB88nEs.js → circle-alert-CVFRPWpv.js} +1 -1
- package/web-app/dist/assets/{clock-C8p2e4NI.js → clock-CLYV8a_x.js} +1 -1
- package/web-app/dist/assets/{cloud-CKp2ZvhG.js → cloud-CiISiIOa.js} +1 -1
- package/web-app/dist/assets/{code-xml-dY70LCHD.js → code-xml-DHsgqwV-.js} +1 -1
- package/web-app/dist/assets/{database-DObn5fmn.js → database-DbvUqtz3.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-DSu6n3K3.js → dollar-sign-Ct0lRPHw.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-DpCnS73z.js → file-code-corner-D1sjFEh7.js} +1 -1
- package/web-app/dist/assets/{file-plus-D3IPKCf1.js → file-plus-DnmX18Fi.js} +1 -1
- package/web-app/dist/assets/{globe-C9QXkgH_.js → globe-bSpDNgoA.js} +1 -1
- package/web-app/dist/assets/{hammer-D_FtWe1y.js → hammer-Bj41Kvlq.js} +1 -1
- package/web-app/dist/assets/{index-CI54rara.css → index-BfQ0f3-S.css} +1 -1
- package/web-app/dist/assets/{index-Cz7q1bvC.js → index-CxajNJVu.js} +3 -3
- package/web-app/dist/assets/{layers-DsW7jnJX.js → layers-BNtBwYER.js} +1 -1
- package/web-app/dist/assets/{loader-circle-B3HspjKR.js → loader-circle-YY_VZofG.js} +1 -1
- package/web-app/dist/assets/{lock-DSI29pct.js → lock-rpjEPVoC.js} +1 -1
- package/web-app/dist/assets/{package-CLNxtA2x.js → package-desXU6XA.js} +1 -1
- package/web-app/dist/assets/{plus-DyI4WC4_.js → plus-7AoOU-I9.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-D2dv0xA0.js → refresh-cw-oNj-Xn4B.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-CBvihA-a.js → rotate-ccw-DeiFjfVO.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DvoOvAl_.js → scroll-text-Q9AzWiNV.js} +1 -1
- package/web-app/dist/assets/{server-DenWvSUt.js → server-DKgVwfek.js} +1 -1
- package/web-app/dist/assets/{shield-alert-40cX_FvG.js → shield-alert-G6x-bS-I.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BrjZ6QuV.js → thumbs-up-Qhk0yvw0.js} +1 -1
- package/web-app/dist/assets/{trash-2-C6evwkEH.js → trash-2-D23gvznl.js} +1 -1
- package/web-app/dist/assets/{trending-down-CfbZis3O.js → trending-down-CSQClPrr.js} +1 -1
- package/web-app/dist/assets/{trending-up-DWuEK3WC.js → trending-up-sjMSd1wc.js} +1 -1
- package/web-app/dist/assets/{upload-B9DFBcPG.js → upload-Dchovhld.js} +1 -1
- package/web-app/dist/assets/{usePolling-BryVC-T1.js → usePolling-DwLceXwF.js} +1 -1
- package/web-app/dist/assets/{user-DMRXwZiw.js → user-BqZM8CmD.js} +1 -1
- package/web-app/dist/index.html +2 -2
- package/web-app/server.py +52 -17
- package/web-app/dist/assets/CockpitPage-DVMk2RUK.js +0 -47
- package/web-app/dist/assets/ComparePage-NMLyE1xL.js +0 -1
- package/web-app/dist/assets/EvidenceReceiptPanel-D2LNKqUx.js +0 -1
- package/web-app/dist/assets/GitHubPRsPanel-BSlmoVTS.js +0 -17
package/docs/v10/BACKLOG.md
CHANGED
|
@@ -193,6 +193,39 @@ Status values: todo, in progress, shipped (version), parked (reason).
|
|
|
193
193
|
|
|
194
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
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 `dashboard-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/dashboard-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
|
+
|
|
196
229
|
## Later milestones
|
|
197
230
|
|
|
198
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.
|