loki-mode 11.17.34 → 11.17.35
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/proof-generator.py +53 -0
- package/autonomy/loki +171 -14
- package/completions/_loki +1 -0
- package/completions/loki.bash +1 -1
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/v10/BOARD.md +4 -4
- package/docs/v10/DECISIONS.md +8 -0
- package/docs/v10/PROGRESS.md +3 -0
- package/loki-ts/dist/loki.js +927 -927
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +453 -412
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-o3gtaCnU.js → AdminPage-DtJ40-0A.js} +1 -1
- package/web-app/dist/assets/{Avatar-C02t-Irl.js → Avatar-BroDCINh.js} +1 -1
- package/web-app/dist/assets/{Badge-BuN80MKq.js → Badge-BS02diTl.js} +1 -1
- package/web-app/dist/assets/{Button-lPXsKVcs.js → Button-DV7QKQIh.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-8CNxkZSh.js → CockpitPage-_jJB0SSp.js} +1 -1
- package/web-app/dist/assets/{ComparePage-j-XhFiwH.js → ComparePage-9G53m6VG.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-D8nyc_y_.js → ErrorBoundary-BxAWorBT.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-DtTSMxZm.js → EvidenceReceiptPanel-D5_6xbqU.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-Bzmm3gBY.js → GitHubIssuesPanel-D4lz3Q9l.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-Dh6vSHLE.js → GitHubPRsPanel-BDHX9d5m.js} +1 -1
- package/web-app/dist/assets/{HomePage-CKKPOMOg.js → HomePage-DP1R90H7.js} +2 -2
- package/web-app/dist/assets/{LoginPage-49FrYkL9.js → LoginPage-DWMnArZX.js} +1 -1
- package/web-app/dist/assets/{MagicPage-D5psAu69.js → MagicPage-DVvZ-ytQ.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-oQXV5q4J.js → MetricsPage-BM5Zifpz.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-C2hj6k1f.js → NotFoundPage-CYrJ2hCM.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-Bo8ocjwn.js → ProjectPage-C_KU_B2Z.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-QUhbz991.js → ProjectsPage-BKOoyezO.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-6XW8I3LO.js → SettingsPage-D0YIMzR4.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-9CHGu9uW.js → ShowcasePage-AgAwQE4Q.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-gZZK7T45.js → SystemSettingsPage-Cin_takd.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-DSlKvZhA.js → TeamsPage-BhpuLv8p.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-BVDR5mF2.js → TemplatesPage-DysLVH1s.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-DnOFdmTG.js → TerminalOutput-BNwZci_n.js} +1 -1
- package/web-app/dist/assets/{activity-D22UFJWA.js → activity-CWziiy0I.js} +1 -1
- package/web-app/dist/assets/{bell-B2Mfgp26.js → bell-DXJj9c93.js} +1 -1
- package/web-app/dist/assets/{bot-CTXo6aac.js → bot-BXjVlRf9.js} +1 -1
- package/web-app/dist/assets/{check-D9kJod1H.js → check-B0m-S8D_.js} +1 -1
- package/web-app/dist/assets/{chevron-left-XI4pnrlY.js → chevron-left-kFvUdte6.js} +1 -1
- package/web-app/dist/assets/{circle-alert-CvS3mi0t.js → circle-alert-CxRoiGmA.js} +1 -1
- package/web-app/dist/assets/{clock-CCgwQ80p.js → clock-BJ39Nl09.js} +1 -1
- package/web-app/dist/assets/{cloud-S-SuEsEp.js → cloud-DK2q56ot.js} +1 -1
- package/web-app/dist/assets/{code-xml-PRnhUKWP.js → code-xml-BQUCyHmu.js} +1 -1
- package/web-app/dist/assets/{database-C_a7H_3N.js → database-CGGMJBY-.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-FDCzdLrB.js → dollar-sign-C6gRmaFY.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-28-hDPSO.js → file-code-corner-Cf25WTZR.js} +1 -1
- package/web-app/dist/assets/{file-plus-c0yygSC8.js → file-plus-D3z0a6s8.js} +1 -1
- package/web-app/dist/assets/{globe-DOA9Y_1n.js → globe-Ft1PAFtm.js} +1 -1
- package/web-app/dist/assets/{hammer-Omzy4vB3.js → hammer-uSNPcG6-.js} +1 -1
- package/web-app/dist/assets/{index-Dp6emuTo.js → index-CVdTpox_.js} +3 -3
- package/web-app/dist/assets/{layers-D7ZjWXJQ.js → layers-Dc50swfm.js} +1 -1
- package/web-app/dist/assets/{loader-circle-CJ2SKm0h.js → loader-circle-VEyejUbH.js} +1 -1
- package/web-app/dist/assets/{lock-HKmv1nIN.js → lock-DjSnxn6I.js} +1 -1
- package/web-app/dist/assets/{package-FQl71HNO.js → package-DZoaxJbK.js} +1 -1
- package/web-app/dist/assets/{plus-DY8mlU6I.js → plus-CfEwV_6v.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-CJ_pkRQQ.js → refresh-cw-8UjV3w0I.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-rGU_udZ1.js → rotate-ccw-Br7s9zAf.js} +1 -1
- package/web-app/dist/assets/{scroll-text-CeVAfOXM.js → scroll-text-CuAQTRV9.js} +1 -1
- package/web-app/dist/assets/{server-D-N_u9OT.js → server-BDj53pad.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CJfx3HCX.js → shield-alert-Yq8Exf7A.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BrC-E9mS.js → thumbs-up-DbolTUui.js} +1 -1
- package/web-app/dist/assets/{trash-2-Bb3mW1oq.js → trash-2-Band0V5Q.js} +1 -1
- package/web-app/dist/assets/{trending-down-CrgUJZLA.js → trending-down-tVJY7vOw.js} +1 -1
- package/web-app/dist/assets/{trending-up-Dk_GS57K.js → trending-up-DzJ3qeYe.js} +1 -1
- package/web-app/dist/assets/{upload-BAxHyFqH.js → upload-kvP9eEgy.js} +1 -1
- package/web-app/dist/assets/{usePolling-CkTdc2YU.js → usePolling-CBydUyUd.js} +1 -1
- package/web-app/dist/assets/{user-Dr6XCReg.js → user-CglUAW3P.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/web-app/server.py +164 -132
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.35
|
|
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.35 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
11.17.
|
|
1
|
+
11.17.35
|
|
@@ -782,6 +782,8 @@ def _collect_security(loki_dir):
|
|
|
782
782
|
make here. Stated explicitly because those two say so in their own
|
|
783
783
|
docstrings and this one did not, leaving the behaviour to be inferred from
|
|
784
784
|
silence -- which is the exact failure the honesty ledger exists to prevent.
|
|
785
|
+
A scan that ran and came back clean IS read by _exogenous_corroboration
|
|
786
|
+
(TEN-GATES-10): it can only stand beside a green suite, never cause a gap.
|
|
785
787
|
"""
|
|
786
788
|
out = {
|
|
787
789
|
"ran": False, "total": 0, "active": 0, "waived": 0,
|
|
@@ -853,6 +855,8 @@ def _collect_functional(loki_dir):
|
|
|
853
855
|
NOT change what "Verified" means. Making functional-satisfaction gate the green
|
|
854
856
|
headline is a trust-semantics product decision (council + founder), the second
|
|
855
857
|
half of FV-2. Recording it first lets the signal be seen and validated safely.
|
|
858
|
+
Exception (TEN-GATES-10): functional_status verified is read by
|
|
859
|
+
_exogenous_corroboration as agent-independent evidence beside a green suite.
|
|
856
860
|
"""
|
|
857
861
|
out = {"ran": False, "functional_status": "not_run",
|
|
858
862
|
"passed": 0, "failed": 0, "inconclusive": 0}
|
|
@@ -892,6 +896,8 @@ def _collect_healthcheck(loki_dir):
|
|
|
892
896
|
NOT read by _compute_headline / _compute_degraded, so it does not change what
|
|
893
897
|
"Verified" means. Gating on it is the founder-gated trust decision (mirrors the
|
|
894
898
|
FV-2 opt-in gate). ponytail: reuses the health.json app-runner already writes.
|
|
899
|
+
Exception (TEN-GATES-10): ok:true is read by _exogenous_corroboration as
|
|
900
|
+
agent-independent evidence beside a green suite.
|
|
895
901
|
"""
|
|
896
902
|
out = {"ran": False, "ok": False, "status": "not_run", "checked_at": ""}
|
|
897
903
|
raw = _read_json(
|
|
@@ -1960,14 +1966,61 @@ def _compute_degraded(facts):
|
|
|
1960
1966
|
if rec.get("state") == "gap":
|
|
1961
1967
|
out.append({"item": "functionality:%s" % axis, "status": "failed",
|
|
1962
1968
|
"reason": rec.get("reason") or "axis disproven"})
|
|
1969
|
+
# TEN-GATES-10 (D105): the agent writes both the code and the suite, so a
|
|
1970
|
+
# green suite alone is the agent grading its own work. When the suite is the
|
|
1971
|
+
# ONLY passing fact, record the gap here (pre-headline, so proof-verify.py
|
|
1972
|
+
# re-derives the same amber headline from the recorded ledger) and VERIFIED
|
|
1973
|
+
# becomes VERIFIED WITH GAPS. LOKI_PROOF_REQUIRE_EXOGENOUS=0 opts out.
|
|
1974
|
+
tests_verified = (
|
|
1975
|
+
tests.get("status") == "verified"
|
|
1976
|
+
and bool(tests.get("command"))
|
|
1977
|
+
and tests.get("exit_code") == 0
|
|
1978
|
+
)
|
|
1979
|
+
if (tests_verified
|
|
1980
|
+
and os.environ.get("LOKI_PROOF_REQUIRE_EXOGENOUS", "1").strip() != "0"
|
|
1981
|
+
and not _exogenous_corroboration(facts)):
|
|
1982
|
+
out.append({"item": "exogenous_evidence", "status": "not_run",
|
|
1983
|
+
"reason": "no agent-independent evidence (only the agent's "
|
|
1984
|
+
"own test suite passed)"})
|
|
1963
1985
|
return out
|
|
1964
1986
|
|
|
1965
1987
|
|
|
1988
|
+
def _exogenous_corroboration(facts):
|
|
1989
|
+
"""Names of agent-independent facts that ran and passed (TEN-GATES-10).
|
|
1990
|
+
|
|
1991
|
+
Counts: build verified, healthcheck ok, functional verified, a security scan
|
|
1992
|
+
that actually ran and came back clean, or an EXOGENOUS quality gate that
|
|
1993
|
+
passed. An advisory (model-authored) gate pass never counts: it is the same
|
|
1994
|
+
plausibility signal the agent's own suite already is. Absent facts count as
|
|
1995
|
+
nothing (fail-closed).
|
|
1996
|
+
"""
|
|
1997
|
+
names = []
|
|
1998
|
+
if (facts.get("build") or {}).get("status") == "verified":
|
|
1999
|
+
names.append("build")
|
|
2000
|
+
hc = facts.get("healthcheck") or {}
|
|
2001
|
+
if hc.get("ran") and hc.get("ok") is True:
|
|
2002
|
+
names.append("healthcheck")
|
|
2003
|
+
fn = facts.get("functional") or {}
|
|
2004
|
+
if fn.get("ran") and str(fn.get("functional_status") or "").lower() in (
|
|
2005
|
+
"verified", "passed"):
|
|
2006
|
+
names.append("functional")
|
|
2007
|
+
sec = facts.get("security") or {}
|
|
2008
|
+
if sec.get("ran") and sec.get("status") == "clean":
|
|
2009
|
+
names.append("security")
|
|
2010
|
+
for g in facts.get("quality_gates") or []:
|
|
2011
|
+
if g.get("status") == "passed" and _is_exogenous(g):
|
|
2012
|
+
names.append("quality_gate:%s" % g.get("name", ""))
|
|
2013
|
+
return names
|
|
2014
|
+
|
|
2015
|
+
|
|
1966
2016
|
def _compute_headline(facts, degraded):
|
|
1967
2017
|
"""Deterministic headline. NEVER green from an LLM opinion or a bare
|
|
1968
2018
|
pass:true. Rules:
|
|
1969
2019
|
- VERIFIED only when tests.status == verified AND there are no degraded
|
|
1970
2020
|
items AND the diff is non-empty AND tests recorded a real command.
|
|
2021
|
+
(TEN-GATES-10: _compute_degraded adds an exogenous_evidence gap when
|
|
2022
|
+
the suite is the only passing fact, so VERIFIED also needs one
|
|
2023
|
+
agent-independent fact; see _exogenous_corroboration.)
|
|
1971
2024
|
- VERIFIED WITH GAPS when some facts verified but degraded is non-empty.
|
|
1972
2025
|
- NOT VERIFIED otherwise.
|
|
1973
2026
|
"""
|
package/autonomy/loki
CHANGED
|
@@ -10009,7 +10009,7 @@ _deploy_latest_receipt() {
|
|
|
10009
10009
|
return 0
|
|
10010
10010
|
}
|
|
10011
10011
|
|
|
10012
|
-
# _deploy_record <dir> <command> <exit_code> <run_id> <anchor_sha> [state] [health_status] [health_url] [rb_attempted] [rb_exit] [receipt_sha256] [started_at] [finished_at] [target] [canary] [post_rollback_health] [health_http_code] [health_match] [tree_sha] [destination] [deployed_url] [health_url_source]
|
|
10012
|
+
# _deploy_record <dir> <command> <exit_code> <run_id> <anchor_sha> [state] [health_status] [health_url] [rb_attempted] [rb_exit] [receipt_sha256] [started_at] [finished_at] [target] [canary] [post_rollback_health] [health_http_code] [health_match] [tree_sha] [destination] [deployed_url] [health_url_source] [env_keys_csv] [env_source]
|
|
10013
10013
|
# Writes the executed deploy's own record, then signs it (loki.deploy/1, Ed25519 via the
|
|
10014
10014
|
# receipt signer in loki-ts/src/util/receipt_signer.ts) so it is bound to the receipt that
|
|
10015
10015
|
# authorized it; `loki verify <record>` re-checks it offline. An unsigned record is reported
|
|
@@ -10034,6 +10034,9 @@ _deploy_record() {
|
|
|
10034
10034
|
local receipt_sha="${11:-}" started_at="${12:-}" finished_at="${13:-}" target="${14:-}" canary="${15:-false}"
|
|
10035
10035
|
local post_rb="${16:-unchecked}" hcode_rec="${17:-}" hmatch="${18:-}" tree_sha="${19:-}" dest_rec="${20:-}"
|
|
10036
10036
|
local deployed_url="${21:-}" hsrc="${22:-}"
|
|
10037
|
+
# --env-file: key NAMES only (comma-joined, validated identifiers) and the file
|
|
10038
|
+
# path. A value is never passed here, so the signed record cannot carry one.
|
|
10039
|
+
local env_keys_csv="${23:-}" env_source="${24:-}"
|
|
10037
10040
|
local ddir="$dir/.loki/deploys"
|
|
10038
10041
|
[ -d "${LOKI_DIR:-}" ] && ddir="${LOKI_DIR}/deploys"
|
|
10039
10042
|
mkdir -p "$ddir" 2>/dev/null || return 0
|
|
@@ -10042,6 +10045,7 @@ _deploy_record() {
|
|
|
10042
10045
|
DR_STATE="$anchor_state" DR_HS="$health_status" DR_HU="$health_url" \
|
|
10043
10046
|
DR_RBA="$rb_attempted" DR_RBX="$rb_exit" DR_RSHA="$receipt_sha" DR_T0="$started_at" \
|
|
10044
10047
|
DR_T1="$finished_at" DR_TGT="$target" DR_CAN="$canary" DR_PRB="$post_rb" DR_HC="$hcode_rec" DR_HM="$hmatch" DR_TREE="$tree_sha" DR_DEST="$dest_rec" DR_DURL="$deployed_url" DR_HSRC="$hsrc" \
|
|
10048
|
+
DR_ENVK="$env_keys_csv" DR_ENVS="$env_source" \
|
|
10045
10049
|
python3 -c '
|
|
10046
10050
|
import json, os, datetime
|
|
10047
10051
|
state = os.environ.get("DR_STATE") or "anchored"
|
|
@@ -10073,6 +10077,8 @@ json.dump({
|
|
|
10073
10077
|
"destination": os.environ.get("DR_DEST", ""),
|
|
10074
10078
|
"deployed_url": os.environ.get("DR_DURL", ""),
|
|
10075
10079
|
"health_url_source": os.environ.get("DR_HSRC", ""),
|
|
10080
|
+
"env_keys": sorted(k for k in os.environ.get("DR_ENVK", "").split(",") if k),
|
|
10081
|
+
"env_source": os.environ.get("DR_ENVS", ""),
|
|
10076
10082
|
"health_http_code": int(os.environ["DR_HC"]) if os.environ.get("DR_HC", "").isdigit() else None,
|
|
10077
10083
|
}, open(os.environ["DR_OUT"], "w"), indent=2)
|
|
10078
10084
|
' 2>/dev/null || return 0
|
|
@@ -10241,6 +10247,59 @@ sys.exit(0 if ok else 1)' "$f" "$sha" 2>/dev/null || continue
|
|
|
10241
10247
|
return 1
|
|
10242
10248
|
}
|
|
10243
10249
|
|
|
10250
|
+
# _deploy_env_load <env_file> <example_file>
|
|
10251
|
+
# Parses KEY=VALUE lines with NO shell evaluation (python, never source/eval) and
|
|
10252
|
+
# writes NUL-terminated records to stdout: one "KEY=VALUE" per key (sorted by
|
|
10253
|
+
# key), then "__LOKI_ENV_OK__". On any problem it writes a single
|
|
10254
|
+
# "__LOKI_ENV_ERR__:<reason>" record instead. A reason names keys and line
|
|
10255
|
+
# numbers only, never a value. When <example_file> exists, every key it lists
|
|
10256
|
+
# must be present in <env_file>, else the reason names the missing keys.
|
|
10257
|
+
_deploy_env_load() {
|
|
10258
|
+
python3 - "$1" "$2" <<'PYEOF'
|
|
10259
|
+
import os, re, sys
|
|
10260
|
+
KEY = re.compile(r"[A-Za-z_][A-Za-z0-9_]*\Z")
|
|
10261
|
+
def out(s):
|
|
10262
|
+
sys.stdout.buffer.write(s.encode("utf-8", "surrogateescape") + b"\0")
|
|
10263
|
+
def parse(path, label):
|
|
10264
|
+
found = {}
|
|
10265
|
+
with open(path, encoding="utf-8", errors="surrogateescape") as fh:
|
|
10266
|
+
for n, raw in enumerate(fh, 1):
|
|
10267
|
+
line = raw.strip()
|
|
10268
|
+
if not line or line.startswith("#"):
|
|
10269
|
+
continue
|
|
10270
|
+
if line.startswith("export "):
|
|
10271
|
+
line = line[7:].lstrip()
|
|
10272
|
+
if "=" not in line:
|
|
10273
|
+
raise ValueError("%s line %d is not KEY=VALUE" % (label, n))
|
|
10274
|
+
k, v = line.split("=", 1)
|
|
10275
|
+
k, v = k.strip(), v.strip()
|
|
10276
|
+
if not KEY.match(k):
|
|
10277
|
+
raise ValueError("%s line %d has an invalid key name" % (label, n))
|
|
10278
|
+
if len(v) >= 2 and v[0] == v[-1] and v[0] in "\"'":
|
|
10279
|
+
v = v[1:-1]
|
|
10280
|
+
elif " #" in v:
|
|
10281
|
+
v = v.split(" #", 1)[0].rstrip()
|
|
10282
|
+
if "\0" in v:
|
|
10283
|
+
raise ValueError("%s key %s has a NUL byte in its value" % (label, k))
|
|
10284
|
+
found[k] = v
|
|
10285
|
+
return found
|
|
10286
|
+
try:
|
|
10287
|
+
env = parse(sys.argv[1], "env file")
|
|
10288
|
+
if not env:
|
|
10289
|
+
raise ValueError("env file has no KEY=VALUE entries")
|
|
10290
|
+
if os.path.isfile(sys.argv[2]):
|
|
10291
|
+
missing = sorted(set(parse(sys.argv[2], ".env.example")) - set(env))
|
|
10292
|
+
if missing:
|
|
10293
|
+
raise ValueError("env file is missing key(s) listed in .env.example: " + ", ".join(missing))
|
|
10294
|
+
except (OSError, ValueError) as e:
|
|
10295
|
+
out("__LOKI_ENV_ERR__:" + (str(e) if isinstance(e, ValueError) else "cannot read the env file"))
|
|
10296
|
+
sys.exit(0)
|
|
10297
|
+
for k in sorted(env):
|
|
10298
|
+
out(k + "=" + env[k])
|
|
10299
|
+
out("__LOKI_ENV_OK__")
|
|
10300
|
+
PYEOF
|
|
10301
|
+
}
|
|
10302
|
+
|
|
10244
10303
|
# _deploy_try_execute <dir> <type>
|
|
10245
10304
|
# The ONLY place a deploy command is ever run. Evaluates the gate, and either
|
|
10246
10305
|
# executes + records, or REFUSES naming every failed check. Returns the deploy
|
|
@@ -10290,6 +10349,52 @@ _deploy_try_execute() {
|
|
|
10290
10349
|
esac
|
|
10291
10350
|
fi
|
|
10292
10351
|
|
|
10352
|
+
# --env-file: values live ONLY in env_pairs and the provider argv. Stdout, the
|
|
10353
|
+
# 'Running:' line and the record carry names (K=***), never values.
|
|
10354
|
+
# Documented verbs only: Vercel '-e K=V' per key on the deploy itself; Fly
|
|
10355
|
+
# 'fly secrets set --stage K=V ...' before 'fly deploy'; Netlify
|
|
10356
|
+
# 'netlify env:import FILE' and Cloudflare 'wrangler secret bulk FILE' before
|
|
10357
|
+
# the deploy (the provider reads FILE, so no value enters argv).
|
|
10358
|
+
local env_file="${_LOKI_DEPLOY_ENV_FILE:-}" env_kind="" env_keys="" env_disp="" env_pre_disp="" _env_rec _env_ok=false _env_err=""
|
|
10359
|
+
local -a env_pairs=() env_pre_argv=()
|
|
10360
|
+
if [ -n "$env_file" ]; then
|
|
10361
|
+
case "$command" in
|
|
10362
|
+
"vercel --prod") env_kind="vercel" ;;
|
|
10363
|
+
"fly deploy") env_kind="fly" ;;
|
|
10364
|
+
"netlify deploy --prod") env_kind="netlify" ;;
|
|
10365
|
+
"wrangler deploy") env_kind="cloudflare" ;;
|
|
10366
|
+
*)
|
|
10367
|
+
echo -e "${RED}REFUSED: --env-file is not supported for: ${command}${NC}" >&2
|
|
10368
|
+
echo " No documented env verb is wired for this provider. Nothing was run." >&2
|
|
10369
|
+
return 1
|
|
10370
|
+
;;
|
|
10371
|
+
esac
|
|
10372
|
+
while IFS= read -r -d '' _env_rec; do
|
|
10373
|
+
case "$_env_rec" in
|
|
10374
|
+
__LOKI_ENV_OK__) _env_ok=true ;;
|
|
10375
|
+
__LOKI_ENV_ERR__:*) _env_err="${_env_rec#__LOKI_ENV_ERR__:}" ;;
|
|
10376
|
+
*) env_pairs+=("$_env_rec") ;;
|
|
10377
|
+
esac
|
|
10378
|
+
done < <(_deploy_env_load "$env_file" "$dir/.env.example")
|
|
10379
|
+
if [ "$_env_ok" != true ]; then
|
|
10380
|
+
echo -e "${RED}REFUSED: --env-file: ${_env_err:-the env file could not be parsed}${NC}" >&2
|
|
10381
|
+
echo " Nothing was run." >&2
|
|
10382
|
+
return 1
|
|
10383
|
+
fi
|
|
10384
|
+
case "$env_kind" in
|
|
10385
|
+
fly) env_pre_argv=(fly secrets set --stage); env_pre_disp="fly secrets set --stage" ;;
|
|
10386
|
+
netlify) env_pre_argv=(netlify env:import "$env_file"); env_pre_disp="netlify env:import ${env_file}" ;;
|
|
10387
|
+
cloudflare) env_pre_argv=(wrangler secret bulk "$env_file"); env_pre_disp="wrangler secret bulk ${env_file}" ;;
|
|
10388
|
+
esac
|
|
10389
|
+
for _env_rec in "${env_pairs[@]}"; do
|
|
10390
|
+
env_keys="${env_keys:+${env_keys},}${_env_rec%%=*}"
|
|
10391
|
+
case "$env_kind" in
|
|
10392
|
+
vercel) env_disp="${env_disp} -e ${_env_rec%%=*}=***" ;;
|
|
10393
|
+
fly) env_pre_argv+=("$_env_rec"); env_pre_disp="${env_pre_disp} ${_env_rec%%=*}=***" ;;
|
|
10394
|
+
esac
|
|
10395
|
+
done
|
|
10396
|
+
fi
|
|
10397
|
+
|
|
10293
10398
|
local reasons
|
|
10294
10399
|
reasons="$(_deploy_gate "$dir" "$command")"
|
|
10295
10400
|
|
|
@@ -10346,17 +10451,18 @@ _deploy_try_execute() {
|
|
|
10346
10451
|
else
|
|
10347
10452
|
echo -e "${GREEN}Evidence gate PASSED.${NC} Receipt ${run_id:-unknown} VERIFIED this tree (${anchor:0:12})."
|
|
10348
10453
|
fi
|
|
10349
|
-
|
|
10454
|
+
[ -n "$env_pre_disp" ] && echo "Running (env): ${env_pre_disp}"
|
|
10455
|
+
if [ "$canary" = true ]; then echo "Running (canary): ${exec_cmd}${env_disp}"; else echo "Running: ${command}${env_disp}"; fi
|
|
10350
10456
|
echo ""
|
|
10351
10457
|
|
|
10352
10458
|
# Run in the project dir. No credential env var is read, set, or forwarded:
|
|
10353
10459
|
# the command inherits the user's already-authenticated CLI session as-is.
|
|
10354
10460
|
#
|
|
10355
|
-
#
|
|
10356
|
-
# ("vercel --prod"
|
|
10357
|
-
#
|
|
10358
|
-
#
|
|
10359
|
-
#
|
|
10461
|
+
# The deploy runs as an argv array, never through eval: the canonical
|
|
10462
|
+
# command ("vercel --prod") is word-split from the hardcoded
|
|
10463
|
+
# _deploy_options_for_type table (already past the destructive-operation
|
|
10464
|
+
# check in _deploy_gate), and --env-file values are appended as single
|
|
10465
|
+
# array elements, so a value such as $(cmd) is never evaluated.
|
|
10360
10466
|
# Resolve the rollback target BEFORE deploying: after it, the previous Fly
|
|
10361
10467
|
# release is no longer the newest one and cannot be recovered.
|
|
10362
10468
|
local rb_cmd="" rb_note=""
|
|
@@ -10377,6 +10483,24 @@ _deploy_try_execute() {
|
|
|
10377
10483
|
fi
|
|
10378
10484
|
|
|
10379
10485
|
local rc=0 started_at finished_at purl="" canary_out=""
|
|
10486
|
+
local -a deploy_argv=()
|
|
10487
|
+
read -r -a deploy_argv <<<"$exec_cmd"
|
|
10488
|
+
if [ "$env_kind" = vercel ]; then
|
|
10489
|
+
for _env_rec in "${env_pairs[@]}"; do deploy_argv+=(-e "$_env_rec"); done
|
|
10490
|
+
fi
|
|
10491
|
+
# What the record and messages name: the command with values masked as K=***.
|
|
10492
|
+
local exec_disp="${env_pre_disp:+${env_pre_disp}; }${exec_cmd}${env_disp}"
|
|
10493
|
+
if [ -n "$env_pre_disp" ]; then
|
|
10494
|
+
# The env step runs after the gate and before the deploy; if it fails the
|
|
10495
|
+
# deploy is NOT run (a deploy missing its env is not the one asked for).
|
|
10496
|
+
local env_rc=0
|
|
10497
|
+
( cd "$dir" && "${env_pre_argv[@]}" ) || env_rc=$?
|
|
10498
|
+
if [ "$env_rc" -ne 0 ]; then
|
|
10499
|
+
echo -e "${RED}REFUSED: the env step exited ${env_rc}: ${env_pre_disp}${NC}" >&2
|
|
10500
|
+
echo " The deploy was NOT run." >&2
|
|
10501
|
+
return "$env_rc"
|
|
10502
|
+
fi
|
|
10503
|
+
fi
|
|
10380
10504
|
started_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
10381
10505
|
local deployed_url="" health_src=""
|
|
10382
10506
|
[ -n "$health_url" ] && health_src="flag"
|
|
@@ -10385,8 +10509,7 @@ _deploy_try_execute() {
|
|
|
10385
10509
|
# Staged: a preview deploy (no --prod), probe the preview URL, promote only if healthy.
|
|
10386
10510
|
# Nothing reaches production before the probe, so there is nothing to roll back.
|
|
10387
10511
|
rb_cmd=""; auto_rollback=false
|
|
10388
|
-
|
|
10389
|
-
canary_out="$( cd "$dir" && eval "$exec_cmd" )" || rc=$?
|
|
10512
|
+
canary_out="$( cd "$dir" && "${deploy_argv[@]}" )" || rc=$?
|
|
10390
10513
|
printf '%s\n' "$canary_out"
|
|
10391
10514
|
purl="$(grep -Eo 'https?://[^[:space:]]+' <<<"$canary_out" | tail -n 1)"
|
|
10392
10515
|
if [ "$rc" -eq 0 ] && [ -n "$purl" ]; then
|
|
@@ -10395,7 +10518,7 @@ _deploy_try_execute() {
|
|
|
10395
10518
|
if hcode="$(_deploy_probe_health "$health_url" "$health_match")"; then
|
|
10396
10519
|
health_status="healthy"
|
|
10397
10520
|
echo "Promoting: vercel promote ${purl}"
|
|
10398
|
-
|
|
10521
|
+
exec_disp="${exec_disp}; vercel promote ${purl}"
|
|
10399
10522
|
( cd "$dir" && vercel promote "$purl" ) || rc=$?
|
|
10400
10523
|
else
|
|
10401
10524
|
health_status="FAILED_HEALTH"
|
|
@@ -10418,7 +10541,7 @@ _deploy_try_execute() {
|
|
|
10418
10541
|
fi
|
|
10419
10542
|
case $- in *e*) dep_errexit=1 ;; esac
|
|
10420
10543
|
set +e
|
|
10421
|
-
( cd "$dir" &&
|
|
10544
|
+
( cd "$dir" && "${deploy_argv[@]}" ) 2>&1 | tee "$dep_tmp"
|
|
10422
10545
|
rc=${PIPESTATUS[0]}
|
|
10423
10546
|
[ "$dep_errexit" -eq 1 ] && set -e
|
|
10424
10547
|
if [ "$rc" -eq 0 ] && [ "$dep_tmp" != /dev/null ]; then
|
|
@@ -10472,9 +10595,9 @@ _deploy_try_execute() {
|
|
|
10472
10595
|
local rec rsha
|
|
10473
10596
|
finished_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
10474
10597
|
rsha="$(python3 -c 'import json,sys;print((json.load(open(sys.argv[1])).get("verification") or {}).get("hash") or "")' "$pj" 2>/dev/null || printf '')"
|
|
10475
|
-
rec="$(_deploy_record "$dir" "$
|
|
10598
|
+
rec="$(_deploy_record "$dir" "$exec_disp" "$rc" "${run_id:-unknown}" "${anchor:-unknown}" \
|
|
10476
10599
|
"$anchor_state" "$health_status" "$health_url" "$rb_attempted" "$rb_exit" \
|
|
10477
|
-
"$rsha" "$started_at" "$finished_at" "${command%% *}" "$canary" "$post_rb" "$hcode" "$health_match" "$(git -C "$dir" rev-parse 'HEAD^{tree}' 2>/dev/null || true)" "$dest" "$deployed_url" "$health_src")"
|
|
10600
|
+
"$rsha" "$started_at" "$finished_at" "${command%% *}" "$canary" "$post_rb" "$hcode" "$health_match" "$(git -C "$dir" rev-parse 'HEAD^{tree}' 2>/dev/null || true)" "$dest" "$deployed_url" "$health_src" "$env_keys" "$env_file")"
|
|
10478
10601
|
echo ""
|
|
10479
10602
|
if [ "$rc" -eq 0 ]; then
|
|
10480
10603
|
echo -e "${GREEN}Deploy command exited 0.${NC}"
|
|
@@ -10623,6 +10746,7 @@ cmd_deploy() {
|
|
|
10623
10746
|
local LOKI_DEPLOY_ALLOW_UNANCHORED=false
|
|
10624
10747
|
# Per-invocation like --execute; local so an ambient env var cannot set them.
|
|
10625
10748
|
local _LOKI_DEPLOY_HEALTH_URL="" _LOKI_DEPLOY_HEALTH_MATCH="" _LOKI_DEPLOY_AUTO_ROLLBACK=false _LOKI_DEPLOY_CANARY=false _LOKI_DEPLOY_DESTINATION=""
|
|
10749
|
+
local _LOKI_DEPLOY_ENV_FILE=""
|
|
10626
10750
|
|
|
10627
10751
|
# Arg parse (mirror cmd_preview: lenient on unknown args -> no behavior drift).
|
|
10628
10752
|
while [ $# -gt 0 ]; do
|
|
@@ -10630,7 +10754,7 @@ cmd_deploy() {
|
|
|
10630
10754
|
--help|-h|help)
|
|
10631
10755
|
echo -e "${BOLD}Loki Mode -- deploy command advisory (print-only by default)${NC}"
|
|
10632
10756
|
echo ""
|
|
10633
|
-
echo "Usage: loki deploy [--dir <path>] [--no-clip] [--execute [--canary]] [--destination preview|staging|production] [--health-url URL [--health-match STR] [--auto-rollback]]"
|
|
10757
|
+
echo "Usage: loki deploy [--dir <path>] [--no-clip] [--execute [--canary] [--env-file FILE]] [--destination preview|staging|production] [--health-url URL [--health-match STR] [--auto-rollback]]"
|
|
10634
10758
|
echo ""
|
|
10635
10759
|
echo "Detects your project type and your installed cloud CLI (and any"
|
|
10636
10760
|
echo "CI/CD pipeline), then PRINTS the exact deploy command for YOU to run."
|
|
@@ -10720,6 +10844,16 @@ cmd_deploy() {
|
|
|
10720
10844
|
echo " With --execute: preview/staging run a non-production deploy"
|
|
10721
10845
|
echo " (Vercel only); production is refused unless a VERIFIED staging"
|
|
10722
10846
|
echo " deploy record exists for the same SHA. Unset keeps today's behavior."
|
|
10847
|
+
echo " --env-file FILE"
|
|
10848
|
+
echo " With --execute: push KEY=VALUE lines from FILE to the provider"
|
|
10849
|
+
echo " (parsed, never shell-evaluated). Refuses when a key listed in"
|
|
10850
|
+
echo " .env.example is missing from FILE. Vercel: 'vercel --prod -e K=V'"
|
|
10851
|
+
echo " per key; Fly: 'fly secrets set --stage K=V ...' then 'fly deploy';"
|
|
10852
|
+
echo " Netlify: 'netlify env:import FILE'; Cloudflare: 'wrangler secret"
|
|
10853
|
+
echo " bulk FILE'. Any other provider refuses with nothing run. If the env"
|
|
10854
|
+
echo " step fails the deploy is not run. Values are masked as K=*** in"
|
|
10855
|
+
echo " output; the deploy record stores env_keys (names) and env_source,"
|
|
10856
|
+
echo " never values."
|
|
10723
10857
|
echo " --allow-unanchored"
|
|
10724
10858
|
echo " Proceed when the receipt records NO baseline (nothing"
|
|
10725
10859
|
echo " about this tree is proven). Never bypasses a recorded"
|
|
@@ -10770,10 +10904,33 @@ cmd_deploy() {
|
|
|
10770
10904
|
--no-clip)
|
|
10771
10905
|
do_clip=false
|
|
10772
10906
|
;;
|
|
10907
|
+
--env-file)
|
|
10908
|
+
case "${2:-}" in
|
|
10909
|
+
-*|"") echo "loki deploy --env-file requires a file path" >&2; return 1 ;;
|
|
10910
|
+
*) _LOKI_DEPLOY_ENV_FILE="$2"; shift ;;
|
|
10911
|
+
esac
|
|
10912
|
+
;;
|
|
10913
|
+
--env-file=*)
|
|
10914
|
+
_LOKI_DEPLOY_ENV_FILE="${1#--env-file=}"
|
|
10915
|
+
[ -n "$_LOKI_DEPLOY_ENV_FILE" ] || { echo "loki deploy --env-file requires a file path" >&2; return 1; }
|
|
10916
|
+
;;
|
|
10773
10917
|
esac
|
|
10774
10918
|
shift
|
|
10775
10919
|
done
|
|
10776
10920
|
|
|
10921
|
+
if [ -n "$_LOKI_DEPLOY_ENV_FILE" ]; then
|
|
10922
|
+
if [ "$do_execute" != true ]; then
|
|
10923
|
+
echo "loki deploy --env-file requires --execute (the advisory run pushes nothing)" >&2
|
|
10924
|
+
return 1
|
|
10925
|
+
fi
|
|
10926
|
+
if [ ! -f "$_LOKI_DEPLOY_ENV_FILE" ] || [ ! -r "$_LOKI_DEPLOY_ENV_FILE" ]; then
|
|
10927
|
+
echo "loki deploy --env-file: not a readable file: $_LOKI_DEPLOY_ENV_FILE" >&2
|
|
10928
|
+
return 1
|
|
10929
|
+
fi
|
|
10930
|
+
# Absolute, so a provider verb run from the project dir finds the same file.
|
|
10931
|
+
_LOKI_DEPLOY_ENV_FILE="$(cd "$(dirname -- "$_LOKI_DEPLOY_ENV_FILE")" && pwd -P)/$(basename -- "$_LOKI_DEPLOY_ENV_FILE")"
|
|
10932
|
+
fi
|
|
10933
|
+
|
|
10777
10934
|
if [ "$_LOKI_DEPLOY_AUTO_ROLLBACK" = true ] && [ -z "$_LOKI_DEPLOY_HEALTH_URL" ]; then
|
|
10778
10935
|
echo "loki deploy --auto-rollback requires --health-url (no health signal, no rollback)" >&2
|
|
10779
10936
|
return 1
|
package/completions/_loki
CHANGED
|
@@ -178,6 +178,7 @@ function _loki {
|
|
|
178
178
|
'--no-clip[Do not copy the command to the clipboard]' \
|
|
179
179
|
'--execute[Run the deploy command if the receipt gate passes]' \
|
|
180
180
|
'--canary[With --execute: staged rollout (Vercel promote, Fly canary)]' \
|
|
181
|
+
'--env-file[With --execute: push KEY=VALUE env via Vercel, Fly, Netlify or Cloudflare (names-only record)]:env file:_files' \
|
|
181
182
|
'--allow-unanchored[Proceed when the receipt records no baseline]' \
|
|
182
183
|
'--health-url[Health probe URL]:url:' \
|
|
183
184
|
'--auto-rollback[Roll back on a failed health probe]' \
|
package/completions/loki.bash
CHANGED
|
@@ -150,7 +150,7 @@ _loki_completion() {
|
|
|
150
150
|
|
|
151
151
|
deploy)
|
|
152
152
|
if [[ "$cur" == -* ]]; then
|
|
153
|
-
COMPREPLY=( $(compgen -W "--execute --destination --canary --health-url --health-match --auto-rollback --dir --no-clip --allow-unanchored --help" -- "$cur") )
|
|
153
|
+
COMPREPLY=( $(compgen -W "--execute --destination --canary --env-file --health-url --health-match --auto-rollback --dir --no-clip --allow-unanchored --help" -- "$cur") )
|
|
154
154
|
return 0
|
|
155
155
|
fi
|
|
156
156
|
;;
|
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.35. 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 |
|
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.35
|
|
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
|
@@ -1008,10 +1008,10 @@ Source: ~/git/autonomi-dev/research/2026-09-30-adoption/SWARM-PROMPT-ADOPTION.md
|
|
|
1008
1008
|
| TEN-DEPLOY-02 | Signed live provenance doc (loki.provenance/1) and loki verify --url | loki-ts/src/util/receipt_signer.ts, loki-ts/tests/engine10/verify_cmd.test.ts (provenance cases; existing deploy-record tests live here), docs/SIGNED-RECEIPTS.md (one section), CHANGELOG.md. Engine10 core is not edited: verify_cmd.ts:164 already routes through deployAttestCmd, and a one-token --url passthrough there needs the budget test to stay green. | HIGH | see Wall in note | released v11.17.26@2026-10-17T05:48Z | SPLIT per CTO critic into (a) signProvenance plus --sign-provenance, (b) verify --url fetch and verdicts; build as two commits or two agents. wave 2; depends: none. Goal: Extend receipt_signer.ts, the owner of signed deploy attestations, with: signProvenance(head_sha, tree_sha, receipt_sha256, run_id, built_at), which signs with the same Ed25519 key as signDeployRecord; a `--sign-provenance FILE` dispatch in deployAttestCmd; and `loki verify --url https://host` plus a pubkey. The --url check fetches <url>/.well-known/loki-provenance.json with a timeout and size cap, checks the signature, and requires a 200 with JSON. The verdict is VERIFIED only when the signature verifies against the local JWKS or --pubkey AND the cited receipt (when present locally or via --receipt) is VERIFIED. The doc alone with an unknown kid is UNCHECKED rc 2. An edited doc is TAMPERED rc 1. A fetch failure is UNCHECKED and never VERIFIED. Optional --expect-sha SHA must equal head_sha. Wall: RED: tests serve a signed provenance doc from Bun.serve on 127.0.0.1. On main, `verify --url` is an unknown arg and exits 2, so the tests fail. GREEN: genuine doc with --pubkey gives VERIFIED rc 0. One edited byte of head_sha gives TAMPERED rc 1. An unknown kid gives UNCHECKED rc 2. A 404, a non-JSON body or a doc over 64KB gives UNCHECKED rc 2. A wrong --expect-sha gives TAMPERED rc 1. MUTATION: skip the signature verify and the edited-byte case goes red. Gate: cd loki-ts && bun test tests/engine10/verify_cmd.test.ts && bun test tests/engine10/ && bunx tsc --noEmit (the full engine10 suite runs the budget and spawn-env guards) Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1009
1009
|
| TEN-DEPLOY-03 | Ship the provenance doc with the build and prove the live URL serves the verified SHA | autonomy/loki (_deploy_try_execute pre-exec and post-health blocks, _deploy_record live_binding field only), tests/test-deploy-receipt-gate.sh (new section), docs/WORKSPACES.md, CHANGELOG.md | HIGH | see Wall in note | ready@2026-10-17T01:40Z | SPLIT per CTO critic into (a) provenance file into deploy root per project type, (b) post-deploy live-binding probe; build as two commits or two agents. wave 3; depends: TEN-DEPLOY-01, TEN-DEPLOY-02. Goal: In _deploy_try_execute, after the gate passes and before the provider runs, write a signed .well-known/loki-provenance.json into the deploy root via `verify --sign-provenance`. The deploy root is public/ for nextjs and vite, the detected dist/ or build/ for static, and is refused with a reason for docker/python where no static root exists. Write it as an untracked build artifact so the dirty-tree gate is evaluated before it. After the deploy, probe <deployed_url>/.well-known/loki-provenance.json. Set live_binding=VERIFIED only when its head_sha equals the anchor. A mismatch gives FAILED_HEALTH exit 4 (stale or wrong build served). Update docs/WORKSPACES.md and replace 'deployed-SHA binding is not implemented' with what is now bound and what is not. Wall: RED: a stubbed vercel copies dist/ into a served dir and a python http.server serves it. On main, no provenance file exists and the record has no live_binding. GREEN: the file exists in dist/.well-known, live_binding=VERIFIED, and its head_sha equals git rev-parse HEAD. A stub that serves an older provenance gives FAILED_HEALTH exit 4. A docker project prints the refusal reason and records live_binding=unsupported, never VERIFIED. The dirty-tree gate still refuses a dirty tree before the file is written. MUTATION: compare against a constant instead of the anchor and the stale-serve case goes red. Gate: bash -n autonomy/loki && shellcheck -S warning autonomy/loki && bash tests/test-deploy-receipt-gate.sh && (cd loki-ts && bun test tests/engine10/verify_cmd.test.ts) Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1010
1010
|
| TEN-DEPLOY-04 | Verified deploy badge from loki status --badge | loki-ts/src/commands/status.ts (renderLastDeploy plus --badge flag parse only), loki-ts/tests/commands/status.test.ts, CHANGELOG.md | MEDIUM | see Wall in note | released@2026-10-17T05:06Z | wave 4; depends: TEN-DEPLOY-01 (deployed_url field); live_binding from TEN-DEPLOY-03 is read if present, and its absence omits the badge. Goal: `loki status --badge` reads the newest loki.deploy/1 record (renderLastDeploy already loads it) and verifies it through the existing verify path. It prints a markdown shields badge linking to <deployed_url>/.well-known/loki-provenance.json. The message is 'deployed: verified' (brightgreen) ONLY when the record verifies and live_binding=VERIFIED. 'deployed: unverified' (red) is printed for TAMPERED or a failed health check. In all other cases the badge is omitted with a one-line reason. It never prints green from an unchecked field. The color mapping matches the share badge (autonomy/loki:38291), and no new vocabulary is added. Wall: RED: status.test.ts fixture with a signed healthy record, live_binding=VERIFIED and deployed_url. On main, --badge is unknown and no badge line is printed. GREEN: the badge line contains 'brightgreen' and deployed_url. A record with health FAILED_HEALTH gives a red badge. An unsigned record or a missing live_binding omits the badge and prints the reason. A record with no deployed_url omits the badge. MUTATION: drop the verify call and the unsigned case goes green, so the test goes red. Gate: cd loki-ts && bun test tests/commands/status.test.ts && bunx tsc --noEmit && bash tests/test-status-surface-agrees.sh Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1011
|
-
| TEN-DEPLOY-05 | loki deploy --env-file: push env to the provider with names-only records | autonomy/loki (cmd_deploy arg parse for --env-file, _deploy_try_execute env step, _deploy_record env_keys field only), tests/test-deploy-receipt-gate.sh (new section), autonomy/completions (loki deploy flag list only), CHANGELOG.md | HIGH | see Wall in note |
|
|
1011
|
+
| TEN-DEPLOY-05 | loki deploy --env-file: push env to the provider with names-only records | autonomy/loki (cmd_deploy arg parse for --env-file, _deploy_try_execute env step, _deploy_record env_keys field only), tests/test-deploy-receipt-gate.sh (new section), autonomy/completions (loki deploy flag list only), CHANGELOG.md | HIGH | see Wall in note | released v11.17.35 | SPLIT per CTO critic into (a) env-file parser, .env.example check, masking, env_keys record, (b) four provider verbs; build as two commits or two agents. wave 4; depends: TEN-DEPLOY-03 (same function, serialized to avoid conflicts). Goal: `--env-file FILE` (with --execute only) parses KEY=VALUE with no shell eval. It refuses when a key in .env.example is missing from FILE, naming the keys. Env is applied through documented verbs only: Vercel `vercel --prod -e K=V` per key (args built as an array, never through the shell); Fly `fly secrets set --stage K=V ...` before `fly deploy`; Netlify `netlify env:import FILE`; Cloudflare `wrangler secret bulk FILE`. An unsupported provider refuses with nothing run. The record stores env_keys (names, sorted) and env_source; it NEVER stores values. Values never appear in stdout, the record or the printed 'Running:' line, where they are masked as K=***. Wall: RED: a recording vercel stub logs argv. On main, --env-file is ignored and no -e args appear. GREEN: argv has `-e API_URL=x -e TOKEN=s3cr3t`. Grepping stdout, stderr and the record for s3cr3t finds nothing; env_keys=[API_URL,TOKEN]. When .env.example lists DB_URL and the env file lacks it, the command refuses with rc 1, no stub calls and DB_URL named. A value with $(touch pwned) leaves no file named pwned. MUTATION: write values into the record and the secret-grep goes red. Gate: bash -n autonomy/loki && shellcheck -S warning autonomy/loki && bash tests/test-deploy-receipt-gate.sh && bash tests/test-completion-drift.sh (or whichever completion drift test the CHANGELOG cites) Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1012
1012
|
| TEN-DEPLOY-06 | loki deploy --domain: attach a custom domain and prove TLS | autonomy/loki (cmd_deploy --domain parse and a post-health domain block in _deploy_try_execute, _deploy_record domain/tls fields only), tests/test-deploy-receipt-gate.sh (new section), CHANGELOG.md | MEDIUM | see Wall in note | ready@2026-10-17T01:40Z | wave 5; depends: TEN-DEPLOY-05 (same function, serialized). Goal: `--domain example.com` (with --execute) runs documented verbs after a healthy deploy: Vercel `vercel alias set <deployed_url> <domain>`; Fly `fly certs add <domain>`. Netlify and Cloudflare print the manual dashboard step and set domain_status=manual. Then a TLS proof runs: `openssl s_client -servername <domain> -connect <domain>:443` plus `openssl x509 -noout -enddate -checkend 604800`. It records domain, tls_status (valid/expiring/invalid/unchecked) and tls_not_after, and re-probes https://<domain>/.well-known/loki-provenance.json for the same head_sha. DNS not yet pointed gives tls_status=invalid and exit 6, with the DNS record the provider needs printed. It never claims valid without the openssl check. Wall: RED: vercel, openssl and curl are stubbed. On main, --domain is ignored. GREEN: the alias set argv is recorded, tls_status=valid and tls_not_after is set. An openssl stub that fails -checkend gives expiring. An openssl handshake failure gives invalid and exit 6. A netlify project gives domain_status=manual, no alias call, and tls still checked. No openssl on PATH gives unchecked, never valid. MUTATION: default tls_status to valid and the missing-openssl case goes red. Gate: bash -n autonomy/loki && shellcheck -S warning autonomy/loki && bash tests/test-deploy-receipt-gate.sh Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1013
1013
|
| TEN-DEPLOY-07 | loki github publish: receipt-stamped GitHub export from the CLI | autonomy/loki (cmd_github publish arm and its help line only), tests/test-github-publish.sh (new: no existing test owns cmd_github repo creation; test-proven-pr-check.sh covers PR checks only) plus its run-all-tests.sh registration and shard row, CHANGELOG.md | MEDIUM | see Wall in note | released@2026-10-17T03:50Z | merged efa201ffd (TL APPROVE 81346df2a) Shipped in npm 11.17.15 (latest+next) or 11.17.16 (Release run success on e3d445460). |
|
|
1014
|
-
| TEN-DEPLOY-08 | Web app deploy and GitHub push go through the gated CLI; no fabricated URLs | web-app/server.py (deploy_session ~5236-5336 and github_push_session ~5339-5395 only), web-app/tests/test_server.py (new cases), CHANGELOG.md | HIGH | see Wall in note |
|
|
1014
|
+
| TEN-DEPLOY-08 | Web app deploy and GitHub push go through the gated CLI; no fabricated URLs | web-app/server.py (deploy_session ~5236-5336 and github_push_session ~5339-5395 only), web-app/tests/test_server.py (new cases), CHANGELOG.md | HIGH | see Wall in note | released v11.17.35 | SPLIT per CTO critic into (a) deploy_session, (b) github_push_session plus web-app url:null handling; build as two commits or two agents. wave 4; depends: TEN-DEPLOY-01 (deployed_url), TEN-DEPLOY-07 (github publish). Goal: Replace the bodies of deploy_session and github_push_session in web-app/server.py. Deploy runs `loki deploy --execute --dir <session_dir>` as an argv list with a timeout, then reads the newest <session>/.loki/deploys/*.json. It returns {url: deployed_url or null, health_status, live_binding, record_path, refused_reasons} and exits non-2xx on refusal. The platform param is kept as a hint only when it matches the CLI's detected provider; otherwise it returns 409 with the reason. GitHub push calls `loki github publish` (private default). Delete the hardcoded https://vercel.app, https://netlify.app and https://github.io fallbacks and the `git add -A` / `--public` path in the same change. Wall: RED: test_server.py with monkeypatched subprocess. On main, a deploy whose output has no URL returns url='https://vercel.app' (assert url is None fails), and no receipt gate is invoked. GREEN: the subprocess argv is [loki, deploy, --execute, --dir, <dir>]. A gate refusal returns 4xx with the reasons. A no-URL deploy returns url null. A github push argv contains `github publish` and never `add -A`. `grep -n 'https://vercel.app\/https://netlify.app\/"https://github.io"' web-app/server.py` exits 1. MUTATION: restore a fallback URL and the null-URL test goes red. Gate: python3 -m pytest web-app/tests/test_server.py -q && bash tests/moat/p7-no-fabricated-data.sh && bash tests/test-web-app-no-orphan-components.sh Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1015
1015
|
| TEN-DEPLOY-09 | One-click from loki start and loki chat: pass the new deploy flags through | autonomy/loki (cmd_start _ps_ deploy parse block ~2625-2690 only), loki-ts/src/commands/start.ts (help string ~148-151 only), autonomy/lib/chat.sh (help line 53, system prompt line 6, _chat_deploy echo only), tests/test-help-start-flags.sh, docs/DEPLOYMENT.md, CHANGELOG.md | LOW | see Wall in note | building@2026-10-17T05:48Z | SPLIT per CTO critic into (a) start passthrough, (b) chat and docs text; build as two commits or two agents. wave 5; depends: TEN-DEPLOY-05, TEN-DEPLOY-06, TEN-DEPLOY-07. Goal: `loki start --deploy` passes --destination, --canary, --env-file, --domain and --github through to cmd_deploy. --github runs `loki github publish` after a successful deploy. Flag validation uses the existing _ps_ pattern (a value must not start with '-'). Bun-route start.ts help text lists them, and the PATH-slice divert keeps routing --deploy to bash. chat.sh `/deploy` help and _LOKI_CHAT_SYSTEM_PROMPT mention --domain, --env-file and `loki verify --url`, and the confirm prompt prints the full argv. docs/DEPLOYMENT.md gets one end-to-end 'brief to verified URL' section. Wall: RED: test-help-start-flags.sh asserts `loki start --help` lists --domain and --env-file, and a stubbed cmd_deploy recorder receives `--domain x.com --env-file .env` from `loki start --deploy --domain x.com --env-file .env`. It fails on main. GREEN: both pass. `--domain --env-file` (flag-shaped value) exits 2. A non-zero start exit still never deploys. MUTATION: drop the --domain forward and the recorder assertion goes red. Gate: bash -n autonomy/loki autonomy/lib/chat.sh && bash tests/test-help-start-flags.sh && (cd loki-ts && bun test tests/commands/start.test.ts && bunx tsc --noEmit) && bash tests/test-help-drift.sh Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1016
1016
|
| TEN-ADOPTION-01 | Tour shows a receipt you can actually verify offline | autonomy/loki (cmd_demo offline branch only, ~15927-15965); skills/fixtures/demo-receipt/ (add receipt.json, the event log the log_seal check reads, pubkey.jwk; update README.md); tests/cli/test-tour-verify.sh (new: no test owns tour today, and test-proof-command.sh covers the legacy proof store) | MEDIUM | see Wall in note | released v11.17.33 | wave 3; depends: none (the fixture must come from a real sealed run; see not_codeable). Goal: `loki tour` (and `loki demo --offline`) runs the real Bun verifier against a bundled engine10 receipt.json, its event log and a public JWK, and prints VERIFIED. It then flips one byte in a copy under a run-owned temp dir and prints TAMPERED. It stays offline, needs no key and spends nothing. When Bun is absent it prints the exact verify command instead of claiming a result. The display-only disclaimer at autonomy/loki:15953-15957 goes away (the replaced text is deleted). Wall: Red first: the new test asserts the tour stdout contains VERIFIED from the verifier, and TAMPERED for the byte-flipped copy, with rc 0. On main it fails because the stdout says 'for display only'. Mutations: (a) point the tour at a receipt with one changed field: the test must see TAMPERED, not VERIFIED; (b) remove pubkey.jwk: the tour must say UNCHECKED or the verify-command fallback, never VERIFIED; (c) hide bun from PATH: output has the command and no verdict. Gate: bash tests/cli/test-tour-verify.sh && bash tests/test-help-discoverability.sh && bash scripts/local-ci.sh. Register the new test in tests/run-all-tests.sh and its shard. Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1017
1017
|
| TEN-ADOPTION-02 | Portable receipt bundle builder | loki-ts/src/util/receipt_bundle.ts (new: no existing module packages a receipt for third-party verify, and engine10/verify_cmd.ts is core at its line budget); loki-ts/tests/util/receipt_bundle.test.ts (new, beside the existing util tests) | HIGH | see Wall in note | released@2026-10-17T03:50Z | TL APPROVE bb4957e90, merged for v11.17.14 Shipped in npm 11.17.15 (latest+next) or 11.17.16 (Release run success on e3d445460). |
|
|
@@ -1051,11 +1051,11 @@ Source: ~/git/autonomi-dev/research/2026-09-30-adoption/SWARM-PROMPT-ADOPTION.md
|
|
|
1051
1051
|
| TEN-GATES-03 | loki verify reports agent-independent evidence and adds --require-exogenous | loki-ts/src/engine10/verify_cmd.ts, loki-ts/tests/engine10/verify_cmd.test.ts | HIGH | see Wall in note | released@2026-10-17T04:08Z | v11.17.17; TL APPROVE batch J workflow w9sw9xytw |
|
|
1052
1052
|
| TEN-GATES-04 | TS-callable app boot and HTTP health probe over app-runner.sh | loki-ts/src/util/app_probe.ts (new), loki-ts/tests/util/app_probe.test.ts (new) | MEDIUM | see Wall in note | released@2026-10-17T05:25Z v11.17.23 | SPLIT per CTO critic into (a) app boot and health, (b) functional-verify run and artifact write; build as two commits or two agents. wave 2; depends: none. Goal: New loki-ts/src/util/app_probe.ts (justification: no TS module owns app boot; app-runner.sh is bash-only and deep.ts:121-122 names this missing surface). appProbe(repoDir, lokiDir, {specText?, timeoutMs}) sources autonomy/app-runner.sh in a bash child (token-free env via plainTestEnv), runs app_runner_init, app_runner_start, app_runner_health_check, reads .loki/app-runner/health.json, then (when specText given) runs autonomy/lib/functional-verify.py against the URL and writes .loki/quality/functional-results.json in the shape proof-generator.py:841-870 reads. ALWAYS calls app_runner_stop in finally (stops only the PID app-runner recorded). Returns ReceiptCheck-shaped results: 'app boot' and 'http probe' with result pass/fail/not_run and reason; missing runtime or no app detected = not_run, never fail. Wall: Red first: fixture repo with a static index.html (app-runner static-site path, as tests/test-app-runner-static-site.sh) -> app boot pass + health.json ok; fixture whose start command exits 1 -> fail; empty repo -> not_run. Assert no process left on the recorded PID after return. Mutation: drop the stop call -> leftover-PID assertion red. Gate: cd loki-ts && bun test tests/util/app_probe.test.ts && bun test && bunx tsc --noEmit; register the new test file per the structural guards (select-tests.sh --guards-only rows, shard registration) Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1053
1053
|
| TEN-GATES-05 | Spec-derived API auth probe in functional-verify.py | autonomy/lib/functional-verify.py, tests/test_functional_verify.py | HIGH | see Wall in note | parked@2026-10-17T03:30Z | HIGH r1 BLOCK; re-sliced as TEN-GATES-05b |
|
|
1054
|
-
| TEN-GATES-06 | Deep verify: real app boot and secure-scan rules on engine10 | loki-ts/src/engine10/stages/deep.ts, loki-ts/tests/engine10/deep.test.ts | HIGH | see Wall in note |
|
|
1054
|
+
| TEN-GATES-06 | Deep verify: real app boot and secure-scan rules on engine10 | loki-ts/src/engine10/stages/deep.ts, loki-ts/tests/engine10/deep.test.ts | HIGH | see Wall in note | released v11.17.35 | wave 3; depends: TEN-GATES-04, Q18-04 (deep.ts in flight). Goal: Replace runAppBoot's hard-coded not_run (deep.ts:105-130) with a call to util/app_probe.ts, pushing its 'app boot' and 'http probe' checks; extend the existing 'security scan' check to also run autonomy/lib/secure-scan.py over changed files (HIGH active finding = fail, scanner absent = not_run). DEEP_NOT_PROVEN entries clear only for checks that actually ran. Net-zero lines in engine10 core (app boot body shrinks to the call). Wall: Red first in deep.test.ts: injected appProbe fake returning pass -> 'app boot' check result pass (today always not_run); a changed file with a committed PEM private key -> security scan fail with secure-scan rule id; secure-scan missing -> not_run. Mutation: ignore secure-scan exit -> red. Gate: cd loki-ts && bun test tests/engine10/deep.test.ts tests/engine10/deep_wiring.test.ts tests/engine10/budget.test.ts && bun test && bunx tsc --noEmit Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1055
1055
|
| TEN-GATES-07 | loki start route: collect app health and functional facts before the proof | loki-ts/src/runner/proof.ts, loki-ts/tests/runner/proof.test.ts | MEDIUM | see Wall in note | released v11.17.26@2026-10-17T05:48Z | wave 3; depends: TEN-GATES-04. Goal: In runner/proof.ts, before spawning proof-generator.py, call util/app_probe.ts with the run's PRD text (LOKI_PROOF_APP_PROBE=0 opts out) so .loki/app-runner/health.json and .loki/quality/functional-results.json exist on the primary route; the proof's healthcheck and functional facts stop being permanently not_run. Still never throws; probe failure leaves the facts absent (not_run), never fabricated. Wall: Red first in proof.test.ts: inject a fake probe that writes both artifacts -> generator facts.healthcheck/functional ran=true; probe throwing -> generator still invoked, facts not_run. Mutation: skip probe -> red. Gate: cd loki-ts && bun test tests/runner/proof.test.ts tests/runner/proof_run_id_pointer.test.ts && bun test && bunx tsc --noEmit Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1056
1056
|
| TEN-GATES-08 | loki start route: secure-scan as an exogenous security_scan gate | loki-ts/src/runner/quality_gates.ts, loki-ts/tests/runner/quality_gates.test.ts | MEDIUM | see Wall in note | released@2026-10-17T04:08Z | v11.17.17; TL APPROVE batch J workflow w9sw9xytw |
|
|
1057
1057
|
| TEN-GATES-09 | loki start route: write build-results.json (wire the dead pythonBuildCheck) | loki-ts/src/util/python_build_check.ts, loki-ts/src/runner/autonomous.ts, loki-ts/tests/util/python_build_check.test.ts | MEDIUM | see Wall in note | released@2026-10-17T03:50Z | merged f24496198 (TL APPROVE 09a2ae73f) Shipped in npm 11.17.15 (latest+next) or 11.17.16 (Release run success on e3d445460). |
|
|
1058
|
-
| TEN-GATES-10 | Proof headline: VERIFIED needs one agent-independent fact beside the agent's suite | autonomy/lib/proof-generator.py, tests/test_proof_generator.py, docs/v10/DECISIONS.md | HIGH | see Wall in note |
|
|
1058
|
+
| TEN-GATES-10 | Proof headline: VERIFIED needs one agent-independent fact beside the agent's suite | autonomy/lib/proof-generator.py, tests/test_proof_generator.py, docs/v10/DECISIONS.md | HIGH | see Wall in note | released v11.17.35 | wave 4; depends: COST-WALL-f (proof-generator.py in flight), TEN-GATES-07, TEN-GATES-08, TEN-GATES-09 (facts must exist before tightening, or every primary-route run downgrades). Goal: In proof-generator.py the tests_verified branch (:2045-2055) returns VERIFIED only when at least one exogenous fact also passed: build verified, healthcheck ok, functional passed, security clean that actually ran, or an exogenous quality gate passed; otherwise VERIFIED WITH GAPS with degraded item 'no agent-independent evidence (only the agent's own test suite passed)'. Gap record is additive; LOKI_PROOF_REQUIRE_EXOGENOUS=0 opt-out; decision recorded in DECISIONS.md under D99. Wall: Red first in test_proof_generator.py: facts with tests verified + nonempty diff and nothing else -> 'VERIFIED WITH GAPS' plus the degraded item (today VERIFIED); add build verified -> VERIFIED; only an advisory code_review pass -> still WITH GAPS. Mutation: count advisory gates as corroboration -> red. Gate: python3 -m pytest -q tests/test_proof_generator.py tests/test_proof_degraded_disabled_gates.py tests/test_proof_verify.py; bash tests/test-proven-pr-receipt.sh Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
|
1059
1059
|
| TEN-STABILITY-01 | bench-suite argv survives hyperfine 1.20 (unblocks v11.17.6 backstop) | loki-ts/scripts/bench-suite.ts; NEW loki-ts/tests/scripts/bench_suite_argv.test.ts (no existing test owns bench-suite.ts: grep -rl bench-suite loki-ts/tests tests returns nothing) | LOW | see Wall in note | released@2026-10-17T02:57Z | merge d67b2af14, dist bd6348d77; TL APPROVE f1bcf7679 (4 pass, typecheck rc=0); post-merge tsc 0 errors, 130 pass. wave 1; depends: none. Goal: Stop building 'VAR=1 cmd' hyperfine commands. Pass the env as 'env LOKI_LEGACY_BASH=1 <shim> <cmd>' (also 'env BUN_FROM_SOURCE=1'), which works on apt hyperfine 1.18 and brew 1.20 alike. Export a pure argv builder from the script so it can be tested. Write the --export-json files under a mkdtemp dir, not fixed /tmp/bench-*.json paths. Exit non-zero when any command is SKIPPED because hyperfine itself refused the argv, not only when every command was skipped. Wall: RED: the test puts a fake 'hyperfine' on PATH that exits 1 with the real 1.20 message when any positional command matches ^[A-Z_]+=. It runs the builder and fails today, because both benchPair (bench-suite.ts:76) and benchRoute (:108) emit LOKI_LEGACY_BASH=1 first. GREEN after the fix. MUTATION: revert one call site to the VAR= form; the test goes red. A second mutation: a partial SKIP must exit 1. GATE: cd loki-ts && bun test tests/scripts/bench_suite_argv.test.ts && bun run typecheck && bun test (full, per the slice-gate rule). Then run real hyperfine locally: cd loki-ts && bun run scripts/bench-suite.ts --runs 1 --warmup 0 (hyperfine 1.20.0 is installed on this machine) must print no 'Cannot run'. After merge: gh workflow run nightly.yml, and the macOS 1.3.13 leg must be green. Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. v11.17.13 npm next 11.17.13 |
|
|
1060
1060
|
| TEN-STABILITY-02 | promote.yml walks back to the newest promotable next build (D96 exact-SHA rule) | .github/workflows/promote.yml (Derive and validate version, Require a green nightly, Require a green Post-Release Smoke steps); tests/test_release_next_tag.py (nightly-gate and version-derivation cases); tests/test-promote-smoke-sha.sh; docs/v10/DECISIONS.md (one D102 entry) | HIGH | see Wall in note | rejected@2026-10-17T03:30Z | superseded by TEN-RELEASE-INSTANT (D102): promote.yml deleted, every release moves latest and next |
|
|
1061
1061
|
| TEN-STABILITY-03 | pre-push runs the R8 global guard rows on every push to main | .githooks/pre-push; tests/test-pre-push-hook.sh | MEDIUM | see Wall in note | parked@2026-10-17T04:27Z | parked under D102 (instant releases): a 300s guards-only run on every main push delays npm; guards stay on release.sh and CI as fix-forward signals. wave 2; depends: none (TEN-STABILITY-04 adds rows; the hook reads the tsv at run time). Goal: On a push whose remote ref is refs/heads/main, run 'bash scripts/impacted-gate.sh --guards-only' against the pushed tip in a clean detached worktree. Reuse release.sh's worktree pattern: per-row timeout, run-owned tmp via loki_run_tmp_create. Place it before the PRE_PUSH_SKIP exit, next to the release-notes and gitleaks gates, so routine PRE_PUSH_SKIP=1 merge pushes cannot skip it. A red row aborts the push and names the row. LOKI_PREPUSH_SKIP_GUARDS=1 is the only bypass and prints a loud warning. Branch pushes and deletes are untouched. Target time is under 120s with IMPACTED_JOBS=4. Over 180s fails closed with a timeout message, never passes silently. Wall: RED: test-pre-push-hook.sh gains a case where a stub impacted-gate (IMPACTED_TEST_MODE=1 with an IMPACTED_SUITES_FILE listing a failing suite) is red and stdin carries refs/heads/main with LOKI_RELEASE_MANAGER=1 PRE_PUSH_SKIP=1. Today the hook exits 0; after the fix it exits 1 and names the row. GREEN cases: all rows green gives exit 0; a branch push never invokes the gate; the bypass env warns and exits 0; a gate timeout gives exit 1. MUTATION: move the block after the PRE_PUSH_SKIP check and the PRE_PUSH_SKIP case goes red. GATE: bash tests/test-pre-push-hook.sh && bash tests/test-pre-push-gitleaks.sh && shellcheck .githooks/pre-push && bash tests/test-no-tmp-sweep.sh. Then time it: time bash scripts/impacted-gate.sh --guards-only on main must stay under 180s, or re-slice. Rules: FAILURE-CLASSES row first for any bug fix (D86); no CHANGELOG edits (Release Manager writes notes); DECISIONS numbers assigned by the Chief of Staff; reuse util/secure_scan.ts, the shared badge helper, keys_cmd export and the TS claude login probe instead of new copies; new CLI flags update autonomy/completions and the help-drift guard. |
|
package/docs/v10/DECISIONS.md
CHANGED
|
@@ -857,3 +857,11 @@ FC-AGENT-PROOF: a run whose only executed passing check is a test file the same
|
|
|
857
857
|
4. Default on. Opt-out: LOKI_EXOGENOUS_PROOF=0 (exact string "0"; any other value, including "00" or "false", keeps the gate) restores the FC-16 executed-proof verdict. Provenance is still recorded under the opt-out.
|
|
858
858
|
- Cost accepted: some honest runs that only add new tests for new code now seal PARTIAL until a Wall or a pre-existing suite covers them. Reason: Seal accuracy ranks above delivered accuracy (operating model order).
|
|
859
859
|
- Reverse: only by a CTO call recorded here with a measured false-PARTIAL rate.
|
|
860
|
+
|
|
861
|
+
## D105 (2026-10-17, CTO call under D99, TEN-GATES-10): VERIFIED needs one agent-independent fact beside the agent's own suite
|
|
862
|
+
1. The agent writes both the code and its test suite, so a green suite alone is the agent grading its own work. `proof-generator.py` now records a pre-headline degraded item `exogenous_evidence` ("no agent-independent evidence (only the agent's own test suite passed)") when tests are verified and no exogenous fact passed, which turns that VERIFIED into VERIFIED WITH GAPS.
|
|
863
|
+
2. Counts as corroboration: build verified, healthcheck ok, functional_status verified, a security scan that ran and came back clean, or an exogenous quality gate that passed. An advisory (model-authored) gate pass never counts, including the `unit_tests` gate derived from the suite itself.
|
|
864
|
+
3. The item is a headline input (no `post_headline` flag), so `proof-verify.py` re-derives the same amber headline from the recorded ledger with no verifier change. The rule never moves a headline to green and never touches NOT VERIFIED.
|
|
865
|
+
4. Opt-out: `LOKI_PROOF_REQUIRE_EXOGENOUS=0` (exact string "0" after trimming; any other value keeps the requirement, fail-closed).
|
|
866
|
+
5. Ordering: the primary `loki start` route already writes build-results.json (TEN-GATES-09) and an exogenous security_scan gate (TEN-GATES-08), so a run with a real build or scan keeps VERIFIED. Health and functional facts arrive with TEN-GATES-07 (not yet merged when this landed); until then a route run whose stack has no build step and no scan result reads amber, which is the honest reading.
|
|
867
|
+
- Reverse: CTO call if field receipts show honest runs with real exogenous checks reading amber; the opt-out covers one-off needs.
|
package/docs/v10/PROGRESS.md
CHANGED
|
@@ -2482,3 +2482,6 @@ v11.17.21 published (Release success on 462fbc40a; npm latest 11.17.21, next 11.
|
|
|
2482
2482
|
|
|
2483
2483
|
## 2026-10-17T06:50Z (CoS) v11.17.34
|
|
2484
2484
|
- P0 fix-forward: seal.test roundtrip red root-caused to checksOf dropping n (TEN-GATES-03-F1 interaction); HIGH reviewer APPROVE c958f563c with revert-red 90/2 and 226 pass 0 fail across seal, roundtrip, verify_cmd, budget, spawn_env_guard. Cherry-picked (parent was the pre-amend release commit). Doctor red was stale dist. PO refill e9d9b63c8 added 24 rows; TEN-GATES-17 added from the review's remaining forgery path.
|
|
2485
|
+
|
|
2486
|
+
## 2026-10-17T07:09Z (CoS) v11.17.35
|
|
2487
|
+
- Wave Y: GATES-06, GATES-10, DEPLOY-05, DEPLOY-08 HIGH APPROVE; DEPLOY-09 not built (deps DEPLOY-05/06 were unmerged; its row names a wrong completions path and a missing help-drift test). GATES-10 hand-merge renumbered D104 to D105; pytest -k ExogenousEvidence 10 passed after the merge.
|