loki-mode 7.55.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/autonomy/loki CHANGED
@@ -726,8 +726,8 @@ show_help() {
726
726
  echo " help Show this help ('loki help aliases' for old names)"
727
727
  echo ""
728
728
  echo "More commands (grill, spec, cleanup, init, watch, demo, web, api,"
729
- echo "logs, github, import, council, proof, audit, agent, template, magic,"
730
- echo "docs, wiki, ci, test, bench, secrets, telemetry, crash, worktree,"
729
+ echo "logs, github, import, council, proof, audit, compliance, agent, template,"
730
+ echo "magic, docs, wiki, ci, test, bench, secrets, telemetry, crash, worktree,"
731
731
  echo "failover, monitor, remote, ...) are dispatchable and documented via"
732
732
  echo "'loki <command> --help'."
733
733
  echo ""
@@ -14530,6 +14530,9 @@ main() {
14530
14530
  audit)
14531
14531
  cmd_audit "$@"
14532
14532
  ;;
14533
+ compliance)
14534
+ cmd_compliance "$@"
14535
+ ;;
14533
14536
  review)
14534
14537
  cmd_review "$@"
14535
14538
  ;;
@@ -15853,6 +15856,211 @@ STATE_QUERY_PY
15853
15856
  }
15854
15857
 
15855
15858
  # Agent action audit log and quality scanning
