loki-mode 7.56.0 → 7.57.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/README.md +1 -1
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/app-runner.sh +101 -0
- package/autonomy/lib/prd-enrich.sh +437 -0
- package/autonomy/run.sh +175 -60
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +382 -2
- package/dashboard/static/index.html +164 -151
- package/docs/INSTALLATION.md +2 -2
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/skills/quality-gates.md +135 -11
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
|
|
4
4
|
|
|
5
|
-
**Version:** v7.
|
|
5
|
+
**Version:** v7.57.0
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -395,7 +395,7 @@ provider works inside the container. Provide auth with your Anthropic API key:
|
|
|
395
395
|
# Run Loki Mode in Docker (Claude provider, API-key auth)
|
|
396
396
|
docker run --rm -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
|
|
397
397
|
-v $(pwd):/workspace -w /workspace \
|
|
398
|
-
asklokesh/loki-mode:7.
|
|
398
|
+
asklokesh/loki-mode:7.57.0 start ./my-spec.md
|
|
399
399
|
```
|
|
400
400
|
|
|
401
401
|
##### docker compose + .env (no host install)
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var r6=Object.defineProperty;var t6=($)=>$;function i6($,Q){this[$]=t6.bind(null,Q)}var h=($,Q)=>{for(var Z in Q)r6($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:i6.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var K$=import.meta.require;var D1={};h(D1,{lokiDir:()=>P,homeLokiDir:()=>n$,findRepoRootForVersion:()=>o$,REPO_ROOT:()=>g});import{resolve as n,dirname as d$}from"path";import{fileURLToPath as e6}from"url";import{existsSync as P$}from"fs";import{homedir as $Q}from"os";function QQ(){let $=S1;for(let Q=0;Q<6;Q++){if(P$(n($,"VERSION"))&&P$(n($,"autonomy/run.sh")))return $;let Z=d$($);if(Z===$)break;$=Z}return n(S1,"..","..","..")}function o$($){let Q=$;for(let Z=0;Z<6;Z++){if(P$(n(Q,"VERSION"))&&P$(n(Q,"autonomy/run.sh")))return Q;let z=d$(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function n$(){return n($Q(),".loki")}var S1,g;var b=L(()=>{S1=d$(e6(import.meta.url));g=QQ()});import{readFileSync as ZQ}from"fs";import{resolve as zQ,dirname as XQ}from"path";import{fileURLToPath as KQ}from"url";function j$(){if($$!==null)return $$;let $="7.
|
|
2
|
+
var r6=Object.defineProperty;var t6=($)=>$;function i6($,Q){this[$]=t6.bind(null,Q)}var h=($,Q)=>{for(var Z in Q)r6($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:i6.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var K$=import.meta.require;var D1={};h(D1,{lokiDir:()=>P,homeLokiDir:()=>n$,findRepoRootForVersion:()=>o$,REPO_ROOT:()=>g});import{resolve as n,dirname as d$}from"path";import{fileURLToPath as e6}from"url";import{existsSync as P$}from"fs";import{homedir as $Q}from"os";function QQ(){let $=S1;for(let Q=0;Q<6;Q++){if(P$(n($,"VERSION"))&&P$(n($,"autonomy/run.sh")))return $;let Z=d$($);if(Z===$)break;$=Z}return n(S1,"..","..","..")}function o$($){let Q=$;for(let Z=0;Z<6;Z++){if(P$(n(Q,"VERSION"))&&P$(n(Q,"autonomy/run.sh")))return Q;let z=d$(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function n$(){return n($Q(),".loki")}var S1,g;var b=L(()=>{S1=d$(e6(import.meta.url));g=QQ()});import{readFileSync as ZQ}from"fs";import{resolve as zQ,dirname as XQ}from"path";import{fileURLToPath as KQ}from"url";function j$(){if($$!==null)return $$;let $="7.57.0";if(typeof $==="string"&&$.length>0)return $$=$,$$;try{let Q=XQ(KQ(import.meta.url)),Z=o$(Q);$$=ZQ(zQ(Z,"VERSION"),"utf-8").trim()}catch{$$="unknown"}return $$}var $$=null;var a$=L(()=>{b()});var b1={};h(b1,{runOrThrow:()=>qQ,run:()=>k,commandVersion:()=>WQ,commandExists:()=>f,ShellError:()=>s$});async function k($,Q={}){let Z=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:Q.env?{...process.env,...Q.env}:process.env,cwd:Q.cwd}),z,X;if(Q.timeoutMs&&Q.timeoutMs>0)z=setTimeout(()=>{try{Z.kill("SIGTERM")}catch{}X=setTimeout(()=>{try{Z.kill("SIGKILL")}catch{}},2000)},Q.timeoutMs);try{let[q,K,W]=await Promise.all([new Response(Z.stdout).text(),new Response(Z.stderr).text(),Z.exited]);return{stdout:q,stderr:K,exitCode:W}}finally{if(z)clearTimeout(z);if(X)clearTimeout(X)}}async function qQ($,Q={}){let Z=await k($,Q);if(Z.exitCode!==0)throw new s$(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function f($){let Q=VQ($),Z=await k(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function VQ($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function WQ($,Q="--version"){if(!await f($))return null;let z=await k([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var s$;var d=L(()=>{s$=class s$ extends Error{message;exitCode;stdout;stderr;constructor($,Q,Z,z){super($);this.message=$;this.exitCode=Q;this.stdout=Z;this.stderr=z;this.name="ShellError"}}});function a($){return JQ?"":$}var JQ,T,S,_,wZ,I,R,y,V;var c=L(()=>{JQ=(process.env.NO_COLOR??"").length>0;T=a("\x1B[0;31m"),S=a("\x1B[0;32m"),_=a("\x1B[1;33m"),wZ=a("\x1B[0;34m"),I=a("\x1B[0;36m"),R=a("\x1B[1m"),y=a("\x1B[2m"),V=a("\x1B[0m")});import{existsSync as wQ}from"fs";async function Q$(){if(G$!==void 0)return G$;let $="/opt/homebrew/bin/python3.12";if(wQ($))return G$=$,$;let Q=await f("python3.12");if(Q)return G$=Q,Q;let Z=await f("python3");return G$=Z,Z}async function Z$($,Q={}){let Z=await Q$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return k([Z,"-c",$],Q)}var G$;var q$=L(()=>{d()});var e1={};h(e1,{runStatus:()=>uQ});import{existsSync as v,readFileSync as W$,readdirSync as d1,statSync as o1}from"fs";import{resolve as C,basename as DQ}from"path";import{homedir as CQ}from"os";function n1($){let Q=Math.trunc($);if(Q>=1e6)return`${(Math.trunc(Q/1e6*10)/10).toFixed(1)}M`;if(Q>=1000)return`${(Math.trunc(Q/1000*10)/10).toFixed(1)}K`;return String(Q)}function a1($,Q,Z){if(Q===0)return null;let z=Math.trunc($*100/Q),X=Math.trunc($*k$/Q);if(X>k$)X=k$;let q=k$-X,K=S;if(z>=80)K=T;else if(z>=50)K=_;let W="=".repeat(Math.max(0,X))+" ".repeat(Math.max(0,q)),J=n1($),U=n1(Q);return` ${R}${Z}${V} ${K}[${W}]${V} ${z}% (${J} / ${U})`}async function hQ(){if(await f("jq"))return!0;return process.stdout.write(`${T}Error: jq is required but not installed.${V}
|
|
3
3
|
`),process.stdout.write(`Install with:
|
|
4
4
|
`),process.stdout.write(` brew install jq (macOS)
|
|
5
5
|
`),process.stdout.write(` apt install jq (Debian/Ubuntu)
|
|
@@ -790,4 +790,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
790
790
|
`),2}default:return process.stderr.write(`Unknown command: ${Q}
|
|
791
791
|
`),process.stderr.write(s6),2}}l1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var KZ=await XZ(Bun.argv.slice(2));process.exit(KZ);
|
|
792
792
|
|
|
793
|
-
//# debugId=
|
|
793
|
+
//# debugId=6D8496B2540606D064756E2164756E21
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.57.0",
|
|
5
5
|
"description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 8 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "loki-mode",
|
|
4
4
|
"displayName": "Loki Mode",
|
|
5
|
-
"version": "7.
|
|
5
|
+
"version": "7.57.0",
|
|
6
6
|
"description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Autonomi",
|
package/skills/quality-gates.md
CHANGED
|
@@ -2,18 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
**Never ship code without passing all quality gates.**
|
|
4
4
|
|
|
5
|
-
## The Quality Gates (8 default-on + 1 opt-in)
|
|
6
|
-
|
|
7
|
-
Every gate below is wired into the orchestration loop (`autonomy/run.sh`).
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
## The Quality Gates (8 blocking default-on + 3 advisory default-on + 1 opt-in)
|
|
6
|
+
|
|
7
|
+
Every gate below is wired into the orchestration loop (`autonomy/run.sh`). Read
|
|
8
|
+
the count honestly, split by what a gate actually does:
|
|
9
|
+
|
|
10
|
+
- **8 BLOCKING default-on gates** (the numbered table below): run by default and
|
|
11
|
+
FAIL the build / block completion when they trip.
|
|
12
|
+
- **3 ADVISORY default-on gates** (LSP diagnostics, semantic test-authenticity,
|
|
13
|
+
invariant/property; see the advisory table further down): run by default,
|
|
14
|
+
SURFACE actionable findings into the next iteration's prompt, and never block
|
|
15
|
+
by default. Two of them gain a blocking arm only via an explicit `*_BLOCK`
|
|
16
|
+
opt-in flag; LSP diagnostics has no blocking arm at all.
|
|
17
|
+
- **1 OPT-IN gate** (coverage, `LOKI_COVERAGE_GATE`, default OFF): does not run
|
|
18
|
+
unless explicitly enabled. It is the lone opt-in because it doubles test
|
|
19
|
+
runtime (instrumented re-run); see the coverage section for why.
|
|
20
|
+
|
|
21
|
+
So: 8 blocking gates run by default, plus 3 advisory surfacing gates and 1
|
|
22
|
+
opt-in coverage gate. Only the 8 numbered gates block out of the box; the
|
|
23
|
+
advisory gates surface findings without blocking, and the coverage gate is OFF
|
|
24
|
+
unless explicitly enabled. Never count the advisory or opt-in gates as blockers.
|
|
25
|
+
|
|
26
|
+
The numbered table below lists the 8 BLOCKING default-on gates: exactly what each
|
|
27
|
+
detects, what it does NOT detect (so you never over-trust a green gate), its
|
|
28
|
+
opt-out flag, and its blocking behavior. Transcribe this list verbatim; do not
|
|
29
|
+
recompute it.
|
|
13
30
|
|
|
14
31
|
| # | Gate | Detects | Does NOT detect | Blocking | Opt-out flag |
|
|
15
32
|
|---|------|---------|-----------------|----------|--------------|
|
|
16
|
-
| 1 | Static Analysis |
|
|
33
|
+
| 1 | Static Analysis | ESLint/Pylint, type-checker findings on the diff | Logic bugs that pass the linters | Yes (severity ladder) | `PHASE_STATIC_ANALYSIS=false` |
|
|
17
34
|
| 2 | Test Suite (pass/fail) | Whether the project test runner passes or fails (red blocks) | Coverage % (not measured in this release) | Yes (red blocks) | `PHASE_UNIT_TESTS=false` |
|
|
18
35
|
| 3 | Blind Code Review (3-reviewer council + severity blocking) | Correctness/security/design issues via 3 blind reviewers; Critical/High block, Medium/Low advisory | Issues none of the 3 reviewers surface | Yes (Crit/High block) | `PHASE_CODE_REVIEW=false` |
|
|
19
36
|
| 4 | Anti-Sycophancy / Devil's Advocate (on unanimous PASS) | Sycophantic unanimous approvals: a Devil's Advocate re-review on a unanimous PASS; its Crit/High findings block | Problems the Devil's Advocate reviewer also misses | Yes (DA Crit/High block) | `LOKI_GATE_DEVILS_ADVOCATE=false` |
|
|
@@ -21,7 +38,12 @@ this list verbatim; do not recompute it.
|
|
|
21
38
|
| 6 | Test Mutation Detector | Assertion-value churn alongside implementation changes (test-fitting), low assertion density (`tests/detect-test-mutations.sh`); HIGH blocks | Logically-correct-but-weak assertions | Yes (HIGH blocks) | `LOKI_GATE_MUTATION=false` |
|
|
22
39
|
| 7 | Documentation Coverage | README presence, docs freshness within 10 commits, API docs for exported symbols in packages | Whether the docs are accurate or useful | Yes | `LOKI_GATE_DOC_COVERAGE=false` |
|
|
23
40
|
| 8 | Magic Modules Debate | Spec-vs-implementation debate findings on generated Magic Modules; BLOCK-severity findings block | Issues outside the Magic Modules debate scope | Yes (BLOCK severity) | `LOKI_GATE_MAGIC_DEBATE=false` |
|
|
24
|
-
|
|
41
|
+
|
|
42
|
+
The three advisory default-on gates (LSP diagnostics, semantic
|
|
43
|
+
test-authenticity, invariant/property) are documented in their own table under
|
|
44
|
+
"Advisory default-on verification gates" below. Semantic test-authenticity used
|
|
45
|
+
to appear here as "gate 9 (opt-in, default OFF)"; it is now a default-on
|
|
46
|
+
advisory gate and has moved to that table. See the migration note there.
|
|
25
47
|
|
|
26
48
|
**Severity-based blocking** ties the review gates together: any Critical or High
|
|
27
49
|
finding blocks completion. Medium, Low, and cosmetic findings are advisory and
|
|
@@ -100,6 +122,108 @@ LOKI_GATE_MUTATION=false # Disable gate 6 (Test Mutation Detector)
|
|
|
100
122
|
|
|
101
123
|
---
|
|
102
124
|
|
|
125
|
+
## Advisory default-on verification gates (LSP, semantic, invariant)
|
|
126
|
+
|
|
127
|
+
These three gates extend the mock/mutation precedent (gates 5+6: default-on,
|
|
128
|
+
opt-out) into an ADVISORY-FIRST posture. They run by default, surface actionable
|
|
129
|
+
findings into the next iteration's prompt, and only BLOCK completion when their
|
|
130
|
+
opt-in `*_BLOCK` flag is set. LSP diagnostics has no blocking arm at all: it is
|
|
131
|
+
advisory by construction. Coverage is NOT in this group; it remains opt-in (see
|
|
132
|
+
the next section).
|
|
133
|
+
|
|
134
|
+
This is the FROZEN knob scheme. All flags accept `true` or `1`.
|
|
135
|
+
|
|
136
|
+
**Route scope (honest disclosure):** Bun-route parity is ACHIEVED for the
|
|
137
|
+
default-ON behavior. The Bun runner
|
|
138
|
+
(`loki-ts/src/runner/quality_gates.ts` `readToggles`) now defaults all three
|
|
139
|
+
advisory gates ON (`LOKI_GATE_SEMANTIC_TESTS`, `LOKI_GATE_INVARIANTS`,
|
|
140
|
+
`LOKI_GATE_LSP_DIAGNOSTICS` each `flag(X, true)`), matching the bash
|
|
141
|
+
`loki start` route (`autonomy/run.sh`), with blocking behind the same opt-in
|
|
142
|
+
`*_BLOCK` flags. Semantic and invariant findings surface into the next
|
|
143
|
+
iteration's prompt via the `build_prompt` readers
|
|
144
|
+
(`buildSemanticFindingsBlock` + `buildInvariantFindingsBlock`). The one real
|
|
145
|
+
remaining gap is a SURFACING ASYMMETRY: LSP runs default-ON on the Bun route,
|
|
146
|
+
but its advisory findings are NOT yet injected into the Bun prompt (LSP
|
|
147
|
+
contributes only the grounding instruction, not its diagnostics block). That
|
|
148
|
+
prompt-injection parity is still pending for LSP on the Bun route. This mirrors
|
|
149
|
+
the "Reachability note" at the end of this file for the v7.5.0 Phase 1 flags.
|
|
150
|
+
|
|
151
|
+
| Gate | Surfacing (advisory, default-ON, opt-out) | Blocking (opt-in, default-OFF) |
|
|
152
|
+
|------|--------------------------------------------|--------------------------------|
|
|
153
|
+
| LSP diagnostics | `LOKI_GATE_LSP_DIAGNOSTICS=true` | advisory-only, no blocking arm |
|
|
154
|
+
| Semantic test-authenticity | `LOKI_GATE_SEMANTIC_TESTS=true` | `LOKI_GATE_SEMANTIC_TESTS_BLOCK=true` |
|
|
155
|
+
| Invariant / property | `LOKI_GATE_INVARIANTS=true` | `LOKI_GATE_INVARIANTS_BLOCK=true` |
|
|
156
|
+
|
|
157
|
+
How to read the Surfacing column: each gate is already ON by default. The flag
|
|
158
|
+
shown is the gate's own toggle, and `true`/`1` is its enabled value (the default).
|
|
159
|
+
Set the flag to its off value (`false`/`0`) to OPT OUT of surfacing. Setting the
|
|
160
|
+
`=true` value is a no-op confirmation, not an opt-in: these are not opt-in gates.
|
|
161
|
+
|
|
162
|
+
How to read the Blocking column: by default these gates never block, they only
|
|
163
|
+
surface. To make a gate also block completion, set its `*_BLOCK` flag (default
|
|
164
|
+
OFF). The blocking arm fires only on a completion claim, and only on the gate's
|
|
165
|
+
high-severity findings; lower-severity findings stay advisory either way.
|
|
166
|
+
|
|
167
|
+
**What each gate surfaces:**
|
|
168
|
+
|
|
169
|
+
- **LSP diagnostics** (`LOKI_GATE_LSP_DIAGNOSTICS`, default on): language-server
|
|
170
|
+
diagnostics (errors/warnings) on the changed files. Advisory only; there is no
|
|
171
|
+
`_BLOCK` flag and no way to make it block. Inert when no language server is
|
|
172
|
+
available for the project's languages.
|
|
173
|
+
- **Semantic test-authenticity** (`LOKI_GATE_SEMANTIC_TESTS`, default on):
|
|
174
|
+
fake tests that look real but verify nothing (literal-via-variable echo,
|
|
175
|
+
mock-return echo, deleted assertions) that gates 5+6 miss
|
|
176
|
+
(`tests/detect-semantic-test-problems.sh`). Surfaces by default; blocks on
|
|
177
|
+
CRITICAL/HIGH only when `LOKI_GATE_SEMANTIC_TESTS_BLOCK=true`. Does NOT detect
|
|
178
|
+
deep dataflow, legitimate computed-literal assertions, or non-JS/TS tests
|
|
179
|
+
(JS/TS only).
|
|
180
|
+
- **Invariant / property** (`LOKI_GATE_INVARIANTS`, default on): property and
|
|
181
|
+
metamorphic invariant findings. Surfaces by default; blocks only when
|
|
182
|
+
`LOKI_GATE_INVARIANTS_BLOCK=true`.
|
|
183
|
+
|
|
184
|
+
**Advisory-first posture and deny-filter:** these gates run by default and feed
|
|
185
|
+
their findings into the next iteration's prompt so the agent can act on them.
|
|
186
|
+
They only stop a completion claim when the matching `*_BLOCK` opt-in is set. The
|
|
187
|
+
gates are deny-filtered: a clean result, an absent toolchain (e.g. no language
|
|
188
|
+
server, no test files in scope), or a timeout never fires the gate. The gate
|
|
189
|
+
surfaces or blocks only on real, parseable findings, so a missing toolchain does
|
|
190
|
+
not produce false surfacing or a false block.
|
|
191
|
+
|
|
192
|
+
### Migration: semantic and invariant flags were repurposed
|
|
193
|
+
|
|
194
|
+
`LOKI_GATE_SEMANTIC_TESTS` and `LOKI_GATE_INVARIANTS` changed meaning:
|
|
195
|
+
|
|
196
|
+
- **Before:** these flags were default-OFF opt-ins that, when set, made the gate
|
|
197
|
+
BLOCK completion. Semantic test-authenticity was documented as "gate 9
|
|
198
|
+
(opt-in, default OFF)" and blocked on CRITICAL/HIGH when
|
|
199
|
+
`LOKI_GATE_SEMANTIC_TESTS=true`.
|
|
200
|
+
- **Now:** these flags are default-ON surfacing toggles (set to `false`/`0` to
|
|
201
|
+
opt OUT of surfacing). They no longer block. Blocking moved to the new
|
|
202
|
+
`LOKI_GATE_SEMANTIC_TESTS_BLOCK` and `LOKI_GATE_INVARIANTS_BLOCK` opt-ins
|
|
203
|
+
(default OFF).
|
|
204
|
+
|
|
205
|
+
**Action required if you relied on the old behavior:** anyone who set
|
|
206
|
+
`LOKI_GATE_SEMANTIC_TESTS=true` (or `LOKI_GATE_INVARIANTS=true`) specifically to
|
|
207
|
+
BLOCK the build must now set `LOKI_GATE_SEMANTIC_TESTS_BLOCK=true` (or
|
|
208
|
+
`LOKI_GATE_INVARIANTS_BLOCK=true`). The old flag set to `true` now only confirms
|
|
209
|
+
the default-on surfacing and will NOT block. This is the one behavior change in
|
|
210
|
+
the migration: a flag that used to block now only surfaces.
|
|
211
|
+
|
|
212
|
+
### Coverage stays opt-in (the exception)
|
|
213
|
+
|
|
214
|
+
The coverage gate is the one verification gate that remains OPT-IN
|
|
215
|
+
(`LOKI_COVERAGE_GATE`, default OFF). It is the exception because measuring
|
|
216
|
+
coverage requires an instrumented SECOND test run, which roughly doubles test
|
|
217
|
+
runtime for every iteration. The advisory gates above add no such cost, so they
|
|
218
|
+
default on; coverage's cost is why it does not.
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
LOKI_COVERAGE_GATE=1 # opt in: measure + record coverage. Default OFF because
|
|
222
|
+
# it doubles test runtime (instrumented re-run). Even
|
|
223
|
+
# when enabled it measures and warns; it does not block
|
|
224
|
+
# unless LOKI_ENFORCE_COVERAGE=1 is also set.
|
|
225
|
+
```
|
|
226
|
+
|
|
103
227
|
## v7.5.0 Phase 1 environment flags
|
|
104
228
|
|
|
105
229
|
These four flags activate the override council and structured-findings
|
|
@@ -662,7 +786,7 @@ Initial excitement -> Velocity spike -> Quality degradation accumulates
|
|
|
662
786
|
```yaml
|
|
663
787
|
velocity_quality_balance:
|
|
664
788
|
before_commit:
|
|
665
|
-
- static_analysis: "Run ESLint/Pylint
|
|
789
|
+
- static_analysis: "Run ESLint/Pylint - warnings must not increase"
|
|
666
790
|
- complexity_check: "Cyclomatic complexity must not increase >10%"
|
|
667
791
|
- test_suite: "Tests must pass (coverage % not measured in this release)"
|
|
668
792
|
|