loki-mode 11.17.51 → 11.17.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/secure-scan.py +70 -2
  4. package/dashboard/__init__.py +1 -1
  5. package/docs/CLI-REFERENCE.md +6 -1
  6. package/docs/INSTALLATION.md +1 -1
  7. package/docs/v10/BOARD.md +62 -2
  8. package/docs/v10/CLI-MODERN.md +1 -1
  9. package/docs/v10/FAILURE-CLASSES.md +7 -0
  10. package/docs/v10/PROGRESS.md +6 -0
  11. package/loki-ts/dist/loki.js +1114 -1114
  12. package/mcp/__init__.py +1 -1
  13. package/package.json +2 -2
  14. package/packages/control-plane/dist/ask-tools-server.js +6 -2
  15. package/packages/control-plane/dist/server.js +319 -67
  16. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  17. package/web-app/dist/assets/{AdminPage-CDSL6lzQ.js → AdminPage-B5S4tImz.js} +1 -1
  18. package/web-app/dist/assets/{Avatar-BG02zRCM.js → Avatar-DVT9cXf-.js} +1 -1
  19. package/web-app/dist/assets/{Badge-DZAAUjis.js → Badge-D-n8nS0d.js} +1 -1
  20. package/web-app/dist/assets/{Button-BXHri3Bg.js → Button-Dfgum0N6.js} +1 -1
  21. package/web-app/dist/assets/{CockpitPage-DzSQmo7Q.js → CockpitPage-4xhSdrDM.js} +1 -1
  22. package/web-app/dist/assets/{ComparePage-Bo_nMN8K.js → ComparePage-CPta-oKN.js} +1 -1
  23. package/web-app/dist/assets/{ErrorBoundary-CTQU5X7k.js → ErrorBoundary-CR8B9oGo.js} +1 -1
  24. package/web-app/dist/assets/{EvidenceReceiptPanel-C4lQ99Wp.js → EvidenceReceiptPanel-CUhElwm7.js} +1 -1
  25. package/web-app/dist/assets/{GitHubIssuesPanel-DkKxlaTB.js → GitHubIssuesPanel-xKI3dI1W.js} +1 -1
  26. package/web-app/dist/assets/{GitHubPRsPanel-Br02sXlA.js → GitHubPRsPanel-CJ16YJ9s.js} +1 -1
  27. package/web-app/dist/assets/{HomePage-DjXhkhFt.js → HomePage-CzW6cDpa.js} +2 -2
  28. package/web-app/dist/assets/{LoginPage-C4xmRk7J.js → LoginPage-CV6Tvhge.js} +1 -1
  29. package/web-app/dist/assets/{MagicPage-D_r38Yde.js → MagicPage-Dqq2v6Uu.js} +1 -1
  30. package/web-app/dist/assets/{MetricsPage-B9Y1p-FE.js → MetricsPage-w5e0DFyq.js} +1 -1
  31. package/web-app/dist/assets/{NotFoundPage-BTNNHLAC.js → NotFoundPage-CD15KPqA.js} +1 -1
  32. package/web-app/dist/assets/{ProjectPage-DUUDqjbc.js → ProjectPage-CLOEGdOa.js} +3 -3
  33. package/web-app/dist/assets/{ProjectsPage-CxX842kz.js → ProjectsPage-wVGxTUqN.js} +1 -1
  34. package/web-app/dist/assets/{SettingsPage-IUQeYuCB.js → SettingsPage-tcZTOUCx.js} +1 -1
  35. package/web-app/dist/assets/{ShowcasePage-DGYLnI8h.js → ShowcasePage-DhhFuJrY.js} +1 -1
  36. package/web-app/dist/assets/{SystemSettingsPage-Dl8x3Woj.js → SystemSettingsPage-DJTIpzRe.js} +1 -1
  37. package/web-app/dist/assets/{TeamsPage-CJ4TPxjB.js → TeamsPage-D_G-ch7e.js} +1 -1
  38. package/web-app/dist/assets/{TemplatesPage-O8LCjJtq.js → TemplatesPage-Br8IjtsC.js} +1 -1
  39. package/web-app/dist/assets/{TerminalOutput-DGTWYoJB.js → TerminalOutput-CDpeKr1C.js} +1 -1
  40. package/web-app/dist/assets/{activity-CNqE-ixm.js → activity-D3HHYtv7.js} +1 -1
  41. package/web-app/dist/assets/{bell-BEi_il9M.js → bell-Cw_RiUI1.js} +1 -1
  42. package/web-app/dist/assets/{bot-CkFZ33Q-.js → bot-CvSdbJCG.js} +1 -1
  43. package/web-app/dist/assets/{check-C_qLIaF-.js → check-BrdmdEjE.js} +1 -1
  44. package/web-app/dist/assets/{chevron-left-B5XC_KnW.js → chevron-left-BNGgoAGR.js} +1 -1
  45. package/web-app/dist/assets/{circle-alert-64ZS4s9j.js → circle-alert-DbRWBNqr.js} +1 -1
  46. package/web-app/dist/assets/{clock-BHdB3bZI.js → clock-Be7jXWMi.js} +1 -1
  47. package/web-app/dist/assets/{cloud-dnsbryqT.js → cloud-CRvIp-jH.js} +1 -1
  48. package/web-app/dist/assets/{code-xml-iLJ48no4.js → code-xml-BzHwWlm3.js} +1 -1
  49. package/web-app/dist/assets/{database-D2uC8Rxd.js → database-91AqM-FY.js} +1 -1
  50. package/web-app/dist/assets/{dollar-sign-B47Mg178.js → dollar-sign-BeNsKJBp.js} +1 -1
  51. package/web-app/dist/assets/{file-code-corner-Dlp_xnun.js → file-code-corner-BvNUefQ2.js} +1 -1
  52. package/web-app/dist/assets/{file-plus-VfERZYg5.js → file-plus-DSdhJlCE.js} +1 -1
  53. package/web-app/dist/assets/{globe-BBduzaTh.js → globe-alpFSVbm.js} +1 -1
  54. package/web-app/dist/assets/{hammer-QSASdDEK.js → hammer-DceL_3zd.js} +1 -1
  55. package/web-app/dist/assets/{index-C0weGbNK.js → index-BOfXC5KW.js} +3 -3
  56. package/web-app/dist/assets/{layers-BAfPZ8HU.js → layers-C2dORLkY.js} +1 -1
  57. package/web-app/dist/assets/{loader-circle-DXqBgYWH.js → loader-circle-CcbHAofe.js} +1 -1
  58. package/web-app/dist/assets/{lock-LCsOKAUi.js → lock-yivPar99.js} +1 -1
  59. package/web-app/dist/assets/{package-BLUwVAd0.js → package-BGe4JXNK.js} +1 -1
  60. package/web-app/dist/assets/{plus-LHz4MkJH.js → plus-BpZ4ajEG.js} +1 -1
  61. package/web-app/dist/assets/{refresh-cw-CnGPNK6c.js → refresh-cw-CqIBSjzI.js} +1 -1
  62. package/web-app/dist/assets/{rotate-ccw-D7EWVgA8.js → rotate-ccw-C7s45N_R.js} +1 -1
  63. package/web-app/dist/assets/{scroll-text-vVVQ3jTP.js → scroll-text-Ce9Kmot6.js} +1 -1
  64. package/web-app/dist/assets/{server-CVmxaWog.js → server-DyUYnlLz.js} +1 -1
  65. package/web-app/dist/assets/{shield-alert-DCrN0N7j.js → shield-alert-DT2LYxTG.js} +1 -1
  66. package/web-app/dist/assets/{thumbs-up-BVtgLRAB.js → thumbs-up-DJeSSzDq.js} +1 -1
  67. package/web-app/dist/assets/{trash-2-BmSBvfQk.js → trash-2-BfICAUqu.js} +1 -1
  68. package/web-app/dist/assets/{trending-down-BIIzpX-l.js → trending-down-DzjhrhCE.js} +1 -1
  69. package/web-app/dist/assets/{trending-up-D8z8AEPW.js → trending-up-qxrTgUwQ.js} +1 -1
  70. package/web-app/dist/assets/{upload-50BgK2yG.js → upload-BRZGP_py.js} +1 -1
  71. package/web-app/dist/assets/{usePolling-B33v_P8Z.js → usePolling-V4nOdEIl.js} +1 -1
  72. package/web-app/dist/assets/{user-DWe9X5rS.js → user-CHfDU18s.js} +1 -1
  73. package/web-app/dist/index.html +1 -1
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: An autonomous software factory that knows what it is supposed to deliver, and proves it did. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
4
4
  ---
5
5
 
6
- # Loki Mode v11.17.51
6
+ # Loki Mode v11.17.53
7
7
 
8
8
  **Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the previous bash loop. PRD-file starts (`loki start ./prd.md`) and the opencode provider still run on it until FC38-SWEEP ports them; the legacy-engine command and the LOKI_ENGINE switch remain removed. Prefer `loki owner/repo#N` for issues.
9
9
 
@@ -483,4 +483,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
483
483
 
484
484
  ---
485
485
 
486
- **v11.17.51 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
486
+ **v11.17.53 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.17.51
1
+ 11.17.53
@@ -18,7 +18,7 @@ The scanner is honest by construction:
18
18
  .git, vendor, bundled dist of dependencies) and oversized files, so it is
19
19
  cheap and deterministic.
20
20
 
21
- The v1 rules (rules 6, 7 and 8 added later) (see internal/LOOP4-SECURE-BY-DEFAULT-PLAN.md):
21
+ The v1 rules (rules 6, 7, 8, 9 and 10 added later) (see internal/LOOP4-SECURE-BY-DEFAULT-PLAN.md):
22
22
  1. private-key-committed (HIGH) a PEM private-key block in any text file
23
23
  2. secret-in-client-file (HIGH) a real secret literal in a browser-served file
24
24
  3. world-open-datastore (HIGH) a literal world-open datastore rule
@@ -47,7 +47,7 @@ import re
47
47
  import subprocess
48
48
  import sys
49
49
 
50
- RULES_VERSION = "1.4"
50
+ RULES_VERSION = "1.7"
51
51
 
52
52
  # --- scan limits -----------------------------------------------------------
53
53
  # Cap per-file size so a giant generated bundle cannot stall the gate. 2 MiB is
@@ -133,6 +133,12 @@ _SECRET_PATTERNS = [
133
133
  ("stripe-key", re.compile(r"(?<![A-Za-z0-9])[sr]k_live_[A-Za-z0-9]{24,}")),
134
134
  # SendGrid API key: SG.<22>.<43>
135
135
  ("sendgrid-key", re.compile(r"(?<![A-Za-z0-9])SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}")),
136
+ # AWS temporary (STS) access key id
137
+ ("aws-sts-key", re.compile(r"\bASIA[0-9A-Z]{16}\b")),
138
+ # Azure storage connection string account key: 86 base64 chars + ==
139
+ ("azure-account-key", re.compile(r"AccountKey=[A-Za-z0-9+/]{86}==")),
140
+ # Twilio API key SID: SK + 32 hex
141
+ ("twilio-key", re.compile(r"(?<![A-Za-z0-9])SK[0-9a-f]{32}(?![A-Za-z0-9])")),
136
142
  ]
137
143
 
138
144
  # Placeholder / example markers. If the matched secret (or its surrounding
@@ -461,6 +467,42 @@ def _shell_injection_hit(text, node_file):
461
467
  return qualified or node_file
462
468
 
463
469
 
470
+ # ---------------------------------------------------------------------------
471
+ # rule 9: unsafe deserialization (Python files)
472
+ # ---------------------------------------------------------------------------
473
+ # pickle.load/loads (also cPickle, _pickle), marshal.load/loads, and yaml.load
474
+ # without a Safe loader on the same line. yaml.safe_load and
475
+ # yaml.load(..., Loader=yaml.SafeLoader) are never flagged. Same path
476
+ # exclusions as rules 6 and 7. Python files only (.py).
477
+ _UNSAFE_DESERIALIZE = re.compile(
478
+ r"""\b(?:c?[pP]ickle|_pickle|marshal)\.loads?\s*\("""
479
+ )
480
+ _YAML_LOAD = re.compile(r"""\byaml\.load(?:_all)?\s*\(""")
481
+ _YAML_SAFE_LOADER = re.compile(r"""\bC?SafeLoader\b""")
482
+
483
+
484
+ def _deserialize_hit(text):
485
+ if _UNSAFE_DESERIALIZE.search(text):
486
+ return True
487
+ return bool(_YAML_LOAD.search(text) and not _YAML_SAFE_LOADER.search(text))
488
+
489
+
490
+ # ---------------------------------------------------------------------------
491
+ # rule 10: SQL built by string formatting and passed to execute() (Python)
492
+ # ---------------------------------------------------------------------------
493
+ # .execute( / .executemany( whose first argument is an interpolated f-string
494
+ # (with a {placeholder}), a string literal followed by % or +, or a string
495
+ # literal followed by .format(. A literal followed by a comma (parameter
496
+ # tuple or list) is the safe form and is never flagged. Same line only; same
497
+ # path exclusions as rules 6, 7 and 9. Python files only (.py).
498
+ _SQL_EXEC_FORMATTED = re.compile(
499
+ r"""\.execute(?:many)?\s*\(\s*(?:"""
500
+ r"""[rR]?[fF]"[^"]*\{|[rR]?[fF]'[^']*\{"""
501
+ r"""|[rR]?"[^"]*"\s*(?:%|\+|\.format\s*\()"""
502
+ r"""|[rR]?'[^']*'\s*(?:%|\+|\.format\s*\())"""
503
+ )
504
+
505
+
464
506
  # ---------------------------------------------------------------------------
465
507
  # rule 8: committed real env file with a secret assignment
466
508
  # ---------------------------------------------------------------------------
@@ -578,6 +620,8 @@ def _scan_file(rel_path, lines, secrets_everywhere=False, env_tracked=None):
578
620
  env_in_git = env_tracked is not None
579
621
  if real_envfile and env_in_git and rel_path not in env_tracked:
580
622
  real_envfile = False
623
+ deser_scan = shell_scan and rel_path.lower().endswith(".py")
624
+ sqli_scan = deser_scan
581
625
  node_file = shell_scan and any(_NODE_CP_FILE.search(t) for _, t in lines)
582
626
 
583
627
  # rule 3 / rule 5 need whole-file context for the AND conditions.
@@ -723,6 +767,30 @@ def _scan_file(rel_path, lines, secrets_everywhere=False, env_tracked=None):
723
767
  "interpolate input into a command string.",
724
768
  ))
725
769
 
770
+ # --- rule 9: unsafe deserialization ------------------------------
771
+ if (deser_scan and not _COMMENT_OR_DOC_LINE.match(text)
772
+ and _deserialize_hit(text)):
773
+ findings.append(_finding(
774
+ "unsafe-deserialization", rel_path, lineno, "HIGH",
775
+ "Untrusted bytes or YAML passed to pickle, marshal or an "
776
+ "unsafe yaml.load can execute arbitrary code on load.",
777
+ "Use yaml.safe_load (or Loader=yaml.SafeLoader) and a data "
778
+ "format such as JSON; never unpickle or unmarshal data from "
779
+ "an untrusted source.",
780
+ ))
781
+
782
+ # --- rule 10: SQL built by string formatting ---------------------
783
+ if (sqli_scan and not _COMMENT_OR_DOC_LINE.match(text)
784
+ and _SQL_EXEC_FORMATTED.search(text)):
785
+ findings.append(_finding(
786
+ "sql-string-formatting", rel_path, lineno, "HIGH",
787
+ "SQL built with an f-string, % formatting, .format or "
788
+ "concatenation and passed to execute() is open to SQL "
789
+ "injection.",
790
+ "Pass values as bound parameters: "
791
+ "cursor.execute(\"... WHERE id = %s\", (value,)).",
792
+ ))
793
+
726
794
  # --- rule 8: committed real env file with a secret value ---------
727
795
  if real_envfile:
728
796
  env_name = _env_secret_assignment(text)
@@ -7,6 +7,6 @@ Modules:
7
7
  control: Session control helpers (status, atomic writes, origin check)
8
8
  """
9
9
 
10
- __version__ = "11.17.51"
10
+ __version__ = "11.17.53"
11
11
 
12
12
  __all__ = ["__version__"]
@@ -1,6 +1,6 @@
1
1
  # CLI reference
2
2
 
3
- Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.17.51. Do not edit by hand.
3
+ Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.17.53. Do not edit by hand.
4
4
  Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for the full inventory.
5
5
 
6
6
  | Command | Description |
@@ -30,6 +30,7 @@ Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for th
30
30
  | `loki rollback show` | Show a checkpoint |
31
31
  | `loki rollback to` | Restore a checkpoint |
32
32
  | `loki rollback latest` | Restore the latest checkpoint |
33
+ | `loki rollback deploy` | Print the provider rollback command for the last deploy (read-only) |
33
34
  | `loki backup` | Back up dashboard state (audit log, checkpoint) with a sha256 manifest |
34
35
  | `loki restore` | Restore dashboard state from a verified backup archive |
35
36
  | `loki proof` (alias: `receipt`) | Inspect and share proof-of-run receipts |
@@ -64,6 +65,10 @@ Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for th
64
65
  | `loki trust` | Trust trajectory from proof history |
65
66
  | `loki trust detail` | Trust metrics detail |
66
67
  | `loki crash` | Inspect or submit scrubbed crash reports |
68
+ | `loki crash list` | List stored crash reports |
69
+ | `loki crash show` | Show one scrubbed crash report |
70
+ | `loki crash submit` | Submit a scrubbed crash report |
71
+ | `loki crash help` | Show crash usage |
67
72
  | `loki contract` | Print the spec delivery contract |
68
73
  | `loki start` | Run the autonomous build (a `jira:KEY` or `linear:KEY` ref also writes the outcome back to that ticket, see docs/trackers.md) |
69
74
  | `loki slack` | Slack inbound handler |
@@ -2,7 +2,7 @@
2
2
 
3
3
  Loki Mode, by [Autonomi](https://www.autonomi.dev/), turns a spec or an issue into a verified pull request with a receipt you can check. This page covers installing it, a first run, and the options around it.
4
4
 
5
- **Version:** v11.17.51
5
+ **Version:** v11.17.53
6
6
 
7
7
  **Engine note:** `loki start` is the primary command. `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` all run the Loki 10 engine, whatever the flag order or input form (PRD file, issue ref, task or one-word brief). The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present. See the [user guide](v10/GUIDE.md) and the [5-minute quickstart](QUICKSTART.md).
8
8
 
package/docs/v10/BOARD.md CHANGED
@@ -1285,8 +1285,8 @@ Source: ~/git/autonomi-dev/research/2026-09-30-adoption/SWARM-PROMPT-ADOPTION.md
1285
1285
  | TEN-COST-46 | fix: cost_claim.py accepts `--target nan`, 0 or a negative number; with nan the `hi > target` test is False so the verdict can read PROVEN_AT(nan); require a finite target greater than 0 and exit 2 otherwise | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | MEDIUM | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k target_must_be_finite fails; green: passes, valid targets unchanged | released v11.17.50 | Gap: cost_claim.py:218 add_argument("--target", type=float) with no range check; :164 `if hi > target` is the only use. Chain: all COST-46..50 rows share cost_claim.py, run in order. |
1286
1286
  | TEN-COST-47 | fix: cost_claim.py with --loki-arm equal to --floor-arm compares an arm with itself (ratio 1.0) and can claim PROVEN at a target of 1.0 or more; refuse identical arm names with exit 2 | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | MEDIUM | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k same_arm fails; green: passes | released v11.17.50 | Gap: cost_claim.py:233-234 filters both arms by arg equality with no distinctness check. Serialize after TEN-COST-46. |
1287
1287
  | TEN-COST-48 | enhancement: cost_claim.py checks engine and loki_version are single-valued but not the model, so a floor arm on one model and a loki arm on a cheaper one reads as a cost win; add a model reason (missing, or differing between arms or within an arm) to the NOT PROVEN reasons | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | MEDIUM | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k model_mismatch fails; green: passes, equal-model fixtures keep their verdict | released v11.17.50 | Gap: grep -n model benchmarks/bench/cost_claim.py returned 0 although attribution.py:267 writes model on every row (the C-F1 pin). Serialize after TEN-COST-47. |
1288
- | TEN-COST-49 | feature: cost_claim.py verdict names the loki arm's cost_profile (lean, default, off) and refuses a loki arm that mixes profiles, so a lean-profile cost claim versus Claude Code is explicit evidence rather than an inference | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | MEDIUM | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k cost_profile fails (no cost_profile key in the verdict); green: passes, verdict gains cost_profile and a mixed arm adds a NOT PROVEN reason | ready@2026-10-17T12:00Z | Gap: attribution.py:263 and :737 stamp cost_profile on loki rows but grep -n cost_profile benchmarks/bench/cost_claim.py returned 0. Serialize after TEN-COST-48. |
1289
- | TEN-COST-50 | fix: `cost_claim.py --exclude-task typo` silently excludes nothing and still prints excluded_tasks, so a mistyped exclusion looks applied; warn on stderr for any excluded name that matches no row and list it as unmatched_exclusions in the verdict | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | LOW | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k unmatched_exclusion fails; green: passes | ready@2026-10-17T12:00Z | Gap: cost_claim.py:231 builds excl from the flag and :232 filters rows with no membership check. Serialize after TEN-COST-49. |
1288
+ | TEN-COST-49 | feature: cost_claim.py verdict names the loki arm's cost_profile (lean, default, off) and refuses a loki arm that mixes profiles, so a lean-profile cost claim versus Claude Code is explicit evidence rather than an inference | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | MEDIUM | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k cost_profile fails (no cost_profile key in the verdict); green: passes, verdict gains cost_profile and a mixed arm adds a NOT PROVEN reason | released v11.17.52 | Gap: attribution.py:263 and :737 stamp cost_profile on loki rows but grep -n cost_profile benchmarks/bench/cost_claim.py returned 0. Serialize after TEN-COST-48. |
1289
+ | TEN-COST-50 | fix: `cost_claim.py --exclude-task typo` silently excludes nothing and still prints excluded_tasks, so a mistyped exclusion looks applied; warn on stderr for any excluded name that matches no row and list it as unmatched_exclusions in the verdict | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | LOW | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k unmatched_exclusion fails; green: passes | released v11.17.52 | Gap: cost_claim.py:231 builds excl from the flag and :232 filters rows with no membership check. Serialize after TEN-COST-49. |
1290
1290
  | TEN-STABILITY-39 | enhancement: a non-numeric LOKI_PROVIDER_CALL_TIMEOUT (for example `2h`) silently disables the provider call timeout; print one stderr note naming the bad value and the 7200 default in effect, keep 0 as the deliberate no-timeout opt-out | loki-ts/src/runner/providers.ts, loki-ts/tests/runner/providers.test.ts | MEDIUM | red: cd loki-ts && bun test tests/runner/providers.test.ts -t "bad call timeout" fails (no note, timeout undefined); green: passes, unset and 0 behave as before | released v11.17.50 | Gap: providers.ts:543-547 treats NaN like 0 (comment: non-numeric means no timeout) with no message; a typo removes the safety cap on a paid call. |
1291
1291
  | TEN-STABILITY-40 | fix: a negative or garbage LOKI_QUEUE_ITEM_TIMEOUT_MIN kills every queued item at once (`Number(x) // 120` keeps a negative); accept only positive finite values and fall back to 120 with one stderr note | loki-ts/src/commands/queue.ts, loki-ts/tests/commands/queue.test.ts | LOW | red: cd loki-ts && bun test tests/commands/queue.test.ts -t "negative item timeout" fails; green: passes, valid values unchanged | released v11.17.50 | Gap: queue.ts:467 const mins = Number(process.env["LOKI_QUEUE_ITEM_TIMEOUT_MIN"]) // 120; setTimeout(proc.kill, mins * 60000) with mins -5 fires immediately. |
1292
1292
  | TEN-STABILITY-41 | fix: a negative LOKI_COUNCIL_REVIEW_TIMEOUT aborts the council review call immediately and the vote reads as a failure; accept only positive finite seconds, else 600 | loki-ts/src/council/voter_agents.ts, loki-ts/tests/council/voter_agents.test.ts | LOW | red: cd loki-ts && bun test tests/council/voter_agents.test.ts -t "negative review timeout" fails; green: passes | released v11.17.50 | Gap: voter_agents.ts:348 (Number(process.env["LOKI_COUNCIL_REVIEW_TIMEOUT"]) // 600) * 1000 keeps a negative number. |
@@ -1306,3 +1306,63 @@ Source: ~/git/autonomi-dev/research/2026-09-30-adoption/SWARM-PROMPT-ADOPTION.md
1306
1306
  | TEN-QUALITY-30 | fix: an invalid LOKI_E10_REPOMAP_MAX_FILES (abc, 0, -5, 1.5) silently falls back to 2000; print one stderr note naming the bad value and the default | loki-ts/src/engine10/repomap.ts, loki-ts/tests/engine10/repomap.test.ts | LOW | red: cd loki-ts && bun test tests/engine10/repomap.test.ts -t "bad max files note" fails; green: passes, cap value unchanged | released v11.17.50 | Gap: repomap.ts:19 maxFilesCap returns 2000 for any non-positive-integer with no warning. |
1307
1307
  | TEN-QUALITY-31 | fix: a non-numeric LOKI_E10_SNAPSHOT_MAX makes `st.size > NaN` false, so the intake snapshot hashes every untracked file however large; fall back to the 50 MB default when the value is not a positive finite number | loki-ts/src/e10ext/preexisting_dirty.ts, loki-ts/tests/e10ext/preexisting_dirty.test.ts (new: no test owns snapshotUntracked, only incidental use in seal.test.ts and machine.test.ts) | LOW | red: cd loki-ts && bun test tests/e10ext/preexisting_dirty.test.ts -t "bad snapshot max" fails; green: passes | released v11.17.50 | Gap: preexisting_dirty.ts:38 st.size > Number(process.env.LOKI_E10_SNAPSHOT_MAX ?? 50e6) with no finite check. |
1308
1308
  | TEN-ADOPTION-27 | enhancement: LOKI_AI_MARKING only turns on for the exact string 1; accept 1, true and yes (any case) like the other opt-in flags, so the compliance marking users set as true is not silently off | loki-ts/src/engine10/pr_body.ts, loki-ts/tests/engine10/ai_marking.test.ts | LOW | red: cd loki-ts && bun test tests/engine10/ai_marking.test.ts -t "true enables" fails; green: passes, unset and 0 stay off | released v11.17.50 | Gap: pr_body.ts:5 env["LOKI_AI_MARKING"] === "1". |
1309
+ | TEN-COST-51 | enhancement: cost_claim.py point ratio uses every row of each arm while the CI uses only paired tasks, so arms covering different task sets give a ratio the CI does not describe; add a NOT PROVEN reason "tasks: arms cover different task sets" | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | MEDIUM | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k task_set_mismatch fails; green: passes and the rest of the file stays green | released v11.17.53 | Gap: cost_claim.py:78-80 point ratio from _cpa(loki_rows)/_cpa(floor_rows) over all rows vs CI over paired tasks, no reason emitted. Chain COST-51, COST-52, COST-53 (same files). Serialize after TEN-COST-50 (board row is stale, code already built) |
1310
+ | TEN-COST-52 | feature: cost_claim.py refuses a proven verdict when rows lack cost_source or an arm mixes sources (claude_json.total_cost_usd vs loki.efficiency_cost), because mixed accounting makes the 2x claim unprovable | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | MEDIUM | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k cost_source fails; green: passes | released v11.17.53 | Gap: attribution.py:589 and :636 stamp cost_source but no grep hit for cost_source in cost_claim.py. Serialize after TEN-COST-51 |
1311
+ | TEN-COST-53 | fix: cost_claim.py _cpa treats a missing, None, NaN or negative cost_usd as 0.0 so a broken row makes Loki look cheaper; require finite cost >= 0 or add a NOT PROVEN reason | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | MEDIUM | red: pytest benchmarks/bench/tests/test_cost_claim.py -q -k bad_cost_row fails; green: passes | released v11.17.53 | Gap: cost_claim.py:28-34 float(r.get("cost_usd") or 0.0). Serialize after TEN-COST-52 |
1312
+ | TEN-SECURITY-16 | enhancement: redactSecrets also strips AWS temporary ASIA keys and Azure AccountKey= connection strings, both already recognised by export_sarif | loki-ts/src/util/redact.ts, loki-ts/tests/util/redact.test.ts | HIGH | red: cd loki-ts && bun test tests/util/redact.test.ts -t "asia and azure" fails; green: passes | released v11.17.53 | Gap: redact.ts:3-27 RULES has no ASIA or AccountKey rule; export_sarif.ts SECRET_PATTERNS lines 11-27 knows both |
1313
+ | TEN-SECURITY-17 | enhancement: export_sarif SECRET_PATTERNS also flags PyPI pypi-AgEI, Docker dckr_pat_, DigitalOcean dop_v1_, Google OAuth ya29., Shopify shpat_ and Postman PMAK- tokens | loki-ts/src/commands/export_sarif.ts, loki-ts/tests/commands/export_sarif.test.ts | HIGH | red: cd loki-ts && bun test tests/commands/export_sarif.test.ts -t "more token shapes" fails; green: passes | released v11.17.53 | Gap: export_sarif.ts:11-27 has none of the six shapes |
1314
+ | TEN-SECURITY-18 | enhancement: secure-scan.py _SECRET_PATTERNS also matches AWS ASIA keys, Azure AccountKey= and Twilio SK keys, and RULES_VERSION bumps | autonomy/lib/secure-scan.py, tests/test-secure-scan.sh | HIGH | red: bash tests/test-secure-scan.sh fails on the new fixtures; green: bash tests/test-secure-scan.sh passes | released v11.17.53 | Gap: secure-scan.py:111-136 lacks all three. Chain SECURITY-18, -19, -20 (same files) |
1315
+ | TEN-SECURITY-19 | feature: secure-scan.py rule 9 flags unsafe deserialization (pickle.loads, yaml.load without a safe loader, marshal.loads) in added lines | autonomy/lib/secure-scan.py, tests/test-secure-scan.sh | HIGH | red: bash tests/test-secure-scan.sh fails on the rule 9 fixtures; green: passes | released v11.17.53 | Gap: grep for pickle, yaml.load, eval in secure-scan.py returns 0 hits; rules stop at 8. Serialize after TEN-SECURITY-18 |
1316
+ | TEN-SECURITY-20 | feature: secure-scan.py rule 10 flags SQL built by f-string, % formatting or concatenation passed to execute() | autonomy/lib/secure-scan.py, tests/test-secure-scan.sh | HIGH | red: bash tests/test-secure-scan.sh fails on the rule 10 fixtures; green: passes | released v11.17.53 | Gap: no execute(f"...") or concatenation shape anywhere in secure-scan.py. Serialize after TEN-SECURITY-19 |
1317
+ | TEN-SECURITY-21 | fix: safe_git driverKeys and netCommandOverrides run git config with no timeout, so a hung git blocks the safe-git guard; add a timeout that still fails closed | loki-ts/src/util/safe_git.ts, loki-ts/tests/util/fc25_safe_git.test.ts | HIGH | red: cd loki-ts && bun test tests/util/fc25_safe_git.test.ts -t "hung git config" fails; green: passes | released v11.17.53 | Gap: safe_git.ts:63 and :95 spawnSync("git", ... config ...) without timeout; both already throw on r.error so a timeout error fails closed |
1318
+ | TEN-GATES-30 | fix: a negative LOKI_MUTATION_PROOF_TIMEOUT_S passes the || 30 fallback and makes the mutation proof deadline already past, so the verifier gate fails every run; accept only positive finite seconds | loki-ts/src/util/mutation_proof.ts, loki-ts/tests/engine10/mutation_proof.test.ts | released v11.17.53 | red: cd loki-ts && bun test tests/engine10/mutation_proof.test.ts -t "negative timeout" fails; green: passes | ready@2026-10-17T12:00Z | Gap: mutation_proof.ts:36 Number(... ?? 30) || 30 keeps negatives |
1319
+ | TEN-STABILITY-49 | fix: a negative LOKI_E10_NOTIFY_TIMEOUT_MS makes the Slack notify race resolve at once and drops the event; accept only positive values | loki-ts/src/util/slack_events.ts, loki-ts/tests/engine10/slack_events.test.ts | LOW | red: cd loki-ts && bun test tests/engine10/slack_events.test.ts -t "negative notify timeout" fails; green: passes | released v11.17.53 | Gap: slack_events.ts:27 Number(env.LOKI_E10_NOTIFY_TIMEOUT_MS) || 5000 |
1320
+ | TEN-STABILITY-50 | fix: the PR stage runs the push and pr-ready scripts with spawnSync and no timeout, so one hung push blocks the run; add a bounded timeout surfaced as the stage failure | loki-ts/src/engine10/stages/pr.ts, loki-ts/tests/engine10/pr.test.ts | MEDIUM | red: cd loki-ts && bun test tests/engine10/pr.test.ts -t "hung push script" fails; green: passes | released v11.17.53 | Gap: pr.ts:68, :76, :80, :129 spawnSync("bash", [...]) without timeout; script path injectable via scriptPath |
1321
+ | TEN-STABILITY-51 | fix: the runner push-pr spawn has no timeout while the check-origin spawn has 30s; a hung gh push stalls the attempt | loki-ts/src/runner/attempts.ts, loki-ts/tests/runner/attempts-push-pr.test.ts | MEDIUM | red: cd loki-ts && bun test tests/runner/attempts-push-pr.test.ts -t "hung push" fails; green: passes | released v11.17.53 | Gap: attempts.ts:376 spawnSync without timeout vs attempts.ts:292 timeout 30_000 |
1322
+ | TEN-STABILITY-52 | fix: recordFailures reads the failures file then rewrites existing + lines, so two concurrent runs lose lines; append atomically instead | loki-ts/src/util/failure_memory.ts, loki-ts/tests/e10ext/repomemory.test.ts | MEDIUM | red: cd loki-ts && bun test tests/e10ext/repomemory.test.ts -t "concurrent recordFailures" fails; green: passes | released v11.17.53 | Gap: failure_memory.ts:47 writeFileSync(failuresPath(dir), existing + lines); line 115 already uses temp file plus rename for another file |
1323
+ | TEN-STABILITY-53 | fix: pr_lessons push spawnSync has no timeout, so a hung push blocks pr respond forever; add a bounded timeout | loki-ts/src/util/pr_lessons.ts, loki-ts/tests/util/pr_lessons.test.ts | LOW | red: cd loki-ts && bun test tests/util/pr_lessons.test.ts -t "hung push" fails; green: passes | released v11.17.53 | Gap: pr_lessons.ts:348 spawnSync without timeout (LOKI_PR_RESPOND_MAX at :370 is already guarded at :386, not a gap) |
1324
+ | TEN-STABILITY-54 | fix: issues run shells out to gh with spawnSync and no timeout, so one hung gh call stalls the whole issue batch; add a bounded timeout returned as a nonzero rc | loki-ts/src/commands/issues_run.ts, loki-ts/tests/commands/issues_run.test.ts | MEDIUM | red: cd loki-ts && bun test tests/commands/issues_run.test.ts -t "hung gh" fails; green: passes | released v11.17.53 | Gap: issues_run.ts:533 spawnSync("gh", ...) without timeout |
1325
+ | TEN-STABILITY-55 | enhancement: verify pr gh helper uses execFileSync with no timeout; add a bounded timeout so a stalled gh yields the existing fetch error | loki-ts/src/commands/verify_pr.ts, loki-ts/tests/commands/verify_pr.test.ts | LOW | red: cd loki-ts && bun test tests/commands/verify_pr.test.ts -t "gh timeout" fails; green: passes | released v11.17.53 | Gap: verify_pr.ts:57 execFileSync("gh", args, {...}) without timeout |
1326
+ | TEN-UX-40 | enhancement: loki control with a mistyped subcommand prints "Did you mean" using suggestWord, like crash and wiki do | loki-ts/src/commands/control.ts, loki-ts/tests/commands/control.test.ts | LOW | red: cd loki-ts && bun test tests/commands/control.test.ts -t "did you mean" fails; green: passes | released v11.17.53 | Gap: control.ts:248-250 default case prints unknown command plus HELP only |
1327
+ | TEN-UX-41 | enhancement: loki queue with an unknown subcommand names the bad word and suggests the closest one before the usage | loki-ts/src/commands/queue.ts, loki-ts/tests/commands/queue.test.ts | LOW | red: cd loki-ts && bun test tests/commands/queue.test.ts -t "unknown subcommand hint" fails; green: passes | released v11.17.53 | Gap: queue.ts:529-531 default case prints QUEUE_USAGE without the offending word. Chain UX-41, UX-44 |
1328
+ | TEN-UX-42 | enhancement: loki undo unknown flag suggests the closest known flag | loki-ts/src/commands/undo.ts, loki-ts/tests/commands/undo.test.ts | LOW | red: cd loki-ts && bun test tests/commands/undo.test.ts -t "flag hint" fails; green: passes | released v11.17.53 | Gap: undo.ts:221 err("unknown flag X (see loki undo --help)") with no suggestion although known set is at :219 |
1329
+ | TEN-UX-43 | enhancement: loki memory unknown flag suggests the closest allowed flag | loki-ts/src/commands/memory.ts, loki-ts/tests/commands/memory.test.ts | LOW | red: cd loki-ts && bun test tests/commands/memory.test.ts -t "flag hint" fails; green: passes | released v11.17.53 | Gap: memory.ts:112 unknownFlag writes the error without using the allowed list for a suggestion |
1330
+ | TEN-UX-44 | enhancement: loki queue run unknown argument suggests the closest valid argument | loki-ts/src/commands/queue.ts, loki-ts/tests/commands/queue.test.ts | LOW | red: cd loki-ts && bun test tests/commands/queue.test.ts -t "run arg hint" fails; green: passes | released v11.17.53 | Gap: queue.ts:284 d.err(unknown argument) with no suggestion. Serialize after TEN-UX-41 |
1331
+ | TEN-ADOPTION-28 | feature: registry lists crash subcommands list, show, submit, help so shell completion offers them | loki-ts/src/cli/registry.ts, docs/v10/CLI-MODERN.md, loki-ts/tests/cli/registry_guard.test.ts | LOW | red: cd loki-ts && bun test tests/cli/registry_guard.test.ts -t "crash subcommands" fails; green: passes after bun loki-ts/scripts/gen-cli-modern-doc.ts | released v11.17.53 | Gap: registry.ts:170 crash has no subcommands; crash.ts:258 CRASH_SUBCOMMANDS. Chain ADOPTION-28 to -33 (same files) |
1332
+ | TEN-ADOPTION-29 | feature: registry rollback lists the deploy subcommand and the list --json flag | loki-ts/src/cli/registry.ts, docs/v10/CLI-MODERN.md, loki-ts/tests/cli/registry_guard.test.ts | LOW | red: cd loki-ts && bun test tests/cli/registry_guard.test.ts -t "rollback deploy" fails; green: passes | released v11.17.53 | Gap: registry.ts:118-125 rollback has list, show, to, latest only; rollback.ts:33 documents list [--json]. Serialize after TEN-ADOPTION-28 |
1333
+ | TEN-ADOPTION-30 | feature: registry control status lists the --json flag | loki-ts/src/cli/registry.ts, docs/v10/CLI-MODERN.md, loki-ts/tests/cli/registry_guard.test.ts | LOW | red: cd loki-ts && bun test tests/cli/registry_guard.test.ts -t "control status json" fails; green: passes | released v11.17.53 | Gap: registry.ts:147-153 status has no flags; control.ts:25 and :226 accept status --json. Serialize after TEN-ADOPTION-29 |
1334
+ | TEN-ADOPTION-31 | feature: registry trust lists the --json flag | loki-ts/src/cli/registry.ts, docs/v10/CLI-MODERN.md, loki-ts/tests/cli/registry_guard.test.ts | LOW | red: cd loki-ts && bun test tests/cli/registry_guard.test.ts -t "trust json" fails; green: passes | released v11.17.53 | Gap: registry.ts:169 trust has only detail; trust.ts:106 handles --json. Serialize after TEN-ADOPTION-30 |
1335
+ | TEN-ADOPTION-32 | feature: registry undo lists the --list and --dry-run flags | loki-ts/src/cli/registry.ts, docs/v10/CLI-MODERN.md, loki-ts/tests/cli/registry_guard.test.ts | LOW | red: cd loki-ts && bun test tests/cli/registry_guard.test.ts -t "undo flags" fails; green: passes | released v11.17.53 | Gap: registry.ts:182 undo flags omit --list and --dry-run; undo.ts:219 known set includes both. Serialize after TEN-ADOPTION-31 |
1336
+ | TEN-ADOPTION-33 | feature: registry memory list and memory lessons list the --json flag | loki-ts/src/cli/registry.ts, docs/v10/CLI-MODERN.md, loki-ts/tests/cli/registry_guard.test.ts | LOW | red: cd loki-ts && bun test tests/cli/registry_guard.test.ts -t "memory json" fails; green: passes | released v11.17.53 | Gap: registry.ts:104-117 list and lessons have no flags; memory.ts:126 and :155 accept --json. Serialize after TEN-ADOPTION-32 |
1337
+ | TEN-DEPLOY-24 | fix: rollback deploy hint matches only the first token, so flyctl deploy, npx vercel --prod and bunx wrangler get no rollback command; skip npx, bunx, pnpm dlx, yarn dlx wrappers and alias flyctl to fly | loki-ts/src/commands/rollback.ts, loki-ts/tests/commands/rollback.test.ts | LOW | red: cd loki-ts && bun test tests/commands/rollback.test.ts -t "wrapped deploy" fails; green: passes | released v11.17.53 | Gap: rollback.ts printDeployRollback const first = command.split(/\s+/)[0] then DEPLOY_ROLLBACKS.find(r => r.prefix === first). Chain DEPLOY-24, DEPLOY-25 |
1338
+ | TEN-DEPLOY-25 | feature: loki rollback deploy accepts --json and prints the matched rollback command as a JSON object | loki-ts/src/commands/rollback.ts, loki-ts/tests/commands/rollback.test.ts | LOW | red: cd loki-ts && bun test tests/commands/rollback.test.ts -t "deploy json" fails; green: passes | released v11.17.53 | Gap: rollback.ts:65 allowed flags are [] for deploy. Serialize after TEN-DEPLOY-24 |
1339
+ | TEN-SPEED-17 | feature: engine10 intake reuses the tree-keyed repomap and testmap cache (cachedRepoMap and cachedTestMap) instead of rebuilding both on every run, so a second run on an unchanged tree skips the repo walk and test detection | loki-ts/src/engine10/stages/intake.ts, loki-ts/tests/engine10/intake.test.ts | MEDIUM | red: cd loki-ts && bun test tests/engine10/intake.test.ts -t "tree cache" fails; green: passes | ready@2026-10-17T12:00Z | Gap: cache.ts:66-67 defines cachedRepoMap and cachedTestMap but no src caller exists outside cache.ts; intake.ts:93-95 calls buildRepoMap and ctx.tests.detect every run; sizing.ts:40 and context.ts:46 read repomap2-<tree>.json that nothing writes |
1340
+ | TEN-SPEED-18 | feature: verify runs the selected test files with bounded concurrency (LOKI_E10_VERIFY_JOBS, default 1 so behavior is unchanged) and records checks in the original failed-first order; protect, cwd and interpreter handling stay per test | loki-ts/src/engine10/stages/verify.ts, loki-ts/tests/engine10/verify.test.ts | HIGH | red: cd loki-ts && bun test tests/engine10/verify.test.ts -t "verify jobs" fails; green: passes | ready@2026-10-17T12:00Z | Gap: verify.ts:284 `for (const t of tests) { await runCheck(...) }` runs one test process at a time; no jobs knob exists. Serialize after any open verify.ts row |
1341
+ | TEN-SPEED-19 | feature: the Wall base-tree test run executes wall test files with bounded concurrency (LOKI_E10_BASE_JOBS, default 1) with the same pass/fail/not_run counts and lastNotRunFiles order | loki-ts/src/engine10/stages/wall.ts, loki-ts/tests/engine10/wall_runner.test.ts | HIGH | red: cd loki-ts && bun test tests/engine10/wall_runner.test.ts -t "base jobs" fails; green: passes | ready@2026-10-17T12:00Z | Gap: wall.ts:39 `for (const f of files)` with a synchronous spawnSync per file in RealBaseTestRunner.run, one process at a time |
1342
+ | TEN-SPEED-20 | feature: a group suite-fix unit reuses the failing-suite output integrate already captured instead of re-running the whole suite (up to 600s) just to build the fix brief | loki-ts/src/features/speed/fix_units.ts, loki-ts/src/engine10/integrate.ts, loki-ts/tests/features/speed/fix_units.test.ts | MEDIUM | red: cd loki-ts && bun test tests/features/speed/fix_units.test.ts -t "suite fix reuses output" fails; green: passes | ready@2026-10-17T12:00Z | Gap: fix_units.ts:41 suiteTail does spawnSync of the full test command (timeout 600000) after integrate already ran it; integrate.ts:22 IntegrateResult has no output field. Chain TEN-QUALITY-36, TEN-SPEED-20 (same test file); serialize after TEN-QUALITY-36 |
1343
+ | TEN-UX-45 | feature: loki start --dry-run parses and validates every flag, runs the preflight and prints the provider, model and cost cap it would use, then exits 0 without spending a token | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | MEDIUM | red: cd loki-ts && bun test tests/commands/start.test.ts -t "dry-run" fails; green: passes | ready@2026-10-17T12:00Z | Gap: grep -n "dry-run" loki-ts/src/commands/start.ts returns nothing, so --dry-run is an unknown flag today (start.ts:229 error); a first-run user cannot check setup without a paid run. Chain TEN-UX-48, TEN-UX-50, TEN-DEPLOY-26, TEN-UX-47, TEN-UX-46, TEN-UX-45 (same files); serialize after TEN-UX-46 |
1344
+ | TEN-UX-46 | feature: loki start unknown-flag error suggests the closest valid flag (suggestWord) and stops naming LOKI_SDK_LOOP internals to first-run users | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | LOW | red: cd loki-ts && bun test tests/commands/start.test.ts -t "unknown flag suggestion" fails; green: passes | ready@2026-10-17T12:00Z | Gap: start.ts:229 prints "flag --bogus is not supported by the Bun (LOKI_SDK_LOOP) runner ... run without LOKI_SDK_LOOP" (reproduced with parseStartArgs(["x","--bogus"])); cli/registry.ts:346 exports suggestWord and start does not use it. Serialize after TEN-UX-47 |
1345
+ | TEN-COST-54 | feature: LOKI_PRICE_TABLE=<json file> overrides or extends PRICE_TABLE entries so a stale vendor price is fixable without a release; invalid file falls back to the built-in table | loki-ts/src/providers/price_table.ts, loki-ts/tests/providers/price_table.test.ts (new: no test file owns price_table.ts, grep of tests for priceFor and usdFor finds none) | LOW | red: cd loki-ts && bun test tests/providers/price_table.test.ts -t "price table override" fails; green: passes | ready@2026-10-17T12:00Z | Gap: price_table.ts:7 comment says "Update as vendors publish new prices" and the table is a frozen constant (line 8) with no env override. Chain TEN-COST-56, TEN-COST-58, TEN-COST-54 (same files); serialize after TEN-COST-58 |
1346
+ | TEN-COST-55 | feature: opencode runs get a size-estimate cost record (estimated=true, cost_basis size-estimate) when the model id is priced, instead of an unmeasured cost, so the cost cap and loki cost cover all 5 providers | loki-ts/src/providers/provider_cost.ts, loki-ts/tests/engine10/budget_cap.test.ts | MEDIUM | red: cd loki-ts && bun test tests/engine10/budget_cap.test.ts -t "opencode estimate" fails; green: passes | ready@2026-10-17T12:00Z | Gap: provider_cost.ts:71 ESTIMATED_PROVIDERS is codex, cline, aider only, so buildProviderCost returns null for opencode (line 86); provider_opencode.ts:5-7 states cost is not measured |
1347
+ | TEN-QUALITY-32 | feature: impactedRefs maps a changed Python package __init__.py and Rust mod.rs to the package directory name so tests that import the package are selected | loki-ts/src/engine10/testmap.ts, loki-ts/tests/engine10/testmap.test.ts | HIGH | red: cd loki-ts && bun test tests/engine10/testmap.test.ts -t "package init maps to directory" fails; green: passes | ready@2026-10-17T12:00Z | Gap: reproduced on a repo with pkg/search/__init__.py and tests/test_search.py (from pkg.search import a): buildTestMap yields sourceRefs {search:[tests/test_search.py]} and impactedRefs(map,["pkg/search/__init__.py"]) returns []; testmap.ts:178 keys on basename of the file. Chain TEN-QUALITY-39, TEN-QUALITY-32, TEN-SPEED-22 (same files); serialize after TEN-QUALITY-39 |
1348
+ | TEN-STABILITY-56 | feature: the supervisor forwards SIGHUP (terminal closed) to the detached worker process group, the same way it forwards SIGINT and SIGTERM, so closing the terminal does not orphan a paid worker | loki-ts/src/runner/worker_proc.ts, loki-ts/tests/engine10/supervisor_signal.test.ts | MEDIUM | red: cd loki-ts && bun test tests/engine10/supervisor_signal.test.ts -t "sighup" fails; green: passes | ready@2026-10-17T12:00Z | Gap: grep -rn SIGHUP loki-ts/src returns nothing; worker_proc.ts:35-36 registers only SIGINT and SIGTERM and spawns the worker detached (line 17) so a SIGHUP kills the supervisor and leaves the worker group running |
1349
+ | TEN-SPEED-21 | enhancement: the 30-second session heartbeat lists untracked files once and shares the list between the shortstat and the signature | loki-ts/src/engine10/session.ts, loki-ts/tests/engine10/session.test.ts | LOW | red: cd loki-ts && bun test tests/engine10/session.test.ts -t "heartbeat single ls-files" fails; green: passes | ready@2026-10-17T12:00Z | Gap: session.ts:88 (diffShortstat) and session.ts:104 (diffSignature) each run safeGit ls-files -z --others --exclude-standard on the same tick |
1350
+ | TEN-SPEED-22 | enhancement: buildTestMap reads each JS test file once (the node:test probe and the reference scan share one read) and stops probing for node:test once node is marked | loki-ts/src/engine10/testmap.ts, loki-ts/tests/engine10/testmap.test.ts | LOW | red: cd loki-ts && bun test tests/engine10/testmap.test.ts -t "single read per test file" fails; green: passes | ready@2026-10-17T12:00Z | Gap: testmap.ts:115 readText(full) for every JS test file in the first loop and testmap.ts:143 readText(join(root, t.path)) again in the tests loop. Serialize after TEN-QUALITY-32 |
1351
+ | TEN-SPEED-23 | enhancement: repomap topLevelSymbols reads only the first MAX_SCAN_BYTES bytes of each file instead of the whole file | loki-ts/src/engine10/repomap.ts, loki-ts/tests/engine10/repomap.test.ts | LOW | red: cd loki-ts && bun test tests/engine10/repomap.test.ts -t "bounded read" fails; green: passes | ready@2026-10-17T12:00Z | Gap: repomap.ts:44 `readFileSync(absPath, "utf8").slice(0, MAX_SCAN_BYTES)` loads the full file (and decodes it) before slicing |
1352
+ | TEN-QUALITY-33 | enhancement: enable noImplicitReturns in loki-ts/tsconfig.json and fix the one violation | loki-ts/tsconfig.json, loki-ts/src/contrib/slack_inbound.ts | LOW | red: cd loki-ts && bun run --bun tsc --noEmit --noImplicitReturns fails (exit non-zero); green: cd loki-ts && bun run typecheck && bun test tests/features/slack_inbound.test.ts passes | ready@2026-10-17T12:00Z | Gap: tsc --noImplicitReturns reports exactly 1 error, slack_inbound.ts(217,10) TS7030 in the slackPoster async lambda; tsconfig.json has strict and noUncheckedIndexedAccess (line 9) but not noImplicitReturns. Chain TEN-QUALITY-33, TEN-QUALITY-34 (same file) |
1353
+ | TEN-QUALITY-34 | enhancement: handleSlackEvent takes payload as unknown and narrows it, removing the any | loki-ts/src/contrib/slack_inbound.ts, loki-ts/tests/features/slack_inbound.test.ts | LOW | red: cd loki-ts && bun test tests/features/slack_inbound.test.ts -t "malformed payload" fails; green: passes | ready@2026-10-17T12:00Z | Gap: slack_inbound.ts:100 `payload: any`. Serialize after TEN-QUALITY-33 |
1354
+ | TEN-QUALITY-35 | enhancement: add optional stderrTail to SessionResult and drop the double-cast at both call sites | loki-ts/src/engine10/types.ts, loki-ts/src/engine10/stages/implement.ts, loki-ts/src/engine10/stages/plan.ts | LOW | red: cd loki-ts && grep -c "as unknown as { stderrTail" src/engine10/stages/implement.ts src/engine10/stages/plan.ts prints non-zero counts; green: both counts are 0 and cd loki-ts && bun run typecheck && bun test tests/engine10/implement.test.ts tests/engine10/plan.test.ts passes | ready@2026-10-17T12:00Z | Gap: implement.ts:180 and plan.ts:101 cast `session as unknown as { stderrTail?: string }`; types.ts:98 SessionResult lacks the field that session.ts:176 returns |
1355
+ | TEN-UX-47 | enhancement: loki start unknown --provider error lists the valid providers, as loki estimate already does | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | LOW | red: cd loki-ts && bun test tests/commands/start.test.ts -t "unknown provider lists valid" fails; green: passes | ready@2026-10-17T12:00Z | Gap: start.ts:292 prints only "unknown --provider 'gemini'"; cost_preview.ts:144 exports VALID_PROVIDERS and cost_preview.ts:161 lists them. Serialize after TEN-DEPLOY-26 |
1356
+ | TEN-QUALITY-36 | enhancement: characterization tests for fix_units effectiveDag, integrateWithFixes and fixEnabled (conflict fix, suite fix, MAX_FIX_UNITS cap, LOKI_GROUP_FIX_UNITS=0) | loki-ts/tests/features/speed/fix_units.test.ts (new: no test file imports fix_units.ts) | MEDIUM | red: cd loki-ts && test -f tests/features/speed/fix_units.test.ts fails; green: bun test tests/features/speed/fix_units.test.ts passes | ready@2026-10-17T12:00Z | Gap: fix_units.ts has no direct test; only the LOKI_GROUP_FIX_UNITS name appears in seal_group.test.ts. Chain TEN-QUALITY-36, TEN-SPEED-20 |
1357
+ | TEN-QUALITY-37 | enhancement: unit tests for compound_match linkedHits (compound keyword, suffix word rejected, vendored path skipped, import line required) | loki-ts/tests/e10ext/compound_match.test.ts (new: no test file imports compound_match.ts) | LOW | red: cd loki-ts && test -f tests/e10ext/compound_match.test.ts fails; green: bun test tests/e10ext/compound_match.test.ts passes | ready@2026-10-17T12:00Z | Gap: compound_match.ts:45 linkedHits is covered only indirectly through already_done tests |
1358
+ | TEN-QUALITY-38 | enhancement: unit tests for buildOpencodeArgv (default cli, LOKI_OPENCODE_CLI, LOKI_OPENCODE_MODEL, LOKI_OPENCODE_FLAGS whitespace split, commit hygiene prefix) | loki-ts/tests/runner/provider_opencode.test.ts (new: no test file imports provider_opencode.ts) | LOW | red: cd loki-ts && test -f tests/runner/provider_opencode.test.ts fails; green: bun test tests/runner/provider_opencode.test.ts passes | ready@2026-10-17T12:00Z | Gap: provider_opencode.ts:25 buildOpencodeArgv is documented "unit-testable without spawning" yet grep of loki-ts/tests and tests/ finds no reference |
1359
+ | TEN-QUALITY-39 | fix: impactedRefs returns no tests for a changed index.ts/index.js because the source is keyed as "index" while tests import the directory name | loki-ts/src/engine10/testmap.ts, loki-ts/tests/engine10/testmap.test.ts | HIGH | red: cd loki-ts && bun test tests/engine10/testmap.test.ts -t "index source maps to directory" fails; green: passes | ready@2026-10-17T12:00Z | Gap: reproduced on a repo with src/search/index.ts and tests/search.test.ts (import from "../src/search"): buildTestMap finds the bun runner and the test, impactedRefs(map,["src/search/index.ts"]) returns []; testmap.ts:178 uses basename(rel, extname(rel)) = "index", so the verifier under-selects tests. Chain TEN-QUALITY-39, TEN-QUALITY-32, TEN-SPEED-22 (same files) |
1360
+ | TEN-COST-56 | fix: usdFor returns NaN for non-finite or negative tokens and bills cached tokens in full when cached exceeds input; clamp to finite non-negative and cap cached at input | loki-ts/src/providers/price_table.ts, loki-ts/tests/providers/price_table.test.ts (new: see TEN-COST-54) | MEDIUM | red: cd loki-ts && bun test tests/providers/price_table.test.ts -t "usdFor clamps" fails; green: passes | ready@2026-10-17T12:00Z | Gap: reproduced usdFor("gpt-5",NaN,10) = NaN and usdFor("gpt-5",100,0,500) = 0.000063 (500 cached tokens billed against 100 input); price_table.ts:40-45; provider_cost.ts:94 feeds it. Chain TEN-COST-56, TEN-COST-58, TEN-COST-54 (same files) |
1361
+ | TEN-COST-57 | fix: loki estimate --model followed by another flag swallows that flag as the model id, and --model= (empty) is accepted; require a non-empty value that does not start with a dash | loki-ts/src/runner/router/cost_preview.ts, loki-ts/tests/runner/cost_preview.test.ts | LOW | red: cd loki-ts && bun test tests/runner/cost_preview.test.ts -t "model needs a value" fails; green: passes | ready@2026-10-17T12:00Z | Gap: reproduced runEstimate(["--provider","codex","--model","--json"]) returns 0 and prints text (--json consumed as the model); runEstimate(["--provider","codex","--model="]) returns 0; cost_preview.ts:155 `args[++i]` only rejects an absent value, line 157 has no empty check |
1362
+ | TEN-COST-58 | fix: PRICE_TABLE prices gpt-4o-mini, gpt-4.1-mini, gpt-4.1-nano, gpt-5-mini and gpt-5-nano at the full gpt-4o, gpt-4.1 and gpt-5 rates, overstating cost and tripping the cost cap early; add their own entries from the vendor price page (cite the page in a comment) | loki-ts/src/providers/price_table.ts, loki-ts/tests/providers/price_table.test.ts (new: see TEN-COST-54) | LOW | red: cd loki-ts && bun test tests/providers/price_table.test.ts -t "mini and nano priced separately" fails; green: passes | ready@2026-10-17T12:00Z | Gap: priceFor uses longest-substring match (price_table.ts:28-32) and the table (lines 11-13) has no mini or nano keys, so "gpt-5-mini" resolves to the "gpt-5" entry. Chain TEN-COST-56, TEN-COST-58, TEN-COST-54; serialize after TEN-COST-56 |
1363
+ | TEN-UX-48 | fix: loki start --provider, --session-model, --cost and --spec with a missing or empty value are silently ignored and the run starts with defaults; fail with "needs a value" like the text flags | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | LOW | red: cd loki-ts && bun test tests/commands/start.test.ts -t "value flags need a value" fails; green: passes | ready@2026-10-17T12:00Z | Gap: reproduced parseStartArgs(["x","--provider"]), ["x","--session-model"], ["x","--cost"], ["x","--spec"] all return {prdPath:"x"} with no error and ["x","--provider=","--simple"] yields provider ""; start.ts:57 TEXT_VALUE_FLAGS lists only 6 free-text flags. First in the start.ts chain |
1364
+ | TEN-UX-50 | fix: a PRD path containing a space (for example "My Docs/prd.md") that does not exist is treated as a brief and starts a paid run; treat a slash-containing token ending in a doc extension as a path even with spaces | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | MEDIUM | red: cd loki-ts && bun test tests/commands/start.test.ts -t "spaced prd path" fails; green: passes | ready@2026-10-17T12:00Z | Gap: reproduced missingPrdMessage(["My Docs/prd.md"],"My Docs/prd.md",()=>false) = null while "docs/spec.pdf" and "prd.md" give "PRD file not found"; start.ts:384 pathShaped rejects any \s. Serialize after TEN-UX-48 |
1365
+ | TEN-DEPLOY-26 | fix: loki start --health-url, --domain, --destination and --env-file given with no value pass deployFlagError silently, so the deploy step is skipped or runs without the setting; report a missing value before the paid build | loki-ts/src/commands/start.ts, loki-ts/tests/commands/start.test.ts | MEDIUM | red: cd loki-ts && bun test tests/commands/start.test.ts -t "deploy flag missing value" fails; green: passes | ready@2026-10-17T12:00Z | Gap: reproduced deployFlagError(["x","--health-url"]), ["x","--destination"], ["x","--env-file"] and ["x","--domain","--simple"] all return null; start.ts:437-447 val() returns undefined for an absent or dash-leading value and the checks only run when val is defined. Serialize after TEN-UX-50 |
1366
+ | TEN-UX-51 | fix: a first-run folder that holds only .DS_Store (macOS Finder) is refused as non-empty; ignore .DS_Store and other OS metadata files when deciding the folder is empty | loki-ts/src/util/first_run_repo.ts, loki-ts/tests/engine10/preflight.test.ts | LOW | red: cd loki-ts && bun test tests/engine10/preflight.test.ts -t "ds_store only folder" fails; green: passes | ready@2026-10-17T12:00Z | Gap: reproduced initEmptyRepo(dirWithOnly.DS_Store) returns {fatal:"not a git repository ... "}; first_run_repo.ts:12 `readdirSync(dir).length === 0` counts dotfiles |
1367
+ | TEN-STABILITY-57 | fix: appendRunOutcome is a read-modify-write, so two concurrent runs on one repo lose an outcome; serialize with a lock file or append-only records | loki-ts/src/runner/router/history_store.ts, loki-ts/tests/runner/router_history.test.ts | MEDIUM | red: cd loki-ts && bun test tests/runner/router_history.test.ts -t "concurrent append keeps all" fails; green: passes | ready@2026-10-17T12:00Z | Gap: history_store.ts:70 reads the history, appends in memory, then renames a pid-named temp file over the target (lines 73-77); the atomic rename prevents truncation but not a lost update between two processes |
1368
+ | TEN-SECURITY-22 | fix: secure-scan silently skips untracked files larger than 1 MB, so a secret in a large new file passes the gate unreported; scan them line by line up to a hard cap and list anything above the cap as an explicit skipped file | loki-ts/src/util/secure_scan.ts, loki-ts/tests/util/secure_scan.test.ts | HIGH | red: cd loki-ts && bun test tests/util/secure_scan.test.ts -t "oversized untracked file" fails; green: passes | ready@2026-10-17T12:00Z | Gap: secure_scan.ts:49 MAX_ADDED_FILE_BYTES = 1_000_000 and secure_scan.ts:237 `if (!st.isFile() \|\| st.size > MAX_ADDED_FILE_BYTES) continue;` drops the file with no finding, no error and no skipped count; grep for skipped or unscanned in the file finds nothing |
@@ -11,7 +11,7 @@ Classes: KEEP-MODERN (v10-native or engine-neutral), UPDATE (live but needs mode
11
11
  - DROP-LEGACY: 31
12
12
  - DELETE: 14
13
13
  - Total rows: 141
14
- - Registry paths (commands and nested subcommands): 204
14
+ - Registry paths (commands and nested subcommands): 209
15
15
 
16
16
  ## Commands
17
17
 
@@ -1097,3 +1097,10 @@ L0 review rule (ENGINE-LAWS.md L0): a fix that adds an `if` or a regex about the
1097
1097
  - Siblings: swept 24 bash commands with `<cmd> frobnicate`; only config and api (fixed here) returned 0, plus `loki voice`, a stub with no subcommands that prints a planned-feature notice (left as is).
1098
1098
  - Mechanism: explicit help|--help|-h arm, default arm prints `loki <cmd>: unknown subcommand` to stderr and returns 2.
1099
1099
  - Fixture: tests/test-help-discoverability.sh; restoring the old default arm turns the frobnicate assertions red.
1100
+
1101
+ ## FC-TEN-STABILITY-50 A credentialed push/pr-ready child is spawned with spawnSync and no timeout, so one hung script blocks the run (UNBOUNDED-PUSH-CHILD)
1102
+ - User-visible vs raw: user-visible. A hung engine10-push.sh froze the PR stage with no failure surfaced.
1103
+ - Law broken: every child process is bounded and a timeout is a named stage failure.
1104
+ - Sibling sweep: pr.ts push-pr, push-mr, pr-ready and status now share spawnBounded (LOKI_PR_PUSH_TIMEOUT_MS, default 50s). Still unbounded: src/util/pr_lessons.ts:348, src/runner/attempts.ts:376, src/engine10/supervisor.ts:374.
1105
+ - One shared mechanism: spawnBounded and failReason in loki-ts/src/engine10/stages/pr.ts.
1106
+ - Regression fixture: loki-ts/tests/engine10/pr.test.ts "hung push script".
@@ -2533,3 +2533,9 @@ v11.17.21 published (Release success on 462fbc40a; npm latest 11.17.21, next 11.
2533
2533
 
2534
2534
  ## 2026-10-17T13:29Z (CoS) v11.17.51
2535
2535
  - P0 fix-forward for the wave AO reds (doctor spawn env, engine10 budget, deep_wiring, workspace e2e, sigpipe, DEPS) released; evidence: targeted bun 570 pass 0 fail, four shell suites rc=0, tsc clean.
2536
+
2537
+ ## 2026-10-17T13:34Z (CoS) v11.17.52
2538
+ - TEN-COST-49 and TEN-COST-50 released; evidence: test_cost_claim.py 37 passed, reviewer mutations red then restored.
2539
+
2540
+ ## 2026-10-17T13:56Z (CoS) v11.17.53
2541
+ - Wave AP released (30 rows, 19 chains, each reviewer APPROVE by SHA); evidence in ~/loki-ci-logs/ap-check.log (tsc, bun test, secure-scan, drift guards, cost_claim pytest).