loki-mode 11.17.28 → 11.17.30

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 (71) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/ablation.py +438 -0
  4. package/dashboard/__init__.py +1 -1
  5. package/docs/CLI-REFERENCE.md +3 -2
  6. package/docs/INSTALLATION.md +1 -1
  7. package/docs/v10/BOARD.md +7 -7
  8. package/docs/v10/CLI-MODERN.md +1 -1
  9. package/docs/v10/PROGRESS.md +6 -0
  10. package/loki-ts/dist/loki.js +916 -909
  11. package/mcp/__init__.py +1 -1
  12. package/package.json +2 -2
  13. package/packages/control-plane/dist/server.js +4 -3
  14. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  15. package/web-app/dist/assets/{AdminPage-CVL2iS0A.js → AdminPage-CBKCMJ-2.js} +1 -1
  16. package/web-app/dist/assets/{Avatar-D2v6R8Pa.js → Avatar-B65cFYS3.js} +1 -1
  17. package/web-app/dist/assets/{Badge-Dml-mw_3.js → Badge-DiuwLu4S.js} +1 -1
  18. package/web-app/dist/assets/{Button-C5LDE6K3.js → Button-C1EJ7poF.js} +1 -1
  19. package/web-app/dist/assets/{CockpitPage-vRyDaxcA.js → CockpitPage-CdjLO6cq.js} +1 -1
  20. package/web-app/dist/assets/{ComparePage-DYuyWSI9.js → ComparePage-CwgYe8Nj.js} +1 -1
  21. package/web-app/dist/assets/{ErrorBoundary-C3VvRg7q.js → ErrorBoundary-CdQM-R14.js} +1 -1
  22. package/web-app/dist/assets/{EvidenceReceiptPanel-902knSfv.js → EvidenceReceiptPanel-D6L3pwV1.js} +1 -1
  23. package/web-app/dist/assets/{GitHubIssuesPanel-CRNkNcmk.js → GitHubIssuesPanel-CkvOlZB2.js} +1 -1
  24. package/web-app/dist/assets/{GitHubPRsPanel-q4gx82lS.js → GitHubPRsPanel-Db007bAr.js} +1 -1
  25. package/web-app/dist/assets/{HomePage-Cv7pbnhd.js → HomePage-W7WpULKj.js} +2 -2
  26. package/web-app/dist/assets/{LoginPage-Dh6NB3jf.js → LoginPage-DmboVMYM.js} +1 -1
  27. package/web-app/dist/assets/{MagicPage-BM6Bcci-.js → MagicPage-B6sgjjBa.js} +1 -1
  28. package/web-app/dist/assets/{MetricsPage-fZlWYNF3.js → MetricsPage-CzQumbrt.js} +1 -1
  29. package/web-app/dist/assets/{NotFoundPage-B2WYNJuo.js → NotFoundPage-DGmJyj9m.js} +1 -1
  30. package/web-app/dist/assets/{ProjectPage-BPzxFIOe.js → ProjectPage-CRiTKeon.js} +3 -3
  31. package/web-app/dist/assets/{ProjectsPage-B9ds4_6v.js → ProjectsPage-I7P_4YXW.js} +1 -1
  32. package/web-app/dist/assets/{SettingsPage-BVhRp_5V.js → SettingsPage-OJTDIwFB.js} +1 -1
  33. package/web-app/dist/assets/{ShowcasePage-DdgdARlL.js → ShowcasePage-DwLsu334.js} +1 -1
  34. package/web-app/dist/assets/{SystemSettingsPage-CE2X9jf3.js → SystemSettingsPage-C1LGiuqX.js} +1 -1
  35. package/web-app/dist/assets/{TeamsPage-CoXQ5sW8.js → TeamsPage-CYqH0irC.js} +1 -1
  36. package/web-app/dist/assets/{TemplatesPage-BMdF_-r1.js → TemplatesPage--WYe86LY.js} +1 -1
  37. package/web-app/dist/assets/{TerminalOutput-BjJ3eauc.js → TerminalOutput-CLiOedJp.js} +1 -1
  38. package/web-app/dist/assets/{activity-BNhuXaIH.js → activity-CFC-ctQL.js} +1 -1
  39. package/web-app/dist/assets/{bell-Y2p0uWz8.js → bell-CnNpGwSA.js} +1 -1
  40. package/web-app/dist/assets/{bot-D_24DrNI.js → bot-DFJ9RObS.js} +1 -1
  41. package/web-app/dist/assets/{check-YZVX7kq8.js → check-BjvDPaC9.js} +1 -1
  42. package/web-app/dist/assets/{chevron-left-DRMLmqUz.js → chevron-left-B-_ebw9F.js} +1 -1
  43. package/web-app/dist/assets/{circle-alert-CDLIuEey.js → circle-alert-CWvHGYkt.js} +1 -1
  44. package/web-app/dist/assets/{clock-CERWGH9H.js → clock-Cw1OK-HJ.js} +1 -1
  45. package/web-app/dist/assets/{cloud-DXbVQPWO.js → cloud-IFGzBKzd.js} +1 -1
  46. package/web-app/dist/assets/{code-xml-B3Gvchrt.js → code-xml-BF3PnSrO.js} +1 -1
  47. package/web-app/dist/assets/{database-B5OKN-TT.js → database-iDfV498J.js} +1 -1
  48. package/web-app/dist/assets/{dollar-sign-C2eKvfOT.js → dollar-sign-DpiWQtY0.js} +1 -1
  49. package/web-app/dist/assets/{file-code-corner-DGKU_c3D.js → file-code-corner-D-UadrrJ.js} +1 -1
  50. package/web-app/dist/assets/{file-plus-DkD31_E5.js → file-plus-D8q3mlmz.js} +1 -1
  51. package/web-app/dist/assets/{globe-CyC41Z_-.js → globe-DwB02QjX.js} +1 -1
  52. package/web-app/dist/assets/{hammer-C7FT_3yF.js → hammer-DYDZAmJV.js} +1 -1
  53. package/web-app/dist/assets/{index-BpbEH56b.js → index-DjHDmF_N.js} +3 -3
  54. package/web-app/dist/assets/{layers-D-3Cwpw6.js → layers-DUxGu3Bv.js} +1 -1
  55. package/web-app/dist/assets/{loader-circle-DgNtuzb9.js → loader-circle-D8_Tdij_.js} +1 -1
  56. package/web-app/dist/assets/{lock-D4JH8mi6.js → lock-BevPLkc4.js} +1 -1
  57. package/web-app/dist/assets/{package-t_M9BH8g.js → package-YjgVz0eV.js} +1 -1
  58. package/web-app/dist/assets/{plus-Obkd-9BS.js → plus-D4zF8lZm.js} +1 -1
  59. package/web-app/dist/assets/{refresh-cw-hPt3gjaj.js → refresh-cw-CXqHdxkw.js} +1 -1
  60. package/web-app/dist/assets/{rotate-ccw-Bxx5xmbg.js → rotate-ccw-Dmuj5fqu.js} +1 -1
  61. package/web-app/dist/assets/{scroll-text-BMg_UC4V.js → scroll-text-CNEg9HU5.js} +1 -1
  62. package/web-app/dist/assets/{server-CEI_O0dC.js → server-CYYuICX6.js} +1 -1
  63. package/web-app/dist/assets/{shield-alert-BgUNjSfh.js → shield-alert-Da0l7DN_.js} +1 -1
  64. package/web-app/dist/assets/{thumbs-up-Ce8U9-4o.js → thumbs-up-DsnJANDu.js} +1 -1
  65. package/web-app/dist/assets/{trash-2-CyHGdwm6.js → trash-2-DD_THDop.js} +1 -1
  66. package/web-app/dist/assets/{trending-down-CqoosHU1.js → trending-down-DsgZ3uI3.js} +1 -1
  67. package/web-app/dist/assets/{trending-up-PbI-apLz.js → trending-up-p6BGS23y.js} +1 -1
  68. package/web-app/dist/assets/{upload-BuHrZkxB.js → upload-CCApDI0Q.js} +1 -1
  69. package/web-app/dist/assets/{usePolling-Kohcnabw.js → usePolling-BmbBkpml.js} +1 -1
  70. package/web-app/dist/assets/{user-XgMAd6rY.js → user-C5KK2E-I.js} +1 -1
  71. 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.28