15859
+ # Resolve the repo root (where src/audit lives) from the loki script dir.
15860
+ # _LOKI_SCRIPT_DIR is autonomy/; the JS audit modules live at ../src/audit.
15861
+ _loki_audit_repo_root() {
15862
+ ( cd "$_LOKI_SCRIPT_DIR/.." && pwd )
15863
+ }
15864
+
15865
+ # Link the run manifest (.loki/loki-run.json) into the agent audit chain for
15866
+ # the TARGET project (not the loki repo). Honest no-op when the manifest is
15867
+ # absent. Exit 0 on link or honest no-op; exit 1 only on a real error.
15868
+ cmd_audit_link_manifest() {
15869
+ local target_dir="${1:-$PWD}"
15870
+ if ! command -v node &>/dev/null; then
15871
+ echo -e "${RED}Error: node is required for 'loki audit link-manifest'${NC}"
15872
+ echo "Install Node.js, then re-run."
15873
+ return 1
15874
+ fi
15875
+ local repo_root
15876
+ repo_root="$(_loki_audit_repo_root)"
15877
+ local abs_target
15878
+ abs_target="$( cd "$target_dir" 2>/dev/null && pwd )" || {
15879
+ echo -e "${RED}Error: project dir not found: $target_dir${NC}"
15880
+ return 1
15881
+ }
15882
+
15883
+ echo -e "${BOLD}Linking run manifest into the audit chain...${NC}"
15884
+ echo " Project: $abs_target"
15885
+
15886
+ LOKI_AUDIT_MOD="$repo_root/src/audit" LOKI_AUDIT_TARGET="$abs_target" \
15887
+ node -e '
15888
+ const audit = require(process.env.LOKI_AUDIT_MOD);
15889
+ const res = audit.linkManifest({ projectDir: process.env.LOKI_AUDIT_TARGET });
15890
+ if (res.linked) {
15891
+ console.log(" linked: yes");
15892
+ console.log(" manifest: " + res.manifestPath);
15893
+ console.log(" sha256: " + res.manifestSha256);
15894
+ if (res.manifestSchema) console.log(" schema: " + res.manifestSchema);
15895
+ if (res.anchor && typeof res.anchor.seq !== "undefined") console.log(" anchor seq: " + res.anchor.seq);
15896
+ } else {
15897
+ console.log(" linked: no (" + (res.reason || "no-op") + ")");
15898
+ console.log(" manifest: " + res.manifestPath);
15899
+ }
15900
+ ' || {
15901
+ echo -e "${RED}Error: manifest link failed${NC}"
15902
+ return 1
15903
+ }
15904
+ return 0
15905
+ }
15906
+
15907
+ # Verify the run-manifest link for the TARGET project. Honest empty case
15908
+ # (no anchor recorded yet) exits 0; a real tamper/integrity failure exits 1.
15909
+ cmd_audit_verify_manifest() {
15910
+ local target_dir="${1:-$PWD}"
15911
+ if ! command -v node &>/dev/null; then
15912
+ echo -e "${RED}Error: node is required for 'loki audit verify-manifest'${NC}"
15913
+ echo "Install Node.js, then re-run."
15914
+ return 1
15915
+ fi
15916
+ local repo_root
15917
+ repo_root="$(_loki_audit_repo_root)"
15918
+ local abs_target
15919
+ abs_target="$( cd "$target_dir" 2>/dev/null && pwd )" || {
15920
+ echo -e "${RED}Error: project dir not found: $target_dir${NC}"
15921
+ return 1
15922
+ }
15923
+
15924
+ echo -e "${BOLD}Verifying run-manifest link...${NC}"
15925
+ echo " Project: $abs_target"
15926
+
15927
+ LOKI_AUDIT_MOD="$repo_root/src/audit" LOKI_AUDIT_TARGET="$abs_target" \
15928
+ node -e '
15929
+ const audit = require(process.env.LOKI_AUDIT_MOD);
15930
+ const res = audit.verifyManifestLink({ projectDir: process.env.LOKI_AUDIT_TARGET });
15931
+ const chainValid = res.chain && res.chain.valid;
15932
+ console.log(" chain integrity: " + (chainValid ? "valid" : "INVALID"));
15933
+ if (!res.present) {
15934
+ console.log(" manifest link: none recorded yet (no-op)");
15935
+ // Honest empty case: success only if the chain itself is valid.
15936
+ process.exit(chainValid ? 0 : 1);
15937
+ }
15938
+ const m = res.manifest || {};
15939
+ console.log(" manifest: " + (m.manifestPath || "?"));
15940
+ console.log(" pinned sha256: " + (m.pinnedSha256 || "?"));
15941
+ console.log(" current sha256: " + (m.currentSha256 || "(absent)"));
15942
+ if (res.valid) {
15943
+ console.log(" verdict: VALID (manifest matches anchored hash)");
15944
+ process.exit(0);
15945
+ } else {
15946
+ console.log(" verdict: TAMPERED / INVALID");
15947
+ if (m.error) console.log(" reason: " + m.error);
15948
+ process.exit(1);
15949
+ }
15950
+ '
15951
+ return $?
15952
+ }
15953
+
15954
+ # loki compliance - periodic compliance snapshot (SOC2 / ISO27001 / GDPR).
15955
+ # The scheduler is default-disabled (LOKI_COMPLIANCE_SNAPSHOT_INTERVAL_HOURS
15956
+ # unset or 0). `loki compliance snapshot` runs the self-rate-limiting check;
15957
+ # `--force` generates a snapshot now regardless of interval/elapsed gate.
15958
+ cmd_compliance() {
15959
+ local subcommand="${1:-help}"
15960
+
15961
+ case "$subcommand" in
15962
+ snapshot)
15963
+ shift
15964
+ local force="" target_dir="$PWD"
15965
+ while [[ $# -gt 0 ]]; do
15966
+ case "$1" in
15967
+ --force|-f) force="1"; shift ;;
15968
+ --help|-h)
15969
+ echo -e "${BOLD}loki compliance snapshot${NC} - Generate/check a compliance snapshot"
15970
+ echo ""
15971
+ echo "Usage: loki compliance snapshot [PROJECT_DIR] [--force]"
15972
+ echo ""
15973
+ echo "Without --force, respects the default-disabled interval"
15974
+ echo "(LOKI_COMPLIANCE_SNAPSHOT_INTERVAL_HOURS). Reports honestly:"
15975
+ echo " disabled interval unset/0 (default)"
15976
+ echo " not-elapsed interval not yet elapsed since last snapshot"
15977
+ echo " generated a new snapshot was written"
15978
+ echo ""
15979
+ echo "With --force, a snapshot is generated now regardless."
15980
+ echo "Snapshots are written to .loki/audit/compliance-snapshots/ in the project dir."
15981
+ return 0
15982
+ ;;
15983
+ -*) echo -e "${RED}Unknown option: $1${NC}"; return 1 ;;
15984
+ *) target_dir="$1"; shift ;;
15985
+ esac
15986
+ done
15987
+
15988
+ if ! command -v node &>/dev/null; then
15989
+ echo -e "${RED}Error: node is required for 'loki compliance snapshot'${NC}"
15990
+ echo "Install Node.js, then re-run."
15991
+ return 1
15992
+ fi
15993
+ local repo_root
15994
+ repo_root="$(_loki_audit_repo_root)"
15995
+ local abs_target
15996
+ abs_target="$( cd "$target_dir" 2>/dev/null && pwd )" || {
15997
+ echo -e "${RED}Error: project dir not found: $target_dir${NC}"
15998
+ return 1
15999
+ }
16000
+
16001
+ echo -e "${BOLD}Compliance snapshot${NC}"
16002
+ echo " Project: $abs_target"
16003
+
16004
+ LOKI_SCHED_MOD="$repo_root/src/audit/compliance-scheduler.js" \
16005
+ LOKI_SCHED_TARGET="$abs_target" LOKI_SCHED_FORCE="$force" \
16006
+ node -e '
16007
+ const sched = require(process.env.LOKI_SCHED_MOD);
16008
+ const target = process.env.LOKI_SCHED_TARGET;
16009
+ const force = process.env.LOKI_SCHED_FORCE === "1";
16010
+ if (force) {
16011
+ const now = Date.now();
16012
+ const snapshot = sched.buildSnapshot({ projectDir: target, nowMs: now });
16013
+ const file = sched.persistSnapshot({ projectDir: target, snapshot: snapshot, nowMs: now });
16014
+ console.log(" result: generated (forced)");
16015
+ console.log(" path: " + file);
16016
+ console.log(" audit entries: " + snapshot.totalAuditEntries);
16017
+ process.exit(0);
16018
+ }
16019
+ const res = sched.maybeGenerateSnapshot({ projectDir: target });
16020
+ if (res.generated) {
16021
+ console.log(" result: generated");
16022
+ console.log(" path: " + res.path);
16023
+ console.log(" interval (hours): " + res.intervalHours);
16024
+ } else if (res.reason === "disabled") {
16025
+ console.log(" result: disabled (scheduler off; default)");
16026
+ console.log(" enable: set LOKI_COMPLIANCE_SNAPSHOT_INTERVAL_HOURS=<N>, or use --force to generate now");
16027
+ } else if (res.reason === "not-elapsed") {
16028
+ console.log(" result: not-elapsed (interval not yet reached)");
16029
+ console.log(" interval (hours): " + res.intervalHours);
16030
+ if (res.nextEligibleAtMs) console.log(" next eligible: " + new Date(res.nextEligibleAtMs).toISOString());
16031
+ console.log(" override: use --force to generate now");
16032
+ } else {
16033
+ console.log(" result: " + (res.reason || "no-op"));
16034
+ }
16035
+ process.exit(0);
16036
+ ' || {
16037
+ echo -e "${RED}Error: compliance snapshot failed${NC}"
16038
+ return 1
16039
+ }
16040
+ return 0
16041
+ ;;
16042
+ --help|-h|help)
16043
+ echo -e "${BOLD}loki compliance${NC} - Periodic compliance snapshots"
16044
+ echo ""
16045
+ echo "Usage: loki compliance <subcommand> [options]"
16046
+ echo ""
16047
+ echo "Subcommands:"
16048
+ echo " snapshot [DIR] [--force] Generate/check a compliance snapshot"
16049
+ echo " help Show this help"
16050
+ echo ""
16051
+ echo "The compliance scheduler is default-disabled. A snapshot bundles the"
16052
+ echo "SOC2, ISO27001 and GDPR reports plus the audit chain-integrity verdict"
16053
+ echo "into .loki/audit/compliance-snapshots/. Enable periodic generation by setting"
16054
+ echo "LOKI_COMPLIANCE_SNAPSHOT_INTERVAL_HOURS, or run with --force on demand."
16055
+ ;;
16056
+ *)
16057
+ echo -e "${RED}Unknown compliance subcommand: $subcommand${NC}"
16058
+ echo "Run 'loki compliance help' for usage."
16059
+ exit 1
16060
+ ;;
16061
+ esac
16062
+ }
16063
+
15856
16064
  cmd_audit() {
15857
16065
  local subcommand="${1:-help}"
15858
16066
  local audit_file="$LOKI_DIR/logs/agent-audit.jsonl"
@@ -16148,23 +16356,51 @@ print()
16148
16356
  fi
16149
16357
  ;;
16150
16358
 
16359
+ link-manifest)
16360
+ # Fold the run manifest (.loki/loki-run.json bill-of-materials) into
16361
+ # the agent audit chain so it becomes tamper-evident and verifiable
16362
+ # against the evidence chain. Explicit, on-demand command: cmd_start
16363
+ # execs run.sh and replaces the loki process, so there is no
16364
+ # post-completion return point in this CLI wrapper to auto-invoke
16365
+ # from. Honest no-op (exit 0) when the manifest is absent.
16366
+ shift
16367
+ local target_dir="${1:-$PWD}"
16368
+ cmd_audit_link_manifest "$target_dir"
16369
+ ;;
16370
+ verify-manifest)
16371
+ # Verify the run-manifest link: agent chain integrity AND the on-disk
16372
+ # manifest still matching the hash pinned by the most recent
16373
+ # manifest-link anchor. Honest empty case (exit 0) when no anchor was
16374
+ # recorded yet; nonzero only on a real tamper/integrity failure.
16375
+ shift
16376
+ local target_dir="${1:-$PWD}"
16377
+ cmd_audit_verify_manifest "$target_dir"
16378
+ ;;
16151
16379
  --help|-h|help)
