loki-mode 11.4.2 → 11.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/chat.sh +6 -3
- package/autonomy/lib/engine10-push.sh +19 -1
- package/autonomy/lib/help-core.sh +1 -1
- package/autonomy/lib/proof-generator.py +23 -5
- package/autonomy/lib/proof-verify.py +607 -5
- package/autonomy/lib/run-summary.sh +17 -1
- package/autonomy/lib/setup-requirements.json +35 -0
- package/autonomy/loki +244 -237
- package/autonomy/notification-checker.py +1 -1
- package/autonomy/provider-offer.sh +95 -47
- package/autonomy/route.sh +38 -6
- package/autonomy/run.sh +42 -14
- package/autonomy/setup-wizard.sh +19 -10
- package/autonomy/verify.sh +40 -1
- package/completions/_loki +3 -1
- package/completions/loki.bash +9 -3
- package/dashboard/__init__.py +3 -10
- package/dashboard/control.py +5 -435
- package/docs/ARCHITECTURE.md +1 -2
- package/docs/CLI-CORE-VERBS.md +2 -6
- package/docs/CLI-REFERENCE.md +3 -1
- package/docs/COMPONENTS.md +0 -2
- package/docs/EVALUATING.md +27 -0
- package/docs/HARNESS-INTELLIGENCE-PLAN.md +20 -0
- package/docs/INSTALLATION.md +1 -1
- package/docs/KNOWN-ISSUES.md +10 -1
- package/docs/PROOF-PASSPORT.md +114 -0
- package/docs/alternative-installations.md +103 -0
- package/docs/authentication.md +19 -1
- package/docs/cost-controls.md +139 -0
- package/docs/dev/release-checklist.md +9 -8
- package/docs/enterprise/security.md +3 -234
- package/docs/environment-variables.md +36 -0
- package/docs/exit-codes.md +102 -2
- package/docs/spec-first-intent.md +29 -0
- package/docs/v10/ARCHITECT-CUTS.md +304 -0
- package/docs/v10/CLI-MODERN.md +2 -2
- package/docs/v10/DECISIONS.md +5 -5
- package/docs/v10/ENGINE.md +735 -267
- package/docs/v10/GUARDS.md +16 -14
- package/docs/v10/GUIDE.md +5 -7
- package/docs/v10/PROGRESS.md +12 -1
- package/docs/v11/MARKET-SLICES.md +1 -5
- package/integrations/openclaw/README.md +20 -0
- package/integrations/vibe-kanban.md +12 -50
- package/loki-ts/data/model-pricing.json +1 -0
- package/loki-ts/dist/loki.js +1156 -1103
- package/mcp/__init__.py +1 -1
- package/mcp/_sdk_loader.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +2063 -1032
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/plugins/loki-mode/README.md +41 -1
- package/plugins/loki-mode/commands/handoff.md +12 -0
- package/plugins/loki-mode/commands/loki-verify.md +9 -2
- package/plugins/loki-mode/commands/start.md +20 -0
- package/plugins/loki-mode/hooks/hooks.json +11 -0
- package/plugins/loki-mode/scripts/loki-stop-verify.sh +84 -0
- package/references/quality-control.md +1 -116
- package/skills/00-index.md +2 -2
- package/skills/artifacts.md +0 -22
- package/skills/production.md +2 -38
- package/web-app/dist/assets/{AdminPage-CYJ2BWRC.js → AdminPage-DhXdJNQk.js} +1 -1
- package/web-app/dist/assets/{Avatar-DdK4wynI.js → Avatar-ixVj76fM.js} +1 -1
- package/web-app/dist/assets/{Badge-CrX3MI7J.js → Badge-BGMSp22s.js} +1 -1
- package/web-app/dist/assets/{Button-709-wwGM.js → Button-pYJc32tG.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BapdTInO.js → CockpitPage-C1JBBouA.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DT99pGvA.js → ComparePage-qD0NV4RK.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-B0uJSys8.js → ErrorBoundary-C-yxO58j.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-BtMFgElP.js → EvidenceReceiptPanel-ByPzuE1S.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DjJuU941.js → GitHubIssuesPanel-BNv_2BEJ.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-HXfEX1BC.js → GitHubPRsPanel-CuLZQ9CS.js} +1 -1
- package/web-app/dist/assets/{HomePage-Cqyves-S.js → HomePage-CS_FW8Je.js} +2 -2
- package/web-app/dist/assets/{LoginPage-jUbtC7_Y.js → LoginPage-DwiNf1Wm.js} +1 -1
- package/web-app/dist/assets/{MagicPage-DHRsqjgR.js → MagicPage-CmQybLPZ.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-B-pED05R.js → MetricsPage-D9ERdpv8.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-CsbUs21R.js → NotFoundPage-D9ccgdbF.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BtlLEQwB.js → ProjectPage-B9Jslmgv.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DaRbRjSp.js → ProjectsPage-DnU99Go2.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DALrtP3F.js → SettingsPage-DcTyx6wo.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-CoPHSNP0.js → ShowcasePage-jEY9ghSr.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-kOuSN50O.js → SystemSettingsPage-CSGltW-8.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-DGWK0LMp.js → TeamsPage-gUuJXb9l.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-C-_10CwA.js → TemplatesPage-37Zhe--v.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Cz_vPbXL.js → TerminalOutput-B09hRwaR.js} +1 -1
- package/web-app/dist/assets/{activity-icIsXJVa.js → activity-q_4MY9J0.js} +1 -1
- package/web-app/dist/assets/{bell-DbPR2_4r.js → bell-X8OC_PFP.js} +1 -1
- package/web-app/dist/assets/{bot-DvjP3Yh5.js → bot-C-N1PUOD.js} +1 -1
- package/web-app/dist/assets/{check-D1OBxHeU.js → check-B2c76Jmp.js} +1 -1
- package/web-app/dist/assets/{chevron-left-D09jDZ29.js → chevron-left-BF76YLNw.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DyZMLOcC.js → circle-alert-AeFKBD8h.js} +1 -1
- package/web-app/dist/assets/{clock-CdpdJTId.js → clock-CiXRf-FH.js} +1 -1
- package/web-app/dist/assets/{cloud-CoLTlmoj.js → cloud-DKQ8SRJ5.js} +1 -1
- package/web-app/dist/assets/{code-xml-DrkE2ZZY.js → code-xml-DEb6jXWP.js} +1 -1
- package/web-app/dist/assets/{database-CMQQuM2R.js → database-6W7e-E9c.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CuioDaOG.js → dollar-sign-Ds2GOuyW.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-Cx9j9K1S.js → file-code-corner-CZU0jg52.js} +1 -1
- package/web-app/dist/assets/{file-plus-CYD2zaaI.js → file-plus-DTVYnXCN.js} +1 -1
- package/web-app/dist/assets/{globe-6w-hnQkL.js → globe-0mUzKYDe.js} +1 -1
- package/web-app/dist/assets/{hammer-BpqtautL.js → hammer-BMHZg3YX.js} +1 -1
- package/web-app/dist/assets/{index-Dzs-9EgJ.js → index-BvOTvjax.js} +3 -3
- package/web-app/dist/assets/{layers-D5hd7jb7.js → layers-Df7TdcWB.js} +1 -1
- package/web-app/dist/assets/{loader-circle-C6Y9x_7H.js → loader-circle-kPsVfrSY.js} +1 -1
- package/web-app/dist/assets/{lock-D51L7rYh.js → lock-CXYcbEc5.js} +1 -1
- package/web-app/dist/assets/{package-BJF8hkP8.js → package-Cqhua1ID.js} +1 -1
- package/web-app/dist/assets/{plus-D5kUQ79n.js → plus-lseXhsn-.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-BKdlCa7F.js → refresh-cw-OZriI6gD.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-_bd_YI1e.js → rotate-ccw-CKCfjPg8.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DbkegIxF.js → scroll-text-DoVyyfKb.js} +1 -1
- package/web-app/dist/assets/{server-DAwqFIsq.js → server-DGy7TflW.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BuR1tPHu.js → shield-alert-BCzRcMXi.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BF6p3mRd.js → thumbs-up-C_znJd5g.js} +1 -1
- package/web-app/dist/assets/{trash-2-BVpnkqqz.js → trash-2-BosCbeeA.js} +1 -1
- package/web-app/dist/assets/{trending-down-DpsDvRwW.js → trending-down-CkR5zDkV.js} +1 -1
- package/web-app/dist/assets/{trending-up-mFogTjt3.js → trending-up-DpUIfOH4.js} +1 -1
- package/web-app/dist/assets/{upload-4T8zpBsi.js → upload-CH9aKc8L.js} +1 -1
- package/web-app/dist/assets/{usePolling-DPXQv8WO.js → usePolling-pzxrHJeg.js} +1 -1
- package/web-app/dist/assets/{user-BYGIFaTm.js → user-B7OHa-VQ.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/dashboard/run.py +0 -63
- package/docs/openclaw-integration.md +0 -52
- package/docs/v10/HANDOFF-NEXT-WEEK.md +0 -40
- package/docs/v10/MORNING-BRIEF-1003.md +0 -25
- package/docs/v10/MORNING-BRIEF.md +0 -52
- package/docs/v10/TODO.md +0 -35
- package/mcp/resources.py +0 -351
- package/mcp/tools.py +0 -200
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.
|
|
6
|
+
# Loki Mode v11.6.0
|
|
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.
|
|
486
|
+
**v11.6.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
11.
|
|
1
|
+
11.6.0
|
package/autonomy/lib/chat.sh
CHANGED
|
@@ -107,7 +107,7 @@ _chat_attach_banner() {
|
|
|
107
107
|
_chat_send() {
|
|
108
108
|
local mode="$1" text="$2"
|
|
109
109
|
if [ "$_CHAT_PROVIDER" = "claude" ]; then
|
|
110
|
-
command -v claude >/dev/null 2>&1 || { echo "loki chat: claude CLI not found" >&2; return 1; }
|
|
110
|
+
command -v claude >/dev/null 2>&1 || { echo "loki chat: claude CLI not found. Fix (same as loki doctor):" >&2; _loki_req_fix_line claude >&2; return 1; }
|
|
111
111
|
local -a args=(-p "$text" --append-system-prompt "$_LOKI_CHAT_SYSTEM_PROMPT")
|
|
112
112
|
if [ "$mode" = "plan" ]; then args+=(--permission-mode plan); else args+=(--permission-mode acceptEdits); fi
|
|
113
113
|
[ -n "$_CHAT_MODEL" ] && args+=(--model "$_CHAT_MODEL")
|
|
@@ -197,10 +197,13 @@ EOF
|
|
|
197
197
|
# /run: the exact run the shell would give: loki start with this session's provider and model.
|
|
198
198
|
# The summary prints at the end of the run; chat stays open afterwards.
|
|
199
199
|
_chat_run_start() {
|
|
200
|
-
local loki="$1" input="$2" rc=0
|
|
200
|
+
local loki="$1" input="$2" rc=0 t0=$SECONDS
|
|
201
201
|
local -a args=("start" "$input" --provider "$_CHAT_PROVIDER")
|
|
202
202
|
[ -n "$_CHAT_MODEL" ] && args+=(--model "$_CHAT_MODEL")
|
|
203
203
|
"$loki" "${args[@]}" || rc=$?
|
|
204
|
+
# HANDOFF: same file loki start wrote, so chat and the shell show one review view
|
|
205
|
+
# (only when written during this run; a stale file from an earlier run is never shown)
|
|
206
|
+
if [ -f ".loki/review/HANDOFF.md" ] && [ -n "$(find ".loki/review/HANDOFF.md" -mmin "-$(( (SECONDS - t0) / 60 + 1 ))" 2>/dev/null)" ]; then cat ".loki/review/HANDOFF.md"; fi
|
|
204
207
|
echo "(run finished, exit $rc; chat is still open)"
|
|
205
208
|
return 0
|
|
206
209
|
}
|
|
@@ -224,7 +227,7 @@ cmd_chat() {
|
|
|
224
227
|
done
|
|
225
228
|
|
|
226
229
|
if [ "$tui" = "1" ]; then
|
|
227
|
-
command -v claude >/dev/null 2>&1 || { echo "loki chat: claude CLI not found" >&2; return 1; }
|
|
230
|
+
command -v claude >/dev/null 2>&1 || { echo "loki chat: claude CLI not found. Fix (same as loki doctor):" >&2; _loki_req_fix_line claude >&2; return 1; }
|
|
228
231
|
local -a targs=(--append-system-prompt "$_LOKI_CHAT_SYSTEM_PROMPT")
|
|
229
232
|
[ -n "${LOKI_MODEL:-}" ] && targs+=(--model "$LOKI_MODEL")
|
|
230
233
|
exec claude "${targs[@]}"
|
|
@@ -95,6 +95,14 @@ _e10_local_push() {
|
|
|
95
95
|
log_warn "Not pushing branch '$branch': it is (or may be) the default branch of $origin."
|
|
96
96
|
return 2
|
|
97
97
|
fi
|
|
98
|
+
# RECOVERY: remote already at the local commit means a prior attempt landed; push nothing.
|
|
99
|
+
local want have
|
|
100
|
+
want="$(_e10_git -C "$dir" rev-parse -q --verify "refs/heads/$branch" 2>/dev/null)" || want=""
|
|
101
|
+
have="$(_e10_git ls-remote "$origin" "refs/heads/$branch" 2>/dev/null | awk '{print $1; exit}')" || have=""
|
|
102
|
+
if [ -n "$want" ] && [ "$want" = "$have" ]; then
|
|
103
|
+
log_info "push skipped: remote already has $branch at ${want:0:12}"
|
|
104
|
+
return 0
|
|
105
|
+
fi
|
|
98
106
|
tmp="$(mktemp -d "${TMPDIR:-/tmp}/loki-push.XXXXXX")" || return 1
|
|
99
107
|
if _e10_git init -q --template= "$tmp" >/dev/null 2>&1 \
|
|
100
108
|
&& _e10_git -C "$tmp" fetch -q --no-tags --update-shallow "$dir" \
|
|
@@ -138,7 +146,17 @@ case "$mode" in
|
|
|
138
146
|
printf 'local://%s#%s\n' "$_LOKI_PINNED_ORIGIN" "$branch"
|
|
139
147
|
exit 0
|
|
140
148
|
fi
|
|
141
|
-
|
|
149
|
+
# RECOVERY: a resumed publish skips the push when the remote branch is already at the local commit.
|
|
150
|
+
_e10_want="$(_e10_git -C "$dir" rev-parse -q --verify "refs/heads/$branch" 2>/dev/null)" || _e10_want=""
|
|
151
|
+
_e10_have=""
|
|
152
|
+
case "$branch" in main | master | HEAD) ;; *)
|
|
153
|
+
_e10_have="$(_e10_gh api "repos/$_e10_repo/git/ref/heads/$branch" --jq .object.sha 2>/dev/null)" || _e10_have="" ;;
|
|
154
|
+
esac
|
|
155
|
+
if [ -n "$_e10_want" ] && [ "$_e10_want" = "$_e10_have" ]; then
|
|
156
|
+
log_info "push skipped: remote already has $branch at ${_e10_want:0:12}"
|
|
157
|
+
else
|
|
158
|
+
_loki_trusted_push _loki_with_github_tokens "$dir" "$branch" || die "push refused or failed (rc=$?)"
|
|
159
|
+
fi
|
|
142
160
|
url="$(_e10_gh pr list --repo "$_e10_repo" --head "$branch" --state open --json url --jq '.[0].url')" \
|
|
143
161
|
|| die "gh pr list failed"
|
|
144
162
|
if [ -z "$url" ] || [ "$url" = "null" ]; then
|
|
@@ -31,7 +31,7 @@ help_core_screen() {
|
|
|
31
31
|
echo " agents Agent roles and routing (route shows where a task would go)"
|
|
32
32
|
echo " doctor [--json] Check your setup is ready"
|
|
33
33
|
echo ""
|
|
34
|
-
echo "Options for 'start': --provider NAME, --model ID, --budget USD, --isolation LVL (isolation dial: none | worktree | docker)"
|
|
34
|
+
echo "Options for 'start': --provider NAME, --model ID, --budget USD (default cap $(loki_budget_default_usd 2>/dev/null)), --isolation LVL (isolation dial: none | worktree | docker)"
|
|
35
35
|
echo "Also: cost / estimate (spend before you build), resume (continue a paused or interrupted run)"
|
|
36
36
|
echo "Exit codes: docs/exit-codes.md"
|
|
37
37
|
echo ""
|
|
@@ -40,6 +40,21 @@ from efficiency_cost import collect_efficiency as _collect_efficiency # noqa: E
|
|
|
40
40
|
import effort_estimator # noqa: E402
|
|
41
41
|
from tree_digest import MANIFEST_VERSION, compute_tree_digest # noqa: E402
|
|
42
42
|
from workspace_diff import collect_workspace_diff # noqa: E402
|
|
43
|
+
import importlib.util as _ilu # noqa: E402
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _load_proof_verify_mod():
|
|
47
|
+
# proof-verify.py is hyphenated (not importable); it owns the verification record.
|
|
48
|
+
spec = _ilu.spec_from_file_location(
|
|
49
|
+
"loki_proof_verify", os.path.join(os.path.dirname(os.path.abspath(__file__)), "proof-verify.py"))
|
|
50
|
+
mod = _ilu.module_from_spec(spec)
|
|
51
|
+
spec.loader.exec_module(mod)
|
|
52
|
+
return mod
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
_PV = _load_proof_verify_mod()
|
|
56
|
+
_vr_capture_environment = _PV.capture_environment
|
|
57
|
+
_vr_git_dirty = _PV.git_dirty
|
|
43
58
|
|
|
44
59
|
|
|
45
60
|
# ---------------------------------------------------------------------------
|
|
@@ -1121,8 +1136,6 @@ def _empty_tree_sha(repo_dir):
|
|
|
1121
1136
|
# collect_workspace_diff), so uncommitted work is covered.
|
|
1122
1137
|
_TI_CFG_ALWAYS = re.compile(r"(^|/)(conftest\.py|\.?pytest\.(?:ini|toml)|tox\.ini|jest\.config\.[\w.]+|vitest\.config\.[\w.]+|\.mocharc[\w.]*)$")
|
|
1123
1138
|
_TI_CFG_SHARED = re.compile(r"(^|/)(setup\.cfg|pyproject\.toml|package\.json)$")
|
|
1124
|
-
_TI_TEST_FILE = re.compile(
|
|
1125
|
-
r"(^|/)(tests?|__tests__|spec|specs)/|\.(test|spec)\.[\w]+$|(^|/)test_[^/]*\.py$|_test\.(py|go|rs)$|(^|/)conftest\.py$")
|
|
1126
1139
|
_TI_SKIP_JS = re.compile(
|
|
1127
1140
|
# options object only as the 2nd argument: title (string or identifier), then `, {`
|
|
1128
1141
|
r"\b(test|it|describe|suite|context|specify)\s*\(\s*(?:'[^'\n]*'|\"[^\"\n]*\"|`[^`\n]*`|[\w.$]+)\s*,\s*\{[^}]*\b(skip|todo)\s*:\s*(?!(?:false|0|null|undefined)\b)\S"
|
|
@@ -1270,7 +1283,7 @@ def _collect_tests_integrity(target_dir, base):
|
|
|
1270
1283
|
if u and not u.startswith(".loki/"):
|
|
1271
1284
|
entries.append(("A", u, u))
|
|
1272
1285
|
for st, old, new in entries:
|
|
1273
|
-
if st in ("D", "R") and
|
|
1286
|
+
if st in ("D", "R") and _PV._TEST_FILE.search(old):
|
|
1274
1287
|
weakened.append("test file %s: %s" % ("deleted" if st == "D" else "renamed", old))
|
|
1275
1288
|
if not greenfield:
|
|
1276
1289
|
for st, old, new in entries:
|
|
@@ -1310,7 +1323,7 @@ def _collect_tests_integrity(target_dir, base):
|
|
|
1310
1323
|
edited.append(cur)
|
|
1311
1324
|
cur, rx, removed_assert = None, None, False
|
|
1312
1325
|
elif line.startswith("+++ b/"):
|
|
1313
|
-
cur = line[6:] if
|
|
1326
|
+
cur = line[6:] if _PV._TEST_FILE.search(line[6:]) else None
|
|
1314
1327
|
rx = _ti_skip_re(cur) if cur else None
|
|
1315
1328
|
elif cur and line.startswith("+") and rx and rx.search(line):
|
|
1316
1329
|
weakened.append("skip added in %s" % cur)
|
|
@@ -1318,7 +1331,7 @@ def _collect_tests_integrity(target_dir, base):
|
|
|
1318
1331
|
and _TI_ASSERT.search(line):
|
|
1319
1332
|
removed_assert = True
|
|
1320
1333
|
for u in untracked.split("\0"):
|
|
1321
|
-
if not u or u.startswith(".loki/") or not
|
|
1334
|
+
if not u or u.startswith(".loki/") or not _PV._TEST_FILE.search(u):
|
|
1322
1335
|
continue
|
|
1323
1336
|
rx = _ti_skip_re(u)
|
|
1324
1337
|
if not rx:
|
|
@@ -1625,6 +1638,9 @@ def _build_proof(args, loki_dir, target_dir, repo_root):
|
|
|
1625
1638
|
# recompute it after runner exit to reject proofs followed by code edits.
|
|
1626
1639
|
"tree_sha256": compute_tree_digest(target_dir),
|
|
1627
1640
|
"tree_manifest_version": MANIFEST_VERSION,
|
|
1641
|
+
# Execution validity (docs/PROOF-PASSPORT.md): whether the tree
|
|
1642
|
+
# was dirty when the checks ran. None when git could not answer.
|
|
1643
|
+
"dirty": _vr_git_dirty(target_dir),
|
|
1628
1644
|
}
|
|
1629
1645
|
facts = {
|
|
1630
1646
|
"git": git_facts,
|
|
@@ -1663,6 +1679,8 @@ def _build_proof(args, loki_dir, target_dir, repo_root):
|
|
|
1663
1679
|
# Descriptive; NOT read by _compute_headline (gating is founder-gated).
|
|
1664
1680
|
"healthcheck": healthcheck,
|
|
1665
1681
|
"cost": cost,
|
|
1682
|
+
# Environment the checks ran in (measured at generation time).
|
|
1683
|
+
"environment": _vr_capture_environment(),
|
|
1666
1684
|
"meta": {
|
|
1667
1685
|
"run_id": run_id,
|
|
1668
1686
|
"loki_version": loki_version,
|