6
+ # Loki Mode v11.17.30
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.28 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
486
+ **v11.17.30 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 11.17.28
1
+ 11.17.30
@@ -0,0 +1,438 @@
1
+ #!/usr/bin/env python3
2
+ """Load-bearing ablation producer (moat P8, S-113).
3
+
4
+ Answers one question for the proof: do the recorded acceptance checks actually
5
+ exercise the change? Every changed or added code unit in a non-test source file
6
+ is replaced with a no-op, the recorded check command is re-run, and the working
7
+ tree is restored byte-for-byte (content, mode and mtime).
8
+
9
+ python3 autonomy/lib/ablation.py --repo <dir> --base <sha> --loki-dir <dir>/.loki
10
+
11
+ Reads <loki-dir>/quality/test-results.json ("command", "exit_code").
12
+ Writes <loki-dir>/quality/ablation.json:
13
+ {"status": "load_bearing" | "not_load_bearing" | "not_applicable",
14
+ "reason": "<non-empty text>",
15
+ "command": "<command re-run>",
16
+ "ablated_files": ["<path>", ...],
17
+ "ablated_exit_code": <int or null>}
18
+
19
+ The consumer is proof-generator.py (_collect_ablation copies the record into
20
+ facts.ablation; _compute_headline refuses VERIFIED on not_load_bearing).
21
+
22
+ Deterministic, no network, no model call. Exit 0 whenever a status was
23
+ recorded; exit 2 on bad arguments or when the record cannot be written.
24
+
25
+ A code unit is a Python function or method (ast). A unit is changed when a
26
+ changed line falls in its own lines (lines of nested functions count for the
27
+ nested unit only). Changed code in other languages records not_applicable with
28
+ the reason naming the files, never a guessed verdict.
29
+ """
30
+
31
+ import argparse
32
+ import ast
33
+ import fnmatch
34
+ import json
35
+ import os
36
+ import re
37
+ import shlex
38
+ import signal
39
+ import subprocess
40
+ import sys
41
+
42
+ STATUS_LOAD_BEARING = "load_bearing"
43
+ STATUS_NOT_LOAD_BEARING = "not_load_bearing"
44
+ STATUS_NOT_APPLICABLE = "not_applicable"
45
+
46
+ # Extensions treated as source code. Anything else (docs, config, data) is not
47
+ # code, so a change touching only those is not_applicable.
48
+ CODE_EXTENSIONS = {
49
+ ".py", ".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".go", ".rs", ".java",
50
+ ".kt", ".rb", ".php", ".cs", ".c", ".cc", ".cpp", ".h", ".hpp", ".swift",
51
+ ".scala", ".sh", ".bash",
52
+ }
53
+ SUPPORTED_EXTENSIONS = {".py"}
54
+
55
+ TEST_DIR_NAMES = {"test", "tests", "__tests__", "spec", "specs", "e2e"}
56
+ TEST_FILE_GLOBS = (
57
+ "test_*", "*_test.*", "*.test.*", "*.spec.*", "*_spec.*", "conftest.py",
58
+ )
59
+
60
+ DEFAULT_TIMEOUT_SEC = 600
61
+
62
+
63
+ def _git(repo, *args):
64
+ proc = subprocess.run(
65
+ ["git", "-C", repo] + list(args),
66
+ stdout=subprocess.PIPE,
67
+ stderr=subprocess.PIPE,
68
+ check=False,
69
+ )
70
+ if proc.returncode != 0:
71
+ raise RuntimeError(
72
+ "git %s failed: %s"
73
+ % (" ".join(args[:2]), proc.stderr.decode("utf-8", "replace").strip())
74
+ )
75
+ return proc.stdout.decode("utf-8", "replace")
76
+
77
+
78
+ def changed_files(repo, base):
79
+ """Paths changed since base: committed, staged, unstaged and untracked."""
80
+ tracked = _git(repo, "diff", "--name-only", "--diff-filter=AMR", base, "--")
81
+ untracked = _git(repo, "ls-files", "--others", "--exclude-standard")
82
+ out = []
83
+ for line in (tracked + "\n" + untracked).splitlines():
84
+ p = line.strip()
85
+ if not p or p in out:
86
+ continue
87
+ if p == ".loki" or p.startswith(".loki/"):
88
+ continue
89
+ out.append(p)
90
+ return out
91
+
92
+
93
+ def untracked_files(repo):
94
+ return set(
95
+ p.strip()
96
+ for p in _git(repo, "ls-files", "--others", "--exclude-standard").splitlines()
97
+ if p.strip()
98
+ )
99
+
100
+
101
+ _HUNK_RE = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@")
102
+
103
+
104
+ def changed_lines(repo, base, path, is_untracked):
105
+ """Set of 1-based line numbers in the working-tree file that are new or
106
+ changed relative to base. None means every line (an added file)."""
107
+ if is_untracked:
108
+ return None
109
+ diff = _git(repo, "diff", "-U0", "--no-color", base, "--", path)
110
+ if not diff.strip():
111
+ return set()
112
+ lines = set()
113
+ saw_hunk = False
114
+ for line in diff.splitlines():
115
+ m = _HUNK_RE.match(line)
116
+ if not m:
117
+ if line.startswith("new file mode"):
118
+ return None
119
+ continue
120
+ saw_hunk = True
121
+ start = int(m.group(1))
122
+ count = int(m.group(2)) if m.group(2) is not None else 1
123
+ if count == 0:
124
+ # Pure deletion: the line after the cut belongs to the edited unit.
125
+ lines.add(max(start, 1))
126
+ lines.add(start + 1)
127
+ else:
128
+ lines.update(range(start, start + count))
129
+ return lines if saw_hunk else set()
130
+
131
+
132
+ def command_paths(repo, command):
133
+ """Repo-relative files the check command names directly (the check
134
+ scripts themselves are never ablated)."""
135
+ try:
136
+ tokens = shlex.split(command or "")
137
+ except ValueError:
138
+ tokens = (command or "").split()
139
+ out = set()
140
+ for tok in tokens:
141
+ if not tok or tok.startswith("-"):
142
+ continue
143
+ cand = os.path.normpath(os.path.join(repo, tok))
144
+ if os.path.isfile(cand):
145
+ out.add(os.path.relpath(cand, repo))
146
+ return out
147
+
148
+
149
+ def is_test_path(path, check_paths):
150
+ norm = os.path.normpath(path)
151
+ if norm in check_paths:
152
+ return True
153
+ parts = norm.split(os.sep)
154
+ if any(p in TEST_DIR_NAMES for p in parts[:-1]):
155
+ return True
156
+ name = parts[-1]
157
+ return any(fnmatch.fnmatch(name, g) for g in TEST_FILE_GLOBS)
158
+
159
+
160
+ def _function_nodes(tree):
161
+ """(node, parent_function_or_None) for every function in the module."""
162
+ out = []
163
+
164
+ def walk(node, parent_fn):
165
+ for child in ast.iter_child_nodes(node):
166
+ if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef)):
167
+ out.append((child, parent_fn))
168
+ walk(child, child)
169
+ else:
170
+ walk(child, parent_fn)
171
+
172
+ walk(tree, None)
173
+ return out
174
+
175
+
176
+ def select_units(source, lines):
177
+ """Function nodes to no-op. lines=None selects every function."""
178
+ tree = ast.parse(source)
179
+ funcs = _function_nodes(tree)
180
+ if lines is None:
181
+ chosen = [n for n, _ in funcs]
182
+ else:
183
+ chosen = []
184
+ for node, _ in funcs:
185
+ start = min([node.lineno] + [d.lineno for d in node.decorator_list])
186
+ own = set(range(start, node.end_lineno + 1))
187
+ for other, parent in funcs:
188
+ if parent is node:
189
+ own -= set(range(other.lineno, other.end_lineno + 1))
190
+ if own & lines:
191
+ chosen.append(node)
192
+ # A unit nested inside another chosen unit is already gone with its parent.
193
+ chosen_ids = set(id(n) for n in chosen)
194
+ parent_of = dict((id(n), p) for n, p in funcs)
195
+ top = []
196
+ for n in chosen:
197
+ p = parent_of.get(id(n))
198
+ nested = False
199
+ while p is not None:
200
+ if id(p) in chosen_ids:
201
+ nested = True
202
+ break
203
+ p = parent_of.get(id(p))
204
+ if not nested:
205
+ top.append(n)
206
+ return top
207
+
208
+
209
+ def ablate_source(source, units):
210
+ """Return source with each unit's body replaced by `return None`."""
211
+ lines = source.splitlines(keepends=True)
212
+ # Character offsets per line so (lineno, col) maps into the text. ast
213
+ # col_offset is in UTF-8 bytes, so slice each line as bytes.
214
+ spans = []
215
+ for node in units:
216
+ first, last = node.body[0], node.body[-1]
217
+ spans.append((first.lineno, first.col_offset, last.end_lineno, last.end_col_offset))
218
+ spans.sort(reverse=True)
219
+ blines = [ln.encode("utf-8") for ln in lines]
220
+ for sl, sc, el, ec in spans:
221
+ head = blines[sl - 1][:sc]
222
+ tail = blines[el - 1][ec:]
223
+ blines[sl - 1:el] = [head + b"return None" + tail]
224
+ return b"".join(blines).decode("utf-8")
225
+
226
+
227
+ def _record(loki_dir, status, reason, command, ablated_files, exit_code):
228
+ rec = {
229
+ "status": status,
230
+ "reason": reason,
231
+ "command": command or "",
232
+ "ablated_files": list(ablated_files),
233
+ "ablated_exit_code": exit_code,
234
+ }
235
+ qdir = os.path.join(loki_dir, "quality")
236
+ os.makedirs(qdir, exist_ok=True)
237
+ path = os.path.join(qdir, "ablation.json")
238
+ tmp = path + ".tmp"
239
+ with open(tmp, "w", encoding="utf-8") as f:
240
+ json.dump(rec, f, indent=2, sort_keys=True)
241
+ f.write("\n")
242
+ os.replace(tmp, path)
243
+ return rec
244
+
245
+
246
+ def _read_tests(loki_dir):
247
+ try:
248
+ with open(os.path.join(loki_dir, "quality", "test-results.json"), encoding="utf-8") as f:
249
+ raw = json.load(f)
250
+ except (OSError, ValueError):
251
+ return None
252
+ return raw if isinstance(raw, dict) else None
253
+
254
+
255
+ class _Snapshot(object):
256
+ """Exact bytes, mode and mtime of each file, restored in restore()."""
257
+
258
+ def __init__(self):
259
+ self.saved = {}
260
+
261
+ def save(self, path):
262
+ st = os.stat(path)
263
+ with open(path, "rb") as f:
264
+ self.saved[path] = (f.read(), st.st_mode, st.st_atime_ns, st.st_mtime_ns)
265
+
266
+ def restore(self):
267
+ errors = []
268
+ for path, (data, mode, atime, mtime) in self.saved.items():
269
+ try:
270
+ with open(path, "wb") as f:
271
+ f.write(data)
272
+ os.chmod(path, mode & 0o7777)
273
+ os.utime(path, ns=(atime, mtime))
274
+ except OSError as e:
275
+ errors.append("%s: %s" % (path, e))
276
+ return errors
277
+
278
+
279
+ def _run_command(repo, command, timeout):
280
+ env = dict(os.environ)
281
+ # The re-run must not leave bytecode for the ablated sources behind.
282
+ env["PYTHONDONTWRITEBYTECODE"] = "1"
283
+ proc = subprocess.Popen(
284
+ command,
285
+ shell=True,
286
+ cwd=repo,
287
+ env=env,
288
+ stdin=subprocess.DEVNULL,
289
+ stdout=subprocess.DEVNULL,
290
+ stderr=subprocess.DEVNULL,
291
+ start_new_session=True,
292
+ )
293
+ try:
294
+ return proc.wait(timeout=timeout), False
295
+ except subprocess.TimeoutExpired:
296
+ try:
297
+ os.killpg(proc.pid, signal.SIGKILL)
298
+ except OSError:
299
+ pass
300
+ proc.wait()
301
+ return None, True
302
+
303
+
304
+ def ablate(repo, base, loki_dir, timeout=DEFAULT_TIMEOUT_SEC):
305
+ repo = os.path.abspath(repo)
306
+ tests = _read_tests(loki_dir)
307
+ command = str((tests or {}).get("command") or "").strip()
308
+ if not command:
309
+ return _record(loki_dir, STATUS_NOT_APPLICABLE,
310
+ "no recorded check command in quality/test-results.json",
311
+ "", [], None)
312
+ if tests.get("exit_code") != 0:
313
+ return _record(loki_dir, STATUS_NOT_APPLICABLE,
314
+ "the recorded checks did not pass on the unablated change "
315
+ "(exit_code=%r), so an ablation proves nothing" % tests.get("exit_code"),
316
+ command, [], None)
317
+
318
+ try:
319
+ files = changed_files(repo, base)
320
+ untracked = untracked_files(repo)
321
+ except RuntimeError as e:
322
+ return _record(loki_dir, STATUS_NOT_APPLICABLE,
323
+ "cannot read the change since base %s: %s" % (base, e),
324
+ command, [], None)
325
+
326
+ check_paths = command_paths(repo, command)
327
+ code = [p for p in files
328
+ if os.path.splitext(p)[1].lower() in CODE_EXTENSIONS
329
+ and not is_test_path(p, check_paths)
330
+ and os.path.isfile(os.path.join(repo, p))]
331
+ if not code:
332
+ return _record(loki_dir, STATUS_NOT_APPLICABLE,
333
+ "no non-test source code changed since base (%d changed "
334
+ "file(s), all docs, config or tests)" % len(files),
335
+ command, [], None)
336
+ unsupported = [p for p in code if os.path.splitext(p)[1].lower() not in SUPPORTED_EXTENSIONS]
337
+
338
+ plan = [] # (path, new_source)
339
+ skipped = []
340
+ for p in code:
341
+ if p in unsupported:
342
+ continue
343
+ full = os.path.join(repo, p)
344
+ try:
345
+ with open(full, "rb") as f:
346
+ source = f.read().decode("utf-8")
347
+ units = select_units(source, changed_lines(repo, base, p, p in untracked))
348
+ except (OSError, UnicodeDecodeError, SyntaxError, ValueError, RuntimeError) as e:
349
+ skipped.append("%s (%s)" % (p, type(e).__name__))
350
+ continue
351
+ if units:
352
+ plan.append((p, ablate_source(source, units)))
353
+
354
+ if not plan:
355
+ why = []
356
+ if unsupported:
357
+ why.append("changed code in a language ablation does not parse: %s"
358
+ % ", ".join(sorted(unsupported)))
359
+ if skipped:
360
+ why.append("unreadable source: %s" % ", ".join(sorted(skipped)))
361
+ if not why:
362
+ why.append("the changed source lines sit outside any function, so "
363
+ "there is no code unit to no-op")
364
+ return _record(loki_dir, STATUS_NOT_APPLICABLE, "; ".join(why), command, [], None)
365
+
366
+ snap = _Snapshot()
367
+ for p, _ in plan:
368
+ snap.save(os.path.join(repo, p))
369
+
370
+ def _on_signal(signum, _frame):
371
+ raise KeyboardInterrupt("signal %d" % signum)
372
+
373
+ old = {}
374
+ for sig in (signal.SIGTERM, signal.SIGHUP):
375
+ try:
376
+ old[sig] = signal.signal(sig, _on_signal)
377
+ except (ValueError, OSError):
378
+ pass
379
+ try:
380
+ for p, new_source in plan:
381
+ with open(os.path.join(repo, p), "wb") as f:
382
+ f.write(new_source.encode("utf-8"))
383
+ exit_code, timed_out = _run_command(repo, command, timeout)
384
+ finally:
385
+ errors = snap.restore()
386
+ for sig, handler in old.items():
387
+ signal.signal(sig, handler)
388
+ if errors:
389
+ raise RuntimeError("working tree restore failed: %s" % "; ".join(errors))
390
+
391
+ ablated = [p for p, _ in plan]
392
+ note = ""
393
+ if unsupported:
394
+ note = " (not ablated, unsupported language: %s)" % ", ".join(sorted(unsupported))
395
+ if timed_out:
396
+ return _record(loki_dir, STATUS_LOAD_BEARING,
397
+ "with the changed code no-oped the checks did not finish "
398
+ "within %ds, so they depend on it%s" % (timeout, note),
399
+ command, ablated, None)
400
+ if exit_code != 0:
401
+ return _record(loki_dir, STATUS_LOAD_BEARING,
402
+ "the checks failed (exit %d) with the changed code no-oped, "
403
+ "so they exercise the change%s" % (exit_code, note),
404
+ command, ablated, exit_code)
405
+ return _record(loki_dir, STATUS_NOT_LOAD_BEARING,
406
+ "the checks still pass with the changed code no-oped, so they "
407
+ "do not exercise the change%s" % note,
408
+ command, ablated, exit_code)
409
+
410
+
411
+ def main(argv=None):
412
+ ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
413
+ ap.add_argument("--repo", required=True)
414
+ ap.add_argument("--base", required=True)
415
+ ap.add_argument("--loki-dir", required=True)
416
+ ap.add_argument("--timeout", type=int, default=None,
417
+ help="seconds for the ablated re-run (default LOKI_ABLATION_TIMEOUT or 600)")
418
+ args = ap.parse_args(argv)
419
+ timeout = args.timeout
420
+ if timeout is None:
421
+ try:
422
+ timeout = int(os.environ.get("LOKI_ABLATION_TIMEOUT", DEFAULT_TIMEOUT_SEC))
423
+ except ValueError:
424
+ timeout = DEFAULT_TIMEOUT_SEC
425
+ if not os.path.isdir(args.repo):
426
+ print("ablation: --repo is not a directory: %s" % args.repo, file=sys.stderr)
427
+ return 2
428
+ try:
429
+ rec = ablate(args.repo, args.base, args.loki_dir, timeout=max(timeout, 1))
430
+ except (OSError, RuntimeError) as e:
431
+ print("ablation: %s" % e, file=sys.stderr)
432
+ return 2
433
+ print("ablation: %s - %s" % (rec["status"], rec["reason"]))
434
+ return 0
435
+
436
+
437
+ if __name__ == "__main__":
438
+ sys.exit(main())
@@ -7,6 +7,6 @@ Modules:
7
7
  control: Session control helpers (status, atomic writes, origin check)