16152
16380
  echo -e "${BOLD}loki audit${NC} - Agent audit log and quality scanning"
16153
16381
  echo ""
16154
16382
  echo "Usage: loki audit <subcommand> [options]"
16155
16383
  echo ""
16156
16384
  echo "Subcommands:"
16157
- echo " log [N] Show last N audit log entries (default: 50)"
16158
- echo " count Count actions by type"
16159
- echo " scan Run quality scan against dashboard API"
16160
- echo " lint Run static analysis on project files"
16161
- echo " test Run test coverage check"
16162
- echo " help Show this help"
16385
+ echo " log [N] Show last N audit log entries (default: 50)"
16386
+ echo " count Count actions by type"
16387
+ echo " scan Run quality scan against dashboard API"
16388
+ echo " lint Run static analysis on project files"
16389
+ echo " test Run test coverage check"
16390
+ echo " link-manifest [P] Link the run manifest into the audit chain (tamper-evidence)"
16391
+ echo " verify-manifest [P] Verify the run-manifest link against the evidence chain"
16392
+ echo " help Show this help"
16163
16393
  echo ""
16164
16394
  echo "Quality Scan Options (loki audit scan):"
16165
16395
  echo " --preset NAME Compliance preset (default|healthcare|fintech|government)"
16166
16396
  echo " --export Save report to .loki/quality/report-{date}.json"
16167
16397
  echo ""
16398
+ echo "Manifest tamper-evidence (loki audit link-manifest / verify-manifest):"
16399
+ echo " Hashes .loki/loki-run.json (the build bill-of-materials) into the"
16400
+ echo " agent audit chain. link-manifest no-ops honestly if the manifest is"
16401
+ echo " absent; verify-manifest reports honestly if no anchor exists yet."
16402
+ echo " Optional [P] is the project dir (default: current directory)."
16403
+ echo ""
16168
16404
  echo "The agent audit log records actions taken during Loki sessions,"
16169
16405
  echo "including CLI invocations, git commits, and session lifecycle events."
16170
16406
  echo "Log file: $audit_file"
package/autonomy/run.sh CHANGED
@@ -8320,23 +8320,31 @@ enforce_mutation_integrity() {
8320
8320
  }
8321
8321
 
8322
8322
  # ============================================================================
8323
- # Semantic Test-Authenticity Gate (P1-3): wire tests/detect-semantic-test-problems.sh
8324
- # as an OPT-IN completion gate. The detector catches the harder class of fake
8325
- # tests that the regex detectors (gates 5+6) miss: assertions that look real but
8326
- # verify nothing because the asserted value never flows through code under test
8327
- # (literal-via-variable echo HIGH, mock-return echo MED, deleted assertions MED).
8323
+ # Semantic Test-Authenticity Gate (P1-3): wire tests/detect-semantic-test-problems.sh.
8324
+ # The detector catches the harder class of fake tests that the regex detectors
8325
+ # (gates 5+6) miss: assertions that look real but verify nothing because the
8326
+ # asserted value never flows through code under test (literal-via-variable echo
8327
+ # HIGH, mock-return echo MED, deleted assertions MED).
8328
8328
  #
8329
- # ADVISORY-FIRST POSTURE (no-deadlock contract): this helper is invoked ONLY when
8330
- # LOKI_GATE_SEMANTIC_TESTS=true (the elif guard at the completion-promise arm
8331
- # short-circuits when off, so there is zero runtime cost on the default path).
8332
- # When on, it runs the detector with --block-high (clean exit-code contract:
8333
- # rc 2 iff a CRITICAL/HIGH finding exists). We surface ALL severities to a
8334
- # findings file (advisory) and return nonzero ONLY on rc 2. Every other exit --
8335
- # rc 0 (clean), rc 124 (timeout), detector absent, no test files, malformed
8336
- # output -- returns 0 (pass/fall-through), so the autonomous loop can NEVER
8337
- # deadlock on a clean run. Mirrors enforce_mock_integrity's invocation
8338
- # (cd TARGET_DIR + LOKI_SCAN_DIR=TARGET_DIR + timeout), swapping --strict for
8339
- # --block-high and deciding on the rc-2 contract instead of grepping stdout.
8329
+ # POSTURE (v7.57.0): this enforce_* helper is the shared core for TWO callers:
8330
+ # 1) the DEFAULT-ON mid-iteration ADVISORY arm (gated on LOKI_GATE_SEMANTIC_TESTS,
8331
+ # default true) -- runs every iteration, writes findings, and on a CRIT/HIGH
8332
+ # result the arm only calls track_gate_failure (surfaces to the next prompt),
8333
+ # NEVER PAUSEs / NEVER rejects completion (clone of the mock arm).
8334
+ # 2) the OPT-IN completion-BLOCKING elif (gated on LOKI_GATE_SEMANTIC_TESTS_BLOCK,
8335
+ # default false) -- when set, rejects the completion claim on a CRIT/HIGH.
8336
+ # The default-on flip applies ONLY to surfacing; blocking stays opt-in via the
8337
+ # separate _BLOCK flag, so surfacing-default-on does NOT make blocking default-on.
8338
+ #
8339
+ # NO-DEADLOCK CONTRACT: it runs the detector with --block-high (clean exit-code
8340
+ # contract: rc 2 iff a CRITICAL/HIGH finding exists). It surfaces ALL severities
8341
+ # to a findings file (advisory) and returns nonzero ONLY on rc 2. Every other
8342
+ # exit -- rc 0 (clean), rc 124 (timeout), detector absent, no test files,
8343
+ # malformed output -- returns 0 (pass/fall-through), so the autonomous loop can
8344
+ # NEVER deadlock on a clean run (default-on surfacing is therefore deadlock-safe,
8345
+ # exactly as the mock/mutation gates prove in production). Mirrors
8346
+ # enforce_mock_integrity's invocation (cd TARGET_DIR + LOKI_SCAN_DIR=TARGET_DIR +
8347
+ # timeout), swapping --strict for --block-high and deciding on the rc-2 contract.
8340
8348
  # ============================================================================
8341
8349
  enforce_semantic_integrity() {
8342
8350
  local loki_dir="${TARGET_DIR:-.}/.loki"
@@ -8416,9 +8424,19 @@ _semantic_gate_and_surface() {
8416
8424
  # redirect the scan).
8417
8425
  # The PLURAL token LOKI_GATE_INVARIANTS is used deliberately to match the Bun
8418
8426
  # readToggles flag name; the detector's own reference comment suggests a
8419
- # singular default-on variant (no trailing S), which is NOT used here (parity
8420
- # needs the plural, and this gate is OPT-IN / default OFF like the semantic
8421
- # gate).
8427
+ # singular variant (no trailing S), which is NOT used here (parity needs the
8428
+ # plural).
8429
+ #
8430
+ # POSTURE (v7.57.0): this enforce_* helper is the shared core for TWO callers,
8431
+ # mirroring enforce_semantic_integrity:
8432
+ # 1) the DEFAULT-ON mid-iteration ADVISORY arm (gated on LOKI_GATE_INVARIANTS,
8433
+ # default true) -- runs every iteration, writes invariant-findings.txt, and
8434
+ # on a CRIT/HIGH result the arm only calls track_gate_failure (surfaces to
8435
+ # the next prompt via the invariant injector in build_prompt), NEVER PAUSEs /
8436
+ # NEVER rejects completion.
8437
+ # 2) the OPT-IN completion-BLOCKING elif (gated on LOKI_GATE_INVARIANTS_BLOCK,
8438
+ # default false) -- when set, rejects the completion claim on a CRIT/HIGH.
8439
+ # Surfacing-default-on does NOT make blocking default-on (separate _BLOCK flag).
8422
8440
  enforce_invariant_integrity() {
8423
8441
  local loki_dir="${TARGET_DIR:-.}/.loki"
8424
8442
  local quality_dir="$loki_dir/quality"
@@ -12435,6 +12453,21 @@ if d.get('blocked'):
12435
12453
  fi
12436
12454
  fi
12437
12455
 
12456
+ # P1-4 / v7.57.0: surface specific invariant/property findings (which file,
12457
+ # which violated invariant) when the default-on advisory gate (or the opt-in
12458
+ # LOKI_GATE_INVARIANTS_BLOCK gate) wrote them, so a block converges and an
12459
+ # advisory run still informs the next iteration. The file exists only when
12460
+ # the gate ran AND found something (cleared on clean), so this is zero-cost on
12461
+ # a clean run and when the surfacing gate is opted out. Mirrors the semantic
12462
+ # injector above and is independent of gate-failures.txt presence.
12463
+ if [ -f "${TARGET_DIR:-.}/.loki/quality/invariant-findings.txt" ]; then
12464
+ local inv_findings
12465
+ inv_findings=$(grep -E '\[(CRITICAL|HIGH|MEDIUM|LOW)\]' "${TARGET_DIR:-.}/.loki/quality/invariant-findings.txt" 2>/dev/null | head -20 || true)
12466
+ if [ -n "$inv_findings" ]; then
12467
+ gate_failure_context="${gate_failure_context} INVARIANT/PROPERTY FINDINGS (fix the violated invariants; the code must preserve the stated property/metamorphic relation, not just pass example-based tests): ${inv_findings}"
12468
+ fi
12469
+ fi
12470
+
12438
12471
  # P2-2: high-severity spec-assumption context. When DISCOVERY recorded any
12439
12472
  # high-severity assumption (the spec was ambiguous in a high-impact place),
12440
12473
  # surface it to the build agent so it implements with the gap in view (or
@@ -13461,9 +13494,12 @@ if not features:
13461
13494
  continue
13462
13495
  clean_name = strip_numbering(section_name)
13463
13496
  if len(section_content) > 20 and len(clean_name) > 5:
13497
+ # BUG-A fix: store the REAL section/heading key (not a hardcoded
13498
+ # "Requirements") so sections.get(feat["section"]) later resolves
13499
+ # to this section's body and the description is not just the title.
13464
13500
  features.append({
13465
13501
  "title": clean_name,
13466
- "section": "Requirements",
13502
+ "section": section_name,
13467
13503
  })
13468
13504
 
13469
13505
  if not features:
@@ -13601,6 +13637,20 @@ PRD_PARSE_EOF
13601
13637
  return 0
13602
13638
  fi
13603
13639
 
13640
+ # LLM enrichment post-pass (v7.52.0). The python heredoc above has no model
13641
+ # access, so stub tasks (description == title, or the templated user_story)
13642
+ # are enriched here via one batched provider call. Best-effort: on any
13643
+ # failure (non-claude provider, degraded mode, no binary, timeout, parse
13644
+ # error) the deterministic output is left intact. Never blocks the queue.
13645
+ local _prd_enrich_lib="$SCRIPT_DIR/lib/prd-enrich.sh"
13646
+ if [ -f "$_prd_enrich_lib" ]; then
13647
+ # shellcheck source=lib/prd-enrich.sh
13648
+ source "$_prd_enrich_lib" 2>/dev/null || true
13649
+ if declare -f loki_prd_enrich >/dev/null 2>&1; then
13650
+ loki_prd_enrich ".loki/queue/pending.json" "$effective_prd" || true
13651
+ fi
13652
+ fi
13653
+
13604
13654
  touch ".loki/queue/.prd-populated"
13605
13655
  log_info "PRD task parsing complete"
13606
13656
  }
@@ -15146,27 +15196,39 @@ if __name__ == "__main__":
15146
15196
  log_warn "Mutation integrity gate FAILED ($mt_count consecutive) - HIGH test-fitting detected"
15147
15197
  fi
15148
15198
  fi
15149
- # LSP diagnostics gate (P1-5 bash-route parity, v7.51.0). Closes the
15150
- # parity gap: the Bun route ships runLSPDiagnostics
15151
- # (loki-ts/src/runner/quality_gates.ts) with a route-neutral Python
15152
- # writer (mcp/lsp_proxy.py); the bash route had NO writer/reader.
15153
- # This block runs the SAME writer and mirrors the TS blocking
15154
- # semantics byte-for-byte:
15155
- # - Gate is OPT-IN: default OFF. Enabled by LOKI_GATE_LSP_DIAGNOSTICS=true
15156
- # (the single toggle; mirrors flag("LOKI_GATE_LSP_DIAGNOSTICS", false)
15157
- # at quality_gates.ts:1717). No second knob.
15158
- # - When enabled, count_errors > 0 -> BLOCK (mirrors
15159
- # "if (errorCount > 0) { passed: false }" at quality_gates.ts:1667).
15199
+ # LSP diagnostics gate (P1-5 bash-route parity, v7.51.0; default-on
15200
+ # advisory-surfacing as of v7.57.0). Closes the parity gap: the Bun
15201
+ # route ships runLSPDiagnostics (loki-ts/src/runner/quality_gates.ts)
15202
+ # with a route-neutral Python writer (mcp/lsp_proxy.py); the bash
15203
+ # route had NO writer/reader.
15204
+ #
15205
+ # POSTURE (v7.57.0): DEFAULT-ON SURFACING (no blocking arm exists).
15206
+ # This is the mid-iteration advisory arm -- it RUNS by default (like
15207
+ # the mock/mutation gates), writes lsp-diagnostics.json, and surfaces
15208
+ # errors to the NEXT iteration via track_gate_failure (the
15209
+ # lsp_diagnostics token flows into gate-failures.txt -> build_prompt).
15210
+ # It does NOT reject completion: the "block*" case below only calls
15211
+ # track_gate_failure, never PAUSE / never the completion-promise arm,
15212
+ # exactly like the mock gate. Default-on surfacing CANNOT deadlock
15213
+ # (mock/mutation prove this in production); there is therefore NO
15214
+ # separate blocking knob for LSP (none ever existed on the bash route).
15215
+ # - Toggle: LOKI_GATE_LSP_DIAGNOSTICS (default TRUE = surfacing on;
15216
+ # opt out with =false). Accepts "true" or "1". Single knob (no
15217
+ # blocking arm exists on the bash route, so there is no _BLOCK flag).
15218
+ # - count_errors > 0 -> surface (track_gate_failure), mirroring the
15219
+ # TS "errorCount > 0" finding at quality_gates.ts:1667 but WITHOUT
15220
+ # rejecting completion (advisory-first on the bash route).
15160
15221
  # - warnings only -> advisory PASS (quality_gates.ts:1673).
15161
- # - artifact absent/malformed -> honest pass-through, NEVER block
15162
- # (quality_gates.ts:1646 returns passed:true on null artifact).
15222
+ # - artifact absent/malformed/timeout -> honest pass-through, NEVER
15223
+ # surface a block, NEVER deadlock (deny-filter; mirrors
15224
+ # quality_gates.ts:1646 returning passed:true on null artifact).
15163
15225
  # The writer is OPT-OUT-able with LOKI_GATE_LSP_WRITER=0 (operator can
15164
15226
  # supply a pre-built artifact), matching the TS escape hatch
15165
15227
  # (quality_gates.ts:1630). cwd must be the install dir (PROJECT_DIR =
15166
15228
  # $SCRIPT_DIR/.. ) so `-m mcp.lsp_proxy` imports, while --root points
15167
15229
  # at the TARGET project the loop is building (mirrors
15168
15230
  # runLSPDiagnosticsWriter: cwd=REPO_ROOT, --root=ctx.cwd).
15169
- if [ "${LOKI_GATE_LSP_DIAGNOSTICS:-false}" = "true" ] && [ "$ITERATION_COUNT" -gt 0 ]; then
15231
+ if { [ "${LOKI_GATE_LSP_DIAGNOSTICS:-true}" = "true" ] || [ "${LOKI_GATE_LSP_DIAGNOSTICS:-true}" = "1" ]; } && [ "$ITERATION_COUNT" -gt 0 ]; then
15170
15232
  log_info "Quality gate: LSP diagnostics..."
15171
15233
  # WRITER: route-neutral Python, same program as the Bun route.
15172
15234
  if [ "${LOKI_GATE_LSP_WRITER:-1}" != "0" ]; then
@@ -15228,6 +15290,54 @@ else:
15228
15290
  ;;
15229
15291
  esac
15230
15292
  fi
15293
+ # Semantic test-authenticity gate -- mid-iteration ADVISORY arm
15294
+ # (v7.57.0 default-on surfacing). Clones the mock arm (~15126)
15295
+ # byte-for-byte: runs enforce_semantic_integrity, which writes
15296
+ # semantic-findings.txt and returns 1 ONLY on a CRITICAL/HIGH
15297
+ # fake-test finding (clean / no-test-files / detector-absent / timeout
15298
+ # / malformed all collapse to rc 0 inside the function -- deny-filter).
15299
+ # On rc 1 we ONLY track_gate_failure (surface to the next prompt via
15300
+ # the semantic-findings injector at build_prompt); we NEVER PAUSE and
15301
+ # NEVER reject completion here. Default-on surfacing cannot deadlock
15302
+ # (mock/mutation prove this in production). The opt-in completion-
15303
+ # BLOCKING arm lives behind LOKI_GATE_SEMANTIC_TESTS_BLOCK at the
15304
+ # completion-promise elif below; this surfacing arm is independent.
15305
+ # - Toggle: LOKI_GATE_SEMANTIC_TESTS (default TRUE = surfacing on;
15306
+ # opt out with =false). Accepts "true" or "1".
15307
+ if { [ "${LOKI_GATE_SEMANTIC_TESTS:-true}" = "true" ] || [ "${LOKI_GATE_SEMANTIC_TESTS:-true}" = "1" ]; } && [ "$ITERATION_COUNT" -gt 0 ]; then
15308
+ log_info "Quality gate: semantic test-authenticity (advisory)..."
15309
+ if enforce_semantic_integrity; then
15310
+ clear_gate_failure "semantic_tests"
15311
+ else
15312
+ local sem_count
15313
+ sem_count=$(track_gate_failure "semantic_tests")
15314
+ gate_failures="${gate_failures}semantic_tests,"
15315
+ log_warn "Semantic test-authenticity gate FAILED ($sem_count consecutive) - CRITICAL/HIGH fake-test problems (advisory; surfaced to next iteration)"
15316
+ fi
15317
+ fi
15318
+ # Invariant/property gate -- mid-iteration ADVISORY arm (v7.57.0
15319
+ # default-on surfacing). Mirrors the semantic arm above: runs
15320
+ # enforce_invariant_integrity, which writes invariant-findings.txt and
15321
+ # returns 1 ONLY on a CRITICAL/HIGH invariant violation (clean /
15322
+ # detector-absent / timeout / malformed all collapse to rc 0 inside
15323
+ # the function -- deny-filter). On rc 1 we ONLY track_gate_failure
15324
+ # (surfaced to the next prompt via the invariant-findings injector in
15325
+ # build_prompt); we NEVER PAUSE and NEVER reject completion here. The
15326
+ # opt-in completion-BLOCKING arm lives behind LOKI_GATE_INVARIANTS_BLOCK
15327
+ # at the completion-promise elif below.
15328
+ # - Toggle: LOKI_GATE_INVARIANTS (default TRUE = surfacing on; opt
15329
+ # out with =false). Accepts "true" or "1".
15330
+ if { [ "${LOKI_GATE_INVARIANTS:-true}" = "true" ] || [ "${LOKI_GATE_INVARIANTS:-true}" = "1" ]; } && [ "$ITERATION_COUNT" -gt 0 ]; then
15331
+ log_info "Quality gate: invariant/property (advisory)..."
15332
+ if enforce_invariant_integrity; then
15333
+ clear_gate_failure "invariants"
15334
+ else
15335
+ local inv_count
15336
+ inv_count=$(track_gate_failure "invariants")
15337
+ gate_failures="${gate_failures}invariants,"
15338
+ log_warn "Invariant gate FAILED ($inv_count consecutive) - CRITICAL/HIGH invariant/property violations (advisory; surfaced to next iteration)"
15339
+ fi
15340
+ fi
15231
15341
  # Code review gate (upgraded from advisory, with escalation)
15232
15342
  if [ "$PHASE_CODE_REVIEW" = "true" ] && [ "$ITERATION_COUNT" -gt 0 ]; then
15233
15343
  log_info "Quality gate: code review..."
@@ -15534,35 +15644,40 @@ else:
15534
15644
  log_warn "Completion claim rejected: assumption ledger gate found unresolved high-severity spec assumption(s)."
15535
15645
  log_warn " Details under .loki/council/assumption-block.json ; opt out with LOKI_ASSUMPTION_GATE=0"
15536
15646
  # Fall through; keep iterating until high-sev assumptions resolve.
15537
- # P1-3: semantic test-authenticity gate (OPT-IN, default OFF). Catches
15538
- # fake tests that look real but verify nothing (literal-via-variable
15539
- # echo etc.) that the regex gates 5+6 miss. ADVISORY-FIRST: the arm is
15540
- # guarded by LOKI_GATE_SEMANTIC_TESTS=true, so by default it never runs
15541
- # (zero runtime cost, never blocks). When enabled it runs the detector
15542
- # with --block-high and rejects the completion ONLY on a CRITICAL/HIGH
15543
- # finding; clean / no-test-files / detector-absent / timeout / malformed
15544
- # all collapse to a pass inside _semantic_gate_and_surface, so the
15545
- # autonomous loop can never deadlock on a clean run. Mirrors the
15546
- # evidence / held-out / assumption arms above.
15547
- elif [ "$_completion_claimed" = 1 ] && [ "${LOKI_GATE_SEMANTIC_TESTS:-false}" = "true" ] && type _semantic_gate_and_surface &>/dev/null && ! _semantic_gate_and_surface; then
15647
+ # P1-3: semantic test-authenticity completion-BLOCKING gate (OPT-IN,
15648
+ # default OFF). Catches fake tests that look real but verify nothing
15649
+ # (literal-via-variable echo etc.) that the regex gates 5+6 miss.
15650
+ # v7.57.0: the SURFACING of these findings is now default-on (see the
15651
+ # mid-iteration advisory arm above, gated on LOKI_GATE_SEMANTIC_TESTS,
15652
+ # default true). This completion-BLOCKING arm is a SEPARATE opt-in,
15653
+ # gated on LOKI_GATE_SEMANTIC_TESTS_BLOCK (default OFF; accepts "true"
15654
+ # or "1"), so the surfacing-default-on flip does NOT make blocking
15655
+ # default-on. When the BLOCK flag is set it runs the detector with --block-high and
15656
+ # rejects completion ONLY on a CRITICAL/HIGH finding; clean /
15657
+ # no-test-files / detector-absent / timeout / malformed all collapse
15658
+ # to a pass inside _semantic_gate_and_surface, so the autonomous loop
15659
+ # can never deadlock on a clean run. Mirrors the evidence / held-out /
15660
+ # assumption arms above.
15661
+ elif [ "$_completion_claimed" = 1 ] && { [ "${LOKI_GATE_SEMANTIC_TESTS_BLOCK:-false}" = "true" ] || [ "${LOKI_GATE_SEMANTIC_TESTS_BLOCK:-false}" = "1" ]; } && type _semantic_gate_and_surface &>/dev/null && ! _semantic_gate_and_surface; then
15548
15662
  log_warn "Completion claim rejected: semantic test-authenticity gate found CRITICAL/HIGH fake-test problem(s)."
15549
- log_warn " Details under .loki/quality/semantic-findings.txt ; opt-in gate -- disable with LOKI_GATE_SEMANTIC_TESTS=false"
15663
+ log_warn " Details under .loki/quality/semantic-findings.txt ; opt-in blocking -- disable with LOKI_GATE_SEMANTIC_TESTS_BLOCK=false"
15550
15664
  # Fall through; keep iterating until the fake tests are fixed.
15551
- # P1-4: invariant/property gate (OPT-IN, default OFF). Mirrors the
15552
- # semantic arm above and the Bun route's invariants toggle
15553
- # (loki-ts/src/runner/quality_gates.ts:2057). Guarded by
15554
- # LOKI_GATE_INVARIANTS (PLURAL, to match the Bun readToggles flag
15555
- # name; the detector's reference-comment singular default-on variant
15556
- # without the trailing S is deliberately NOT used). Accepts "true" or
15557
- # "1"; default OFF means the arm never runs (zero cost, never
15558
- # blocks). When enabled it runs detect-invariant-violations.sh
15559
- # --strict and rejects completion ONLY on a CRITICAL/HIGH (rc 1)
15560
- # finding; clean / detector-absent / timeout / malformed all
15561
- # collapse to a pass inside _invariant_gate_and_surface, so the
15562
- # autonomous loop can never deadlock on a clean run.
15563
- elif [ "$_completion_claimed" = 1 ] && { [ "${LOKI_GATE_INVARIANTS:-false}" = "true" ] || [ "${LOKI_GATE_INVARIANTS:-false}" = "1" ]; } && type _invariant_gate_and_surface &>/dev/null && ! _invariant_gate_and_surface; then
15665
+ # P1-4: invariant/property completion-BLOCKING gate (OPT-IN, default
15666
+ # OFF). Mirrors the semantic arm above and the Bun route's invariants
15667
+ # toggle (loki-ts/src/runner/quality_gates.ts:2057). v7.57.0: the
15668
+ # SURFACING of these findings is now default-on (see the mid-iteration
15669
+ # advisory arm above, gated on LOKI_GATE_INVARIANTS, default true).
15670
+ # This completion-BLOCKING arm is a SEPARATE opt-in, gated on
15671
+ # LOKI_GATE_INVARIANTS_BLOCK (default OFF), so the surfacing-default-on
15672
+ # flip does NOT make blocking default-on. Accepts "true" or "1". When
15673
+ # the BLOCK flag is set it runs detect-invariant-violations.sh --strict
15674
+ # and rejects completion ONLY on a CRITICAL/HIGH (rc 1) finding;
15675
+ # clean / detector-absent / timeout / malformed all collapse to a pass
15676
+ # inside _invariant_gate_and_surface, so the autonomous loop can never
15677
+ # deadlock on a clean run.
15678
+ elif [ "$_completion_claimed" = 1 ] && { [ "${LOKI_GATE_INVARIANTS_BLOCK:-false}" = "true" ] || [ "${LOKI_GATE_INVARIANTS_BLOCK:-false}" = "1" ]; } && type _invariant_gate_and_surface &>/dev/null && ! _invariant_gate_and_surface; then
15564
15679
  log_warn "Completion claim rejected: invariant gate found CRITICAL/HIGH invariant/property violation(s)."
15565
- log_warn " Details under .loki/quality/invariant-findings.txt ; opt-in gate -- disable with LOKI_GATE_INVARIANTS=false"
15680
+ log_warn " Details under .loki/quality/invariant-findings.txt ; opt-in blocking -- disable with LOKI_GATE_INVARIANTS_BLOCK=false"
15566
15681
  # Fall through; keep iterating until the invariant violations are fixed.
15567
15682
  elif [ "$_completion_claimed" = 1 ]; then
15568
15683
  echo ""
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "7.55.0"
10
+ __version__ = "7.57.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try: