loki-mode 11.17.28 → 11.17.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/ablation.py +438 -0
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +3 -2
- package/docs/INSTALLATION.md +1 -1
- package/docs/v10/BOARD.md +5 -5
- package/docs/v10/CLI-MODERN.md +1 -1
- package/docs/v10/PROGRESS.md +3 -0
- package/loki-ts/dist/loki.js +916 -909
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +4 -3
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-CVL2iS0A.js → AdminPage-nOM5_DUk.js} +1 -1
- package/web-app/dist/assets/{Avatar-D2v6R8Pa.js → Avatar-CGDH9-gR.js} +1 -1
- package/web-app/dist/assets/{Badge-Dml-mw_3.js → Badge-BeWbTYVE.js} +1 -1
- package/web-app/dist/assets/{Button-C5LDE6K3.js → Button-BNKBYiAG.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-vRyDaxcA.js → CockpitPage-CbEzPdi5.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DYuyWSI9.js → ComparePage-D9Rslj5T.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-C3VvRg7q.js → ErrorBoundary-B_nrpRwD.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-902knSfv.js → EvidenceReceiptPanel-D4rRYbqn.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-CRNkNcmk.js → GitHubIssuesPanel-BQvLUh5v.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-q4gx82lS.js → GitHubPRsPanel-CH7Dyrd6.js} +1 -1
- package/web-app/dist/assets/{HomePage-Cv7pbnhd.js → HomePage-BHxJZ3Kl.js} +2 -2
- package/web-app/dist/assets/{LoginPage-Dh6NB3jf.js → LoginPage-CrazYYjU.js} +1 -1
- package/web-app/dist/assets/{MagicPage-BM6Bcci-.js → MagicPage-C2FJn91q.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-fZlWYNF3.js → MetricsPage-Dz59bBAM.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-B2WYNJuo.js → NotFoundPage-N1pabiAk.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BPzxFIOe.js → ProjectPage-DYoQGOAA.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-B9ds4_6v.js → ProjectsPage-pZ-7z54o.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-BVhRp_5V.js → SettingsPage-DKRvbK1L.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-DdgdARlL.js → ShowcasePage-BWgXXOtm.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-CE2X9jf3.js → SystemSettingsPage-Dk4Bzcq_.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-CoXQ5sW8.js → TeamsPage-DHZQEjY7.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-BMdF_-r1.js → TemplatesPage-C6p9AzQQ.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-BjJ3eauc.js → TerminalOutput-CtwglGdt.js} +1 -1
- package/web-app/dist/assets/{activity-BNhuXaIH.js → activity-BgirK2TT.js} +1 -1
- package/web-app/dist/assets/{bell-Y2p0uWz8.js → bell-NPG8g71D.js} +1 -1
- package/web-app/dist/assets/{bot-D_24DrNI.js → bot-CU_mRs9-.js} +1 -1
- package/web-app/dist/assets/{check-YZVX7kq8.js → check-D5UCrL7s.js} +1 -1
- package/web-app/dist/assets/{chevron-left-DRMLmqUz.js → chevron-left-Bfj1xzjy.js} +1 -1
- package/web-app/dist/assets/{circle-alert-CDLIuEey.js → circle-alert-ZddFscX0.js} +1 -1
- package/web-app/dist/assets/{clock-CERWGH9H.js → clock-CdbiCMDa.js} +1 -1
- package/web-app/dist/assets/{cloud-DXbVQPWO.js → cloud-D4jNgoPd.js} +1 -1
- package/web-app/dist/assets/{code-xml-B3Gvchrt.js → code-xml-DX2AsHzH.js} +1 -1
- package/web-app/dist/assets/{database-B5OKN-TT.js → database-DpwUzfhE.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-C2eKvfOT.js → dollar-sign-CJPL_5Fy.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-DGKU_c3D.js → file-code-corner-B-s99s3w.js} +1 -1
- package/web-app/dist/assets/{file-plus-DkD31_E5.js → file-plus-D5IXpIz8.js} +1 -1
- package/web-app/dist/assets/{globe-CyC41Z_-.js → globe-Dw08p3-o.js} +1 -1
- package/web-app/dist/assets/{hammer-C7FT_3yF.js → hammer-CtBRJvWo.js} +1 -1
- package/web-app/dist/assets/{index-BpbEH56b.js → index-DnYZaSsT.js} +3 -3
- package/web-app/dist/assets/{layers-D-3Cwpw6.js → layers-CfxWVRur.js} +1 -1
- package/web-app/dist/assets/{loader-circle-DgNtuzb9.js → loader-circle-BhR9FwJ1.js} +1 -1
- package/web-app/dist/assets/{lock-D4JH8mi6.js → lock-1kVCQsnD.js} +1 -1
- package/web-app/dist/assets/{package-t_M9BH8g.js → package-qV8-Zyoq.js} +1 -1
- package/web-app/dist/assets/{plus-Obkd-9BS.js → plus-CZ6Td-xg.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-hPt3gjaj.js → refresh-cw-B3C0rY77.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-Bxx5xmbg.js → rotate-ccw-DIvx7x-w.js} +1 -1
- package/web-app/dist/assets/{scroll-text-BMg_UC4V.js → scroll-text-Dd1wqcHK.js} +1 -1
- package/web-app/dist/assets/{server-CEI_O0dC.js → server-BAKsBlPl.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BgUNjSfh.js → shield-alert-BFP6Yjmc.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-Ce8U9-4o.js → thumbs-up-DeYyCkjX.js} +1 -1
- package/web-app/dist/assets/{trash-2-CyHGdwm6.js → trash-2-CFsKTEeM.js} +1 -1
- package/web-app/dist/assets/{trending-down-CqoosHU1.js → trending-down-BAZYNXIX.js} +1 -1
- package/web-app/dist/assets/{trending-up-PbI-apLz.js → trending-up-CUEAWCMi.js} +1 -1
- package/web-app/dist/assets/{upload-BuHrZkxB.js → upload-BaYVlIfV.js} +1 -1
- package/web-app/dist/assets/{usePolling-Kohcnabw.js → usePolling-CQ3I38RA.js} +1 -1
- package/web-app/dist/assets/{user-XgMAd6rY.js → user-C7ePVV51.js} +1 -1
- 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.
|
|
6
|
+
# Loki Mode v11.17.29
|
|
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.
|
|
486
|
+
**v11.17.29 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
11.17.
|
|
1
|
+
11.17.29
|
|
@@ -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())
|
package/dashboard/__init__.py
CHANGED
package/docs/CLI-REFERENCE.md
CHANGED
|
@@ -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.
|
|
3
|
+
Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.17.29. 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 |
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -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.
|
|
5
|
+
**Version:** v11.17.29
|
|
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,19 +1103,19 @@ 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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 |
|
package/docs/v10/CLI-MODERN.md
CHANGED
|
@@ -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):
|
|
14
|
+
- Registry paths (commands and nested subcommands): 202
|
|
15
15
|
|
|
16
16
|
## Commands
|
|
17
17
|
|
package/docs/v10/PROGRESS.md
CHANGED
|
@@ -2464,3 +2464,6 @@ 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.
|