8
8
  """
9
9
 
10
- __version__ = "11.17.28"
10
+ __version__ = "11.17.30"
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.28. Do not edit by hand.
3
+ Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.17.30. 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 |
@@ -44,10 +44,11 @@ Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for th
44
44
  | `loki wiki generate` | Generate the wiki |
45
45
  | `loki wiki show` | Show a section |
46
46
  | `loki wiki ask` | Ask a question |
47
- | `loki control` | Control Plane (serve, backfill, prune, status) |
47
+ | `loki control` | Control Plane (serve, backfill, prune, stop, status) |
48
48
  | `loki control serve` | Run the control plane and UI |
49
49
  | `loki control backfill` | Ship DIR/.loki/runs to the control plane |
50
50
  | `loki control prune` | Delete matching runs |
51
+ | `loki control stop` | Stop the running control plane |
51
52
  | `loki control status` | Show control plane reachability |
52
53
  | `loki intent` | Show a past run's intent card |
53
54
  | `loki intent show` | Print the intent card and answer |
@@ -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.28
5
+ **Version:** v11.17.30
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
@@ -1103,24 +1103,24 @@ Source: ~/git/autonomi-dev/research/2026-09-30-adoption/SWARM-PROMPT-ADOPTION.md
1103
1103
  | TEN-UX-03-F1 | build_verified payload asserted to carry only headline and route | tests/test-first-run-funnel-coverage.sh | LOW | adding an extra arg to loki_emit_build_verified_enum turns the test red | building@2026-10-17T05:43Z | UX-03 TL review non-blocking 1 |
1104
1104
  | TEN-RELEASE-FAST | one-command ship: scripts/release.sh --ship --notes FILE bumps, writes the CHANGELOG section, rebuilds dist, commits, checks ancestry and gitleaks, waits for an in-flight Release run, pushes and verifies origin/main | scripts/release.sh, tests/test-release-sh.sh (extend; it owns release.sh) | HIGH | --ship on a fixture repo with a fake origin completes all phases and prints per-phase timings; a non-ancestor origin, a gitleaks hit, a forbidden staged file and a CHANGELOG c[7] mismatch each abort before push (red mutation per guard) | building@2026-10-17T05:43Z | D103; target under 90s wall for the whole ship |
1105
1105
  | TEN-SEC-PREPUSH-MERGE-WARN | pre-push .gitleaksignore-growth warning diffs merges against the first parent only, so a merge of an older slice no longer reports lines main already had | .githooks/pre-push (line ~621 diff-tree -m), tests/test-security-audit-config.sh or the existing pre-push test that owns this warning; docs/v10/FAILURE-CLASSES.md (row first) | LOW | pushing a merge of a branch based before an ignore line was added prints no warning; a commit that really adds an ignore line still warns (red mutation: put -m back) | released v11.17.28 | v11.17.25 push printed 5 false warnings for merges c6d3894f1..0a16434e1 while git diff 7d4d0ffb2 HEAD -- .gitleaksignore was empty |
1106
- | TEN-COST-16-F1 | haiku-first downgrade row: router-override test, and the cascade override is reported only when cascadeDowngrade(run model) is non-null | loki-ts/src/runner/model_downgrades.ts, loki-ts/tests/engine10/session_l1_model.test.ts | LOW | router+haiku-first names the router override; cascade on a sonnet run reports the haiku-first row, matching implement.ts:106 precedence | building@2026-10-17T05:43Z | COST-16 r2 TL non-blocking N2, N3 |
1106
+ | TEN-COST-16-F1 | haiku-first downgrade row: router-override test, and the cascade override is reported only when cascadeDowngrade(run model) is non-null | loki-ts/src/runner/model_downgrades.ts, loki-ts/tests/engine10/session_l1_model.test.ts | LOW | router+haiku-first names the router override; cascade on a sonnet run reports the haiku-first row, matching implement.ts:106 precedence | released v11.17.29 | COST-16 r2 TL non-blocking N2, N3 |
1107
1107
  | TEN-COST-25 | fix: --cost lean stops forcing a plan session: drop LOKI_ROUTER from the lean profile (router makes plan.ts:65 plan every small task and overrides haiku-first) and add LOKI_IMPLEMENT_HAIKU_FIRST=1 plus the COST-26 sizing knobs | loki-ts/src/util/cost_profile.ts, loki-ts/tests/util/cost_profile.test.ts | MEDIUM | red: resolveCostProfile('lean') yields LOKI_ROUTER=1 and no LOKI_IMPLEMENT_HAIKU_FIRST; green: lean env has LOKI_IMPLEMENT_HAIKU_FIRST=1, no LOKI_ROUTER, and the COST-26 knobs; balanced/max unchanged | ready@2026-10-17T05:54Z | depends: TEN-COST-26, TEN-COST-16-F1. goal: cost-2x lever; C-F1 run4 small tasks were 1.415x raw from fixed plan+Wall cost (cf1-20261017T025219Z, plan_skipped=false on all 31) |
1108
- | TEN-COST-26 | feature: sizing knobs LOKI_E10_SMALL_MAX_CHARS (default 600, unchanged) and opt-in LOKI_E10_SMALL_NO_RUNNER=1 so a missing test runner no longer forces normal (smallTaskPath still routes it to wall) | loki-ts/src/engine10/sizing.ts (at most 3 core lines), loki-ts/tests/engine10/sizing.test.ts | MEDIUM | red: a 700-char task with LOKI_E10_SMALL_MAX_CHARS=800 sizes normal, and a no-runner task with LOKI_E10_SMALL_NO_RUNNER=1 sizes normal; green: both small, defaults byte-identical | ready@2026-10-17T05:54Z | goal: C-F1 run4 sized all 31 tasks normal (19 'no test runner detected', 12 also >600 chars at 683/724); core budget 4937/5000 |
1108
+ | TEN-COST-26 | feature: sizing knobs LOKI_E10_SMALL_MAX_CHARS (default 600, unchanged) and opt-in LOKI_E10_SMALL_NO_RUNNER=1 so a missing test runner no longer forces normal (smallTaskPath still routes it to wall) | loki-ts/src/engine10/sizing.ts (at most 3 core lines), loki-ts/tests/engine10/sizing.test.ts | MEDIUM | red: a 700-char task with LOKI_E10_SMALL_MAX_CHARS=800 sizes normal, and a no-runner task with LOKI_E10_SMALL_NO_RUNNER=1 sizes normal; green: both small, defaults byte-identical | released v11.17.29 | goal: C-F1 run4 sized all 31 tasks normal (19 'no test runner detected', 12 also >600 chars at 683/724); core budget 4937/5000 |
1109
1109
  | TEN-COST-27 | enhancement: loki start reads cost.profile from loki.yaml as the team default; --cost flag and LOKI_COST_PROFILE env still win | loki-ts/src/commands/start.ts (cost flag resolution near line 279 only; not the help block DEPLOY rows own), loki-ts/tests/commands/start.test.ts | LOW | red: loki.yaml cost.profile: lean with no flag resolves balanced; green: resolves lean, flag and env override it, invalid value warns and falls back | ready@2026-10-17T05:54Z | depends: TEN-COST-25. goal: teams opt in to the lean lever once; reuse util/yaml_key.ts yamlKey |
1110
- | TEN-SPEED-01 | feature: cost_claim reports a paired elapsed_s ratio (raw/loki) with the same bootstrap CI as the cost ratio | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | LOW | red: cost_claim JSON has no time_ratio key for paired rows carrying elapsed_s; green: time_ratio and time_ci present, rows missing elapsed_s are excluded and counted | ready@2026-10-17T05:54Z | goal: speed has no measured number today (cost_claim has no time metric; attribution.py:351-355 already writes elapsed_s); first SPEED row |
1110
+ | TEN-SPEED-01 | feature: cost_claim reports a paired elapsed_s ratio (raw/loki) with the same bootstrap CI as the cost ratio | benchmarks/bench/cost_claim.py, benchmarks/bench/tests/test_cost_claim.py | LOW | red: cost_claim JSON has no time_ratio key for paired rows carrying elapsed_s; green: time_ratio and time_ci present, rows missing elapsed_s are excluded and counted | released v11.17.29 | goal: speed has no measured number today (cost_claim has no time metric; attribution.py:351-355 already writes elapsed_s); first SPEED row |
1111
1111
  | TEN-SPEED-02 | enhancement: bench-suite times loki verify --fast and records p95 to migration_bench.jsonl | loki-ts/scripts/bench-suite.ts, loki-ts/tests/scripts/bench_suite_argv.test.ts | LOW | red: benchRouteArgv has no verify --fast route and no p95 field; green: argv test asserts the route and the record carries p95_ms | ready@2026-10-17T05:54Z | goal: METRICS lists verify --fast p95 as not measured; fills it with a repeatable command |
1112
- | TEN-UX-09 | feature: loki control stop stops the detached control plane via instance.json PID plus a /health identity check, never by name | loki-ts/src/commands/control.ts, loki-ts/tests/commands/control.test.ts, loki-ts/src/cli/registry.ts (control row sub list only), completions/_loki and completions/loki.bash (control subcommands only) | MEDIUM | red: loki control stop is an unknown subcommand (control.ts:175-181 handles serve/status/prune/backfill); green: stop ends the recorded PID, refuses a PID whose /health does not match, exits 0 when nothing runs | ready@2026-10-17T05:54Z | goal: bare loki leaves a nohup control serve with no stop (observed PID 50904 + server.js on 47821); reuse restartStaleControlPlane control.ts:52-70 |
1112
+ | TEN-UX-09 | feature: loki control stop stops the detached control plane via instance.json PID plus a /health identity check, never by name | loki-ts/src/commands/control.ts, loki-ts/tests/commands/control.test.ts, loki-ts/src/cli/registry.ts (control row sub list only), completions/_loki and completions/loki.bash (control subcommands only) | MEDIUM | red: loki control stop is an unknown subcommand (control.ts:175-181 handles serve/status/prune/backfill); green: stop ends the recorded PID, refuses a PID whose /health does not match, exits 0 when nothing runs | released v11.17.29 | goal: bare loki leaves a nohup control serve with no stop (observed PID 50904 + server.js on 47821); reuse restartStaleControlPlane control.ts:52-70 |
1113
1113
  | TEN-UX-10 | fix: bare loki prints next steps (give work with loki start "<brief>"; stop the UI with loki control stop) after the URL instead of the URL alone | autonomy/loki (_loki_control_ui only), tests/test-control-plane.sh | LOW | red: bare loki stdout is exactly the URL line; green: the URL line is first and both next-step lines follow; --json or non-TTY output unchanged if it has a contract | ready@2026-10-17T05:54Z | depends: TEN-UX-09. goal: first-run UX; today a new user sees only http://127.0.0.1:47821 and a background daemon |
1114
1114
  | TEN-UX-11 | enhancement: the run summary Time line marks the first sealed PR in a repo (time to first sealed PR) so METRICS row 14 can be read from run output | loki-ts/src/engine10/output.ts (Time line input field only), loki-ts/tests/engine10/output.test.ts | LOW | red: summary with firstSealed=true renders the same Time line as any run; green: Time line appends 'first sealed PR in this repo' only when set, golden for other runs unchanged | ready@2026-10-17T05:54Z | goal: time to first sealed PR is not measured (METRICS row 14); caller wiring is a follow-up row |
1115
1115
  | TEN-UX-12 | fix: the preflight 'could not confirm the Claude login' warning never adds a stdout line in quiet mode (stderr only) | loki-ts/src/engine10/preflight.ts (warning emit at line ~28 only), loki-ts/tests/engine10/preflight.test.ts | LOW | red: quiet run with an unanswered auth status prints 9 stdout lines (e2e.test.ts:130 A-130 limit 8); green: warning on stderr, quiet stdout within 8 lines | ready@2026-10-17T05:54Z | depends: TEN-P9-FIX-F1 (owns preflight.test.ts). goal: quiet-mode contract and a likely cause of the red main Tests runs |
1116
1116
  | TEN-ADOPTION-09 | feature: engine10 pr stage routes a gitlab.com pinned origin to engine10-push-gitlab.sh push-mr and accepts the MR URL | loki-ts/src/engine10/stages/pr.ts, loki-ts/tests/engine10/pr.test.ts | HIGH | red: gitlab origin calls DEFAULT_PUSH_SH engine10-push.sh (pr.ts:42) and an MR URL fails PR_URL_RE (pr.ts:72); green: push-mr is invoked and the MR URL is recorded; github path byte-identical | ready@2026-10-17T05:54Z | goal: GitLab teams; the script and tests/test-engine10-push-gitlab.sh exist but nothing in loki-ts/src references it |
1117
1117
  | TEN-ADOPTION-10 | fix: reviewer instructions name the receipt-check action with a copyable uses: line pinned to the current version instead of 'adds the receipt-check action' | loki-ts/src/e10ext/reviewer_body.ts, loki-ts/tests/engine10/pr_body_golden.test.ts | LOW | red: reviewer body line 54 has no uses: reference; green: body contains uses: <repo>/.github/actions/receipt-check@v<VERSION> and the golden is updated | ready@2026-10-17T05:54Z | goal: .github/actions/receipt-check exists (tests/test-receipt-check-action.sh) but no user-facing text tells a reviewer how to add it |
1118
- | TEN-GATES-11 | feature: build autonomy/lib/ablation.py to the tests/moat/p8-load-bearing-proof.sh contract and promote the 3 P8 ablation lines in tests/moat/pending.txt | autonomy/lib/ablation.py (new: the p8 header names this exact path and no module owns it), tests/test_ablation.py (new: the new module's own test), tests/moat/pending.txt (3 P8 lines only) | HIGH | red: bash tests/moat/p8-load-bearing-proof.sh fails, ablation.py missing; green: P8.ablation-runtime-change-load-bearing, P8.ablation-dead-code-not-sealed, P8.ablation-na-docs-only pass and leave pending.txt; restore is byte-for-byte | ready@2026-10-17T05:54Z | goal: moat 2/9 proven; consumer already built (proof-generator.py:874 _collect_ablation, :2052 headline refusal), producer missing |
1118
+ | TEN-GATES-11 | feature: build autonomy/lib/ablation.py to the tests/moat/p8-load-bearing-proof.sh contract and promote the 3 P8 ablation lines in tests/moat/pending.txt | autonomy/lib/ablation.py (new: the p8 header names this exact path and no module owns it), tests/test_ablation.py (new: the new module's own test), tests/moat/pending.txt (3 P8 lines only) | HIGH | red: bash tests/moat/p8-load-bearing-proof.sh fails, ablation.py missing; green: P8.ablation-runtime-change-load-bearing, P8.ablation-dead-code-not-sealed, P8.ablation-na-docs-only pass and leave pending.txt; restore is byte-for-byte | released v11.17.29 | goal: moat 2/9 proven; consumer already built (proof-generator.py:874 _collect_ablation, :2052 headline refusal), producer missing |
1119
1119
  | TEN-GATES-12 | enhancement: loki start proof path runs ablation.py before proof-generator so quality/ablation.json exists on engine10 runs | loki-ts/src/runner/proof.ts (pre-proof hook only), loki-ts/tests/runner/proof.test.ts | HIGH | red: an engine10 run with a load-bearing change leaves no quality/ablation.json; green: file present with status load_bearing, ablation failure is recorded not_applicable and never blocks the proof | ready@2026-10-17T05:54Z | depends: TEN-GATES-07, TEN-GATES-11. goal: the P8 property reaches real runs, not just the moat script |
1120
1120
  | TEN-GATES-13 | feature: seeded-defect corpus at benchmarks/seeded-defects/manifest.json (schema loki.seeded-defects/v2, >=100 defects, generated) and promote P4.seeded-defect-corpus-present | benchmarks/seeded-defects/ (new dir: the p4 contract names this path), tests/moat/pending.txt (1 P4 line only) | HIGH | red: P4.seeded-defect-corpus-present fails, directory absent; green: manifest validates, count >=100, generator rerun is byte-identical, pending line removed | ready@2026-10-17T05:54Z | depends: TEN-GATES-11 (shared pending.txt, one line each). goal: Seal accuracy cannot be measured without the corpus |
1121
1121
  | TEN-DEPLOY-10 | feature: loki status --probe re-probes the last deploy health URL and exits non-zero on regression | loki-ts/src/commands/status.ts (renderLastDeploy region only), loki-ts/tests/commands/status.test.ts | MEDIUM | red: --probe is an unknown flag; green: healthy URL exits 0, a 500 or timeout exits 1 with the URL and status, no last deploy exits 0 with a note | ready@2026-10-17T05:54Z | goal: post-deploy watch; deploy health is recorded once and never rechecked |
1122
- | TEN-STABILITY-09 | fix: engine10 stub e2e suites answer claude auth status so the P9 login probe never stalls or warns in stub runs | loki-ts/tests/engine10/e2e.test.ts (and its stub fixture only) | MEDIUM | red: on main the A-130 quiet, Rule of Two canary, cost cap, eval PR, issue-ref and SIGINT e2e cases fail; green: all pass with the stub answering auth status | ready@2026-10-17T05:54Z | depends: none; first confirm still red on 7d4d0ffb2/0463f084b. goal: main Tests failed 11 of 13 recent runs; e2e.test.ts untouched since TEN-UX-01 |
1123
- | TEN-STABILITY-10 | fix: pulse merged-not-released check reads merges with one git log pass indexed by slice ID instead of one git log per row | scripts/v10-pulse.sh (lookup near line 1993 and check_merged_not_released_stale only), tests/test-v10-pulse.sh | MEDIUM | red: a board with 50 merged rows runs 50 git log calls and one timeout raises RuntimeError for row D63-C5; green: one git call, same rows flagged, git failure still reported UNKNOWN not 'nothing to flag' | ready@2026-10-17T05:54Z | goal: pulse at 05:51Z reported 'git log --merges failed for row D63-C5: rc=None: TIMEOUT'; the anti-drift signal goes dark under load |
1122
+ | TEN-STABILITY-09 | fix: engine10 stub e2e suites answer claude auth status so the P9 login probe never stalls or warns in stub runs | loki-ts/tests/engine10/e2e.test.ts (and its stub fixture only) | MEDIUM | red: on main the A-130 quiet, Rule of Two canary, cost cap, eval PR, issue-ref and SIGINT e2e cases fail; green: all pass with the stub answering auth status | released v11.17.30 | depends: none; first confirm still red on 7d4d0ffb2/0463f084b. goal: main Tests failed 11 of 13 recent runs; e2e.test.ts untouched since TEN-UX-01 |
1123
+ | TEN-STABILITY-10 | fix: pulse merged-not-released check reads merges with one git log pass indexed by slice ID instead of one git log per row | scripts/v10-pulse.sh (lookup near line 1993 and check_merged_not_released_stale only), tests/test-v10-pulse.sh | MEDIUM | red: a board with 50 merged rows runs 50 git log calls and one timeout raises RuntimeError for row D63-C5; green: one git call, same rows flagged, git failure still reported UNKNOWN not 'nothing to flag' | released v11.17.30 | goal: pulse at 05:51Z reported 'git log --merges failed for row D63-C5: rc=None: TIMEOUT'; the anti-drift signal goes dark under load |
1124
1124
  | TEN-QUALITY-10 | fix: a traceback or file:line path missing from a truncated repo map (cap 2000) is still ranked when git tracks it | loki-ts/src/util/relevance.ts, loki-ts/src/engine10/relevant_files.ts (at most 2 core lines), loki-ts/tests/engine10/plan.test.ts | MEDIUM | red: repo with 2500 files and a traceback naming file 2400 never lists it as relevant; green: it ranks first; untracked or absent paths still ignored | ready@2026-10-17T05:54Z | goal: repomap.ts:19,34 MAX_FILES=2000 takes the first 2000 ls-files entries, so large repos lose explicit file hints |
1125
1125
  | TEN-QUALITY-11 | enhancement: a Python repo with uv.lock and no .venv runs tests and lint through uv run as the project interpreter | loki-ts/src/engine10/stages/verify.ts (resolveTool only, at most 3 core lines), loki-ts/tests/engine10/verify.test.ts | MEDIUM | red: uv.lock repo without .venv gets interpreter system and 'tests ran on the system interpreter' NOT PROVEN (verify.ts:43,339); green: interpreter project via uv run; no uv on PATH keeps today's system result | ready@2026-10-17T05:54Z | goal: avoid a false PARTIAL for uv projects; verify.ts has no uv handling today |
1126
1126
  | TEN-QUALITY-12 | enhancement: repo map cap configurable (LOKI_E10_REPOMAP_MAX_FILES) and truncation drops vendored or generated dirs before source | loki-ts/src/engine10/repomap.ts (at most 3 core lines), loki-ts/tests/engine10/repomap.test.ts | LOW | red: 2500-file repo with 1500 vendor/ files maps mostly vendor and ignores the env knob; green: knob honored, vendor/ node_modules dist dropped first, default 2000 unchanged | ready@2026-10-17T05:54Z | goal: plan context quality on large repos; complements TEN-QUALITY-10 with no shared file |
@@ -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): 201
14
+ - Registry paths (commands and nested subcommands): 202
15
15
 
16
16
  ## Commands
17
17
 
@@ -2464,3 +2464,9 @@ v11.17.21 published (Release success on 462fbc40a; npm latest 11.17.21, next 11.
2464
2464
 
2465
2465
  ## 2026-10-17T06:08Z (CoS) v11.17.28
2466
2466
  - v11.17.26 Release run 39008106373 success, npm latest=next=11.17.26. v11.17.27 pushed e044e5395 (HEAD equals origin/main, gitleaks no leaks). Ships TEN-COST-04 (TL APPROVE b6562f67d: pytest 153 passed, mutation M1 3 failed) and TEN-SEC-PREPUSH-MERGE-WARN (TL APPROVE 78f48de3a: tests/test-pre-push-gitleaks.sh Passed 59 Failed 0, mutation case 19b red). TEN-COST-16-F1 built nothing (row uncommitted at dispatch); re-dispatched in wave Z with COST-26, SPEED-01, UX-09, GATES-11.
2467
+
2468
+ ## 2026-10-17T06:16Z (CoS) v11.17.29
2469
+ - v11.17.28 pushed 5f504d333 without waiting for the v11.17.27 Release run (release.yml has no concurrency group; publish has a never-backwards guard). Wave Z all APPROVE: COST-16-F1 d9b5917fd (47 pass, 2 mutations red), COST-26 ddaf2389a (30 pass, 2 mutations red), SPEED-01 a643883d7 (pytest 24 passed, inverted ratio 6 failed), UX-09 b80656d3e (64 pass, 2 mutations red), GATES-11 c7cc6a31b HIGH (p8 moat rc=0 3 of 3 PASS, pytest 23 passed, 5 mutations red). COST-26 hand-merge: test-only conflict in sizing.test.ts resolved as union, bun test sizing and wall 94 pass 0 fail. Moat P8 moved from pending to proven.
2470
+
2471
+ ## 2026-10-17T06:18Z (CoS) v11.17.30
2472
+ - Ships TEN-STABILITY-09 (TL APPROVE 57e3aa1f6: bun test 87 pass 0 fail, 2 stub mutations red) and TEN-STABILITY-10 (TL APPROVE f8b625ca1: tests/test-v10-pulse.sh 171 passed, 2 mutations red at T51b). v11.17.29 landed 1e4c2da03.