loki-mode 9.52.0 → 9.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v9.52.0
6
+ # Loki Mode v9.54.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
470
470
 
471
471
  ---
472
472
 
473
- **v9.52.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
473
+ **v9.54.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 9.52.0
1
+ 9.54.0
@@ -19,6 +19,12 @@
19
19
  # - Multi-agent debate: Voting beats unanimous (+13.2%), KS adaptive stopping
20
20
  # - NVIDIA ToolOrchestra: Efficiency metrics for agent tool use
21
21
  #
22
+ # Inline Python (D7): the council runs with the cwd inside the agent's repo, so
23
+ # every "python3 -c" / "python3 -" here runs -E (a PYTHONPATH empty component
24
+ # would load a committed sitecustomize.py) and drops '' and '.' from sys.path
25
+ # before any other import (a committed json.py would print the verdict).
26
+ # Pinned by tests/moat/p2-honest-verdict.sh P2.council-readers-not-shadowed.
27
+ #
22
28
  # Environment Variables:
23
29
  # LOKI_COUNCIL_ENABLED - Enable completion council (default: true)
24
30
  # LOKI_COUNCIL_SIZE - Number of council members (default: 3)
@@ -371,7 +377,7 @@ council_track_iteration() {
371
377
  _COUNCIL_ITERATION="${ITERATION_COUNT:-0}" \
372
378
  _COUNCIL_FILES_CHANGED="$files_changed" \
373
379
  _COUNCIL_DIFF_HASH="$combined_hash" \
374
- python3 -c "
380
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
375
381
  import json, os
376
382
  state_file = os.environ['_COUNCIL_STATE_FILE']
377
383
  try:
@@ -453,7 +459,7 @@ _uncertainty_state_path() {
453
459
  # Read uncertainty.json (or emit a default object if missing/corrupt) to stdout.
454
460
  _uncertainty_read_state() {
455
461
  local file="$1"
456
- _UNC_FILE="$file" python3 -c "
462
+ _UNC_FILE="$file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
457
463
  import json, os
458
464
  f = os.environ['_UNC_FILE']
459
465
  default = {
@@ -487,7 +493,7 @@ _uncertainty_write_state() {
487
493
  dir="$(dirname "$file")"
488
494
  mkdir -p "$dir" 2>/dev/null || true
489
495
  tmp="${file}.tmp.$$"
490
- if _UNC_PAYLOAD="$payload" _UNC_TMP="$tmp" python3 -c "
496
+ if _UNC_PAYLOAD="$payload" _UNC_TMP="$tmp" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
491
497
  import json, os
492
498
  payload = os.environ['_UNC_PAYLOAD']
493
499
  tmp = os.environ['_UNC_TMP']
@@ -539,7 +545,7 @@ uncertainty_should_escalate() {
539
545
  _UNC_SPLIT_ROUNDS="$split_rounds" \
540
546
  _UNC_NOCHANGE_MIN="$nochange_min" \
541
547
  _UNC_RING_SIZE="$ring_size" \
542
- python3 -c "
548
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
543
549
  import json, os
544
550
 
545
551
  prior = json.loads(os.environ['_UNC_PRIOR'])
@@ -826,7 +832,7 @@ council_vote() {
826
832
  local budget_exceeded=false
827
833
  if [ "$total_issue_count" -gt 0 ] && [ "$COUNCIL_ERROR_BUDGET" != "0.0" ] && [ "$COUNCIL_ERROR_BUDGET" != "0" ]; then
828
834
  # Check if non-blocking issue ratio exceeds the error budget
829
- budget_exceeded=$(_NB="$non_blocking_count" _TOTAL="$total_issue_count" _BUDGET="$COUNCIL_ERROR_BUDGET" python3 -c "
835
+ budget_exceeded=$(_NB="$non_blocking_count" _TOTAL="$total_issue_count" _BUDGET="$COUNCIL_ERROR_BUDGET" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
830
836
  import os
831
837
  nb = int(os.environ['_NB'])
832
838
  total = int(os.environ['_TOTAL'])
@@ -918,7 +924,7 @@ print('true' if ratio > budget else 'false')
918
924
  _COUNCIL_REJECT="$reject_count" \
919
925
  _COUNCIL_ITERATION="${ITERATION_COUNT:-0}" \
920
926
  _COUNCIL_THRESHOLD="$effective_threshold" \
921
- python3 -c "
927
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
922
928
  import json, os
923
929
  from datetime import datetime, timezone
924
930
  state_file = os.environ['_COUNCIL_STATE_FILE']
@@ -1036,7 +1042,7 @@ council_write_transcript() {
1036
1042
  _MEMBERS_DIR="$COUNCIL_STATE_DIR/votes/iteration-${iteration}" \
1037
1043
  _THRESHOLD="$effective_threshold" \
1038
1044
  _OUT="$transcript_file" \
1039
- python3 -c "
1045
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1040
1046
  import json, os, pathlib, re
1041
1047
 
1042
1048
  iteration_id = os.environ['_IID']
@@ -1214,7 +1220,7 @@ EVIDENCE_SECTION
1214
1220
  local queue_file=".loki/queue/${queue}.json"
1215
1221
  if [ -f "$queue_file" ]; then
1216
1222
  local count
1217
- count=$(_QUEUE_FILE="$queue_file" python3 -c "import json, os; print(len(json.load(open(os.environ['_QUEUE_FILE']))))" 2>/dev/null || echo "?")
1223
+ count=$(_QUEUE_FILE="$queue_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json, os; print(len(json.load(open(os.environ['_QUEUE_FILE']))))" 2>/dev/null || echo "?")
1218
1224
  echo "- ${queue}: $count tasks" >> "$evidence_file"
1219
1225
  fi
1220
1226
  done
@@ -1287,7 +1293,7 @@ EVIDENCE_SECTION
1287
1293
  elif [ -f ".loki/verification/playwright-results.json" ]; then
1288
1294
  echo "" >> "$evidence_file"
1289
1295
  echo "## Playwright Smoke Test Results" >> "$evidence_file"
1290
- _PW_RESULTS=".loki/verification/playwright-results.json" python3 -c "
1296
+ _PW_RESULTS=".loki/verification/playwright-results.json" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1291
1297
  import json, os
1292
1298
  try:
1293
1299
  d = json.load(open(os.environ['_PW_RESULTS']))
@@ -1375,7 +1381,7 @@ council_checklist_gate() {
1375
1381
  # council_heldout_gate at the ship gate, and surfacing them in this gate's
1376
1382
  # block report would leak their identity back into the build loop.
1377
1383
  local gate_result
1378
- gate_result=$(_RESULTS_FILE="$results_file" _WAIVERS_FILE="$waivers_file" _HELDOUT_FILE="$heldout_file" python3 -c "
1384
+ gate_result=$(_RESULTS_FILE="$results_file" _WAIVERS_FILE="$waivers_file" _HELDOUT_FILE="$heldout_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1379
1385
  import json, sys, os
1380
1386
 
1381
1387
  results_file = os.environ['_RESULTS_FILE']
@@ -1438,13 +1444,13 @@ else:
1438
1444
  local timestamp
1439
1445
  timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
1440
1446
  local failures_json
1441
- failures_json=$(_FAILURES="$failures" python3 -c "
1447
+ failures_json=$(_FAILURES="$failures" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1442
1448
  import json, os
1443
1449
  items = os.environ['_FAILURES'].split('|')
1444
1450
  print(json.dumps(items))
1445
1451
  " 2>/dev/null || echo '[]')
1446
1452
  local critical_count
1447
- critical_count=$(_FAILURES="$failures" python3 -c "
1453
+ critical_count=$(_FAILURES="$failures" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1448
1454
  import os
1449
1455
  print(len(os.environ['_FAILURES'].split('|')))
1450
1456
  " 2>/dev/null || echo '0')
@@ -1514,7 +1520,7 @@ council_heldout_gate() {
1514
1520
  # contain ':' or '|'); they are read separately from the held-out JSON block
1515
1521
  # below in the BLOCK branch.
1516
1522
  local gate_result
1517
- gate_result=$(_RESULTS_FILE="$results_file" _HELDOUT_FILE="$heldout_file" _WAIVERS_FILE="$waivers_file" python3 -c "
1523
+ gate_result=$(_RESULTS_FILE="$results_file" _HELDOUT_FILE="$heldout_file" _WAIVERS_FILE="$waivers_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1518
1524
  import json, sys, os
1519
1525
 
1520
1526
  results_file = os.environ['_RESULTS_FILE']
@@ -1634,7 +1640,7 @@ print('%s %d %d' % (verdict, passed, failed))
1634
1640
  if [ "$verdict" = "BLOCK" ]; then
1635
1641
  # Read failing held-out titles directly from the data (colon/pipe-safe).
1636
1642
  local titles_json titles_display
1637
- titles_json=$(_RESULTS_FILE="$results_file" _HELDOUT_FILE="$heldout_file" _WAIVERS_FILE="$waivers_file" python3 -c "
1643
+ titles_json=$(_RESULTS_FILE="$results_file" _HELDOUT_FILE="$heldout_file" _WAIVERS_FILE="$waivers_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1638
1644
  import json, os
1639
1645
  results = json.load(open(os.environ['_RESULTS_FILE']))
1640
1646
  heldout_ids = set(json.load(open(os.environ['_HELDOUT_FILE'])).get('held_out', []))
@@ -1653,7 +1659,7 @@ for cat in results.get('categories', []):
1653
1659
  titles.append(item.get('title', iid))
1654
1660
  print(json.dumps(titles[:5]))
1655
1661
  " 2>/dev/null || echo '[]')
1656
- titles_display=$(_T="$titles_json" python3 -c "
1662
+ titles_display=$(_T="$titles_json" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1657
1663
  import json, os
1658
1664
  try:
1659
1665
  print(', '.join(json.loads(os.environ['_T'])))
@@ -1927,7 +1933,8 @@ council_evidence_gate() {
1927
1933
  local test_inconclusive_reason=""
1928
1934
  if [ -f "$tr_file" ]; then
1929
1935
  local test_status
1930
- test_status=$(_TR_FILE="$tr_file" python3 <<'PYEOF' 2>/dev/null || echo "INCONCLUSIVE:none:true"
1936
+ test_status=$(_TR_FILE="$tr_file" python3 -E -s - <<'PYEOF' 2>/dev/null || echo "INCONCLUSIVE:none:true"
1937
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
1931
1938
  import json, os, sys
1932
1939
  tr_file = os.environ['_TR_FILE']
1933
1940
  try:
@@ -1954,7 +1961,10 @@ if runner == 'none':
1954
1961
  elif passed is False:
1955
1962
  print('FAIL:%s:false' % runner)
1956
1963
  elif status == 'no_tests_run' or passed is not True:
1957
- print('INCONCLUSIVE:%s:true' % runner)
1964
+ # Both are INCONCLUSIVE; NO_PASS names the second: no boolean pass was
1965
+ # recorded at all (missing, null, or a non-boolean value), which is not a
1966
+ # zero-test run.
1967
+ print('%s:%s:true' % ('INCONCLUSIVE' if status == 'no_tests_run' else 'NO_PASS', runner))
1958
1968
  else:
1959
1969
  print('PASS:%s:true' % runner)
1960
1970
  PYEOF
@@ -1985,6 +1995,13 @@ PYEOF
1985
1995
  test_inconclusive="true"
1986
1996
  test_inconclusive_reason="no_tests_executed"
1987
1997
  fi
1998
+ # A real runner label but no boolean pass recorded: the same
1999
+ # pass-through INCONCLUSIVE, named for what it is. Not gated by the
2000
+ # opt-out either: an unrecorded outcome is never affirmative.
2001
+ if [ "$_verdict" = "NO_PASS" ]; then
2002
+ test_inconclusive="true"
2003
+ test_inconclusive_reason="no_pass_recorded"
2004
+ fi
1988
2005
  else
1989
2006
  # Missing test-results.json: no suite was recorded at all. Like the
1990
2007
  # runner=="none" case this is not affirmative evidence, so classify it
@@ -2099,6 +2116,16 @@ INCONCLUSIVE_EOF
2099
2116
  local _diff_ok _tests_ok
2100
2117
  if [ "$diff_fails" = "true" ]; then _diff_ok="false"; else _diff_ok="true"; fi
2101
2118
  if [ "$test_fails" = "true" ]; then _tests_ok="false"; else _tests_ok="true"; fi
2119
+ # BACKLOG 55: tests.pass is true only for affirmative evidence (a real
2120
+ # runner recorded a boolean pass and nothing downgraded it). $test_pass
2121
+ # itself is "true" for every inconclusive outcome (no runner, no results,
2122
+ # zero tests, no pass recorded, tautological), so it is not written raw.
2123
+ local _tests_pass_json='"inconclusive"'
2124
+ if [ "$test_fails" = "true" ]; then
2125
+ _tests_pass_json="false"
2126
+ elif [ "$test_inconclusive" != "true" ] && [ "$test_runner" != "none" ] && [ "$test_pass" = "true" ]; then
2127
+ _tests_pass_json="true"
2128
+ fi
2102
2129
  # Proof-of-Function axes (nomock/persistence/auth) are declared later in
2103
2130
  # the gate; default to "true"/"" when this helper runs before they are
2104
2131
  # set (it never does in practice, but keep the write robust).
@@ -2122,7 +2149,7 @@ INCONCLUSIVE_EOF
2122
2149
  "tests": {
2123
2150
  "ok": $_tests_ok,
2124
2151
  "runner": "$test_runner",
2125
- "pass": $test_pass,
2152
+ "pass": $_tests_pass_json,
2126
2153
  "inconclusive": $test_inconclusive,
2127
2154
  "inconclusive_reason": "$test_inconclusive_reason"
2128
2155
  },
@@ -2175,7 +2202,8 @@ DETAILS_EOF
2175
2202
  boot_inconclusive_reason="no_app_runner"
2176
2203
  elif command -v python3 >/dev/null 2>&1; then
2177
2204
  local _boot_status
2178
- _boot_status=$(_HEALTH="$_health_file" _STATE="$_state_file" python3 <<'PYEOF' 2>/dev/null || echo "INCONCLUSIVE:parse_error"
2205
+ _boot_status=$(_HEALTH="$_health_file" _STATE="$_state_file" python3 -E -s - <<'PYEOF' 2>/dev/null || echo "INCONCLUSIVE:parse_error"
2206
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
2179
2207
  import json, os
2180
2208
  health_file = os.environ.get('_HEALTH', '')
2181
2209
  state_file = os.environ.get('_STATE', '')
@@ -2338,7 +2366,8 @@ PYEOF
2338
2366
  persist_inconclusive="true"; persist_inconclusive_reason="not_serveable"
2339
2367
  elif command -v python3 >/dev/null 2>&1; then
2340
2368
  local _p_status
2341
- _p_status=$(_PF="$_proof_file" _ITER="${ITERATION_COUNT:-0}" python3 <<'PYEOF' 2>/dev/null || echo "MISSING"
2369
+ _p_status=$(_PF="$_proof_file" _ITER="${ITERATION_COUNT:-0}" python3 -E -s - <<'PYEOF' 2>/dev/null || echo "MISSING"
2370
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
2342
2371
  import json, os
2343
2372
  p = os.environ['_PF']
2344
2373
  if not os.path.isfile(p):
@@ -2401,7 +2430,8 @@ PYEOF
2401
2430
  auth_inconclusive="true"; auth_inconclusive_reason="not_serveable"
2402
2431
  elif command -v python3 >/dev/null 2>&1; then
2403
2432
  local _a_status
2404
- _a_status=$(_PF="$_proof_file" _STRICT="${LOKI_PROOF_AUTH_STRICT:-1}" _ITER="${ITERATION_COUNT:-0}" python3 <<'PYEOF' 2>/dev/null || echo "MISSING"
2433
+ _a_status=$(_PF="$_proof_file" _STRICT="${LOKI_PROOF_AUTH_STRICT:-1}" _ITER="${ITERATION_COUNT:-0}" python3 -E -s - <<'PYEOF' 2>/dev/null || echo "MISSING"
2434
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
2405
2435
  import json, os
2406
2436
  p = os.environ['_PF']
2407
2437
  strict = os.environ.get('_STRICT', '1') != '0'
@@ -2479,7 +2509,8 @@ PYEOF
2479
2509
  authz_inconclusive="true"; authz_inconclusive_reason="not_serveable"
2480
2510
  elif command -v python3 >/dev/null 2>&1; then
2481
2511
  local _authz_status
2482
- _authz_status=$(_PF="$_proof_file" _ITER="${ITERATION_COUNT:-0}" python3 <<'PYEOF' 2>/dev/null || echo "MISSING"
2512
+ _authz_status=$(_PF="$_proof_file" _ITER="${ITERATION_COUNT:-0}" python3 -E -s - <<'PYEOF' 2>/dev/null || echo "MISSING"
2513
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
2483
2514
  import json, os
2484
2515
  p = os.environ['_PF']
2485
2516
  if not os.path.isfile(p):
@@ -2736,7 +2767,7 @@ PYEOF
2736
2767
  local timestamp
2737
2768
  timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
2738
2769
  local failures_json diff_ok tests_ok base_for_json
2739
- failures_json=$(_FAILURES="$failures" python3 -c "
2770
+ failures_json=$(_FAILURES="$failures" python3 -E -s -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
2740
2771
  import json, os
2741
2772
  items = [s for s in os.environ['_FAILURES'].split('|') if s]
2742
2773
  print(json.dumps(items[:5]))
@@ -2753,11 +2784,11 @@ print(json.dumps(items[:5]))
2753
2784
  if [ "$authz_fails" = "true" ]; then authz_ok="false"; else authz_ok="true"; fi
2754
2785
  # Record WHY boot was inconclusive (no_app_runner / not_serveable / etc.) so a
2755
2786
  # consumer of the block report can tell a genuine boot pass from a pass-through.
2756
- boot_reason_json=$(_R="${boot_inconclusive_reason:-}" python3 -c "import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2757
- nomock_reason_json=$(_R="${nomock_inconclusive_reason:-}" python3 -c "import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2758
- persist_reason_json=$(_R="${persist_inconclusive_reason:-}" python3 -c "import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2759
- auth_reason_json=$(_R="${auth_inconclusive_reason:-}" python3 -c "import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2760
- authz_reason_json=$(_R="${authz_inconclusive_reason:-}" python3 -c "import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2787
+ boot_reason_json=$(_R="${boot_inconclusive_reason:-}" python3 -E -s -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2788
+ nomock_reason_json=$(_R="${nomock_inconclusive_reason:-}" python3 -E -s -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2789
+ persist_reason_json=$(_R="${persist_inconclusive_reason:-}" python3 -E -s -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2790
+ auth_reason_json=$(_R="${auth_inconclusive_reason:-}" python3 -E -s -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2791
+ authz_reason_json=$(_R="${authz_inconclusive_reason:-}" python3 -E -s -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json,os; print(json.dumps(os.environ['_R']))" 2>/dev/null || echo '""')
2761
2792
  base_for_json="${base_sha:-}"
2762
2793
  cat > "$ev_tmp" << EVIDENCE_EOF
2763
2794
  {
@@ -3395,7 +3426,7 @@ council_heuristic_review() {
3395
3426
  local _tr_file=".loki/quality/test-results.json"
3396
3427
  local _tests_ok=0
3397
3428
  if [ -f "$_tr_file" ] && command -v python3 >/dev/null 2>&1; then
3398
- _tests_ok=$(_TR="$_tr_file" python3 -c "
3429
+ _tests_ok=$(_TR="$_tr_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
3399
3430
  import json, os
3400
3431
  try:
3401
3432
  with open(os.environ['_TR']) as f:
@@ -3568,7 +3599,7 @@ council_evaluate_member() {
3568
3599
  local test_runner_seen="none"
3569
3600
  if [ -f "$tr_file" ]; then
3570
3601
  local _tr_status
3571
- _tr_status=$(_TR_FILE="$tr_file" python3 -c "
3602
+ _tr_status=$(_TR_FILE="$tr_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
3572
3603
  import json, os, sys
3573
3604
  try:
3574
3605
  with open(os.environ['_TR_FILE']) as f:
@@ -3625,7 +3656,7 @@ else:
3625
3656
  local _q _qcount
3626
3657
  for _q in pending in-progress blocked; do
3627
3658
  [ -f "$loki_dir/queue/${_q}.json" ] || continue
3628
- _qcount=$(_QUEUE_FILE="$loki_dir/queue/${_q}.json" python3 -c "import json, os
3659
+ _qcount=$(_QUEUE_FILE="$loki_dir/queue/${_q}.json" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json, os
3629
3660
  d = json.load(open(os.environ['_QUEUE_FILE']))
3630
3661
  print(len(d.get('tasks', d) if isinstance(d, dict) else d))" 2>/dev/null || echo "0")
3631
3662
  # Guard against a non-numeric read (malformed file, python absent).
@@ -3762,7 +3793,7 @@ council_aggregate_votes() {
3762
3793
  # Serialize the votes array with json.dumps so backslashes/control chars are
3763
3794
  # escaped correctly (BUG fix: sed-only escaping produced invalid JSON).
3764
3795
  local votes_json
3765
- votes_json=$(_MEMBERS="$_members" _ROLES="$_roles" _VOTEVALS="$_vote_values" _REASONS="$_reasons" python3 -c "
3796
+ votes_json=$(_MEMBERS="$_members" _ROLES="$_roles" _VOTEVALS="$_vote_values" _REASONS="$_reasons" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
3766
3797
  import json, os
3767
3798
  def lines(name):
3768
3799
  v = os.environ.get(name, '')
@@ -3805,7 +3836,7 @@ print(json.dumps(out))
3805
3836
  _VERDICT="$verdict" \
3806
3837
  _VOTES="$votes_json" \
3807
3838
  _ROUND_FILE="$round_file" \
3808
- python3 -c "
3839
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
3809
3840
  import json, os
3810
3841
  from datetime import datetime, timezone
3811
3842
  round_data = {
@@ -3866,7 +3897,7 @@ council_devils_advocate_review() {
3866
3897
  local tr_file="$loki_dir/quality/test-results.json"
3867
3898
  if [ -f "$tr_file" ]; then
3868
3899
  local _tr_status
3869
- _tr_status=$(_TR_FILE="$tr_file" python3 -c "
3900
+ _tr_status=$(_TR_FILE="$tr_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
3870
3901
  import json, os, sys
3871
3902
  try:
3872
3903
  with open(os.environ['_TR_FILE']) as f:
@@ -3904,7 +3935,7 @@ else:
3904
3935
  # Skeptical check 2: Are there still failing tasks in the queue?
3905
3936
  if [ -f "$loki_dir/queue/failed.json" ]; then
3906
3937
  local failed_count
3907
- failed_count=$(_QUEUE_FILE="$loki_dir/queue/failed.json" python3 -c "import json, os; print(len(json.load(open(os.environ['_QUEUE_FILE']))))" 2>/dev/null || echo "0")
3938
+ failed_count=$(_QUEUE_FILE="$loki_dir/queue/failed.json" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json, os; print(len(json.load(open(os.environ['_QUEUE_FILE']))))" 2>/dev/null || echo "0")
3908
3939
  if [ "$failed_count" -gt 0 ]; then
3909
3940
  ((issues_found++))
3910
3941
  issue_details="${issue_details}$failed_count tasks in failed queue; "
@@ -3950,7 +3981,7 @@ else:
3950
3981
  _ISSUES="$issues_found" \
3951
3982
  _DETAILS="${issue_details:-none}" \
3952
3983
  _DA_FILE="$da_file" \
3953
- python3 -c "
3984
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
3954
3985
  import json, os
3955
3986
  from datetime import datetime, timezone
3956
3987
  da_result = {
@@ -4046,7 +4077,7 @@ council_evaluate() {
4046
4077
  if loki_council_dispatch_agents "$ITERATION_COUNT" "${COUNCIL_PRD_PATH:-}"; then
4047
4078
  local _va_round_file="$COUNCIL_STATE_DIR/votes/round-${ITERATION_COUNT}.json"
4048
4079
  if [ -f "$_va_round_file" ]; then
4049
- aggregate_result=$(_RF="$_va_round_file" python3 -c "import json, os; print(json.load(open(os.environ['_RF'])).get('verdict', 'CONTINUE'))" 2>/dev/null || echo "")
4080
+ aggregate_result=$(_RF="$_va_round_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json, os; print(json.load(open(os.environ['_RF'])).get('verdict', 'CONTINUE'))" 2>/dev/null || echo "")
4050
4081
  fi
4051
4082
  fi
4052
4083
  fi
@@ -4068,7 +4099,7 @@ council_evaluate() {
4068
4099
  local complete_count=0
4069
4100
  local members_present=0
4070
4101
  if [ -f "$round_file" ]; then
4071
- complete_count=$(_RF="$round_file" python3 -c "import json, os; print(json.load(open(os.environ['_RF'])).get('complete_votes', 0))" 2>/dev/null || echo "0")
4102
+ complete_count=$(_RF="$round_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json, os; print(json.load(open(os.environ['_RF'])).get('complete_votes', 0))" 2>/dev/null || echo "0")
4072
4103
  # WAVE13 CRITICAL quorum gate: how many voters actually responded
4073
4104
  # (total_members records the ACTUAL returned count -- see
4074
4105
  # voter-agents.sh). A degraded/partial dispatch response must never
@@ -4076,7 +4107,7 @@ council_evaluate() {
4076
4107
  # somehow read COMPLETE. This is defense-in-depth: the parser
4077
4108
  # already forces CONTINUE on undercount, but the completion-detection
4078
4109
  # trust core must independently assert full quorum before stopping.
4079
- members_present=$(_RF="$round_file" python3 -c "import json, os; print(json.load(open(os.environ['_RF'])).get('total_members', 0))" 2>/dev/null || echo "0")
4110
+ members_present=$(_RF="$round_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json, os; print(json.load(open(os.environ['_RF'])).get('total_members', 0))" 2>/dev/null || echo "0")
4080
4111
  fi
4081
4112
  # Normalize to integers (guard against empty/non-numeric on read failure)
4082
4113
  case "$complete_count" in (''|*[!0-9]*) complete_count=0 ;; esac
@@ -4172,7 +4203,7 @@ council_managed_should_stop() {
4172
4203
  diff_summary=$(cd "$project_dir" 2>/dev/null && git diff --stat 2>/dev/null | tail -20 | tr '\n' ' ' || echo "")
4173
4204
  local test_summary=""
4174
4205
  if [ -f "$loki_dir/quality/test-results.json" ]; then
4175
- test_summary=$(_TRF="$loki_dir/quality/test-results.json" python3 -c "
4206
+ test_summary=$(_TRF="$loki_dir/quality/test-results.json" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
4176
4207
  import json, os
4177
4208
  try:
4178
4209
  d = json.load(open(os.environ['_TRF']))
@@ -4183,7 +4214,7 @@ except Exception:
4183
4214
  fi
4184
4215
  local pending_tasks="[]"
4185
4216
  if [ -f "$loki_dir/queue/pending.json" ]; then
4186
- pending_tasks=$(_QF="$loki_dir/queue/pending.json" python3 -c "
4217
+ pending_tasks=$(_QF="$loki_dir/queue/pending.json" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
4187
4218
  import json, os
4188
4219
  try:
4189
4220
  d = json.load(open(os.environ['_QF']))
@@ -4206,12 +4237,17 @@ except Exception:
4206
4237
  _CC_VERDICTS_DIR="$verdicts_dir" \
4207
4238
  _CC_LOKI_DIR="$loki_dir" \
4208
4239
  LOKI_TARGET_DIR="${TARGET_DIR:-$(pwd)}" \
4209
- python3 - <<'PYEOF' 2>/dev/null || exit_code=$?
4240
+ PROJECT_DIR="${PROJECT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd)}" \
4241
+ python3 -E - <<'PYEOF' 2>/dev/null || exit_code=$?
4242
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
4210
4243
  import json, os, sys, pathlib
4211
4244
 
4212
- # Path setup: prefer project_dir so providers.managed resolves from main tree.
4213
- project_dir = os.environ.get("PROJECT_DIR") or os.getcwd()
4214
- sys.path.insert(0, project_dir)
4245
+ # Path setup: import providers.managed only from an explicit PROJECT_DIR. Never
4246
+ # fall back to the cwd (D7): it is the agent's repo, which could ship its own
4247
+ # providers/managed.py. Unset -> ImportError -> the Bash voting path.
4248
+ project_dir = os.environ.get("PROJECT_DIR", "")
4249
+ if project_dir:
4250
+ sys.path.insert(0, project_dir)
4215
4251
 
4216
4252
  try:
4217
4253
  from providers.managed import (
@@ -4383,7 +4419,7 @@ _council_convergence_evidence_green() {
4383
4419
  # file or runner=="none" (no suite) is NOT affirmative evidence -> not green.
4384
4420
  [ -f "$tr_file" ] || return 1
4385
4421
  local tr_state
4386
- tr_state=$(_TR_FILE="$tr_file" python3 -c "
4422
+ tr_state=$(_TR_FILE="$tr_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
4387
4423
  import json, os, sys
4388
4424
  try:
4389
4425
  with open(os.environ['_TR_FILE']) as f:
@@ -4406,7 +4442,7 @@ print('yes' if (runner != 'none' and passed is True
4406
4442
  local results_file="${TARGET_DIR:-.}/.loki/checklist/verification-results.json"
4407
4443
  if [ -f "$results_file" ]; then
4408
4444
  local cl_state
4409
- cl_state=$(_RESULTS_FILE="$results_file" python3 -c "
4445
+ cl_state=$(_RESULTS_FILE="$results_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
4410
4446
  import json, os, sys
4411
4447
  try:
4412
4448
  with open(os.environ['_RESULTS_FILE']) as f:
@@ -4655,7 +4691,7 @@ council_write_report() {
4655
4691
  REPORT_HEADER
4656
4692
 
4657
4693
  # Append vote history from state
4658
- _COUNCIL_STATE_FILE="$COUNCIL_STATE_DIR/state.json" python3 -c "
4694
+ _COUNCIL_STATE_FILE="$COUNCIL_STATE_DIR/state.json" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
4659
4695
  import json, os
4660
4696
  try:
4661
4697
  with open(os.environ['_COUNCIL_STATE_FILE']) as f:
@@ -19,6 +19,12 @@
19
19
  # - swarm/sycophancy.py (sycophancy detection)
20
20
  # - swarm/calibration.py (reviewer calibration)
21
21
  #
22
+ # Inline Python (D7): the council runs with the cwd inside the agent's repo, so
23
+ # every python3 here runs -E and drops '' and '.' from sys.path before any other
24
+ # import (the swarm dir is inserted after that); a committed json.py or
25
+ # sitecustomize.py cannot read the votes. Pinned by
26
+ # tests/test-council-no-fabricated-verdict.sh (D7 section).
27
+ #
22
28
  #===============================================================================
23
29
 
24
30
  COUNCIL_V2_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -97,7 +103,7 @@ council_v2_vote() {
97
103
  votes_json="$votes_json$vote_content"
98
104
 
99
105
  local verdict
100
- verdict=$(echo "$vote_content" | python3 -c "import sys,json; print(json.load(sys.stdin).get('verdict','').upper())" 2>/dev/null || echo "UNKNOWN")
106
+ verdict=$(echo "$vote_content" | python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json; print(json.load(sys.stdin).get('verdict','').upper())" 2>/dev/null || echo "UNKNOWN")
101
107
  # TRUST: a reviewer that could not be REACHED did not vote REJECT.
102
108
  #
103
109
  # Every provider arm below used to substitute a literal
@@ -135,7 +141,7 @@ council_v2_vote() {
135
141
 
136
142
  # Step 4: Sycophancy detection
137
143
  local sycophancy_score
138
- sycophancy_score=$(python3 -c "
144
+ sycophancy_score=$(python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
139
145
  import sys
140
146
  sys.path.insert(0, '${COUNCIL_V2_DIR}/../swarm')
141
147
  from sycophancy import detect_sycophancy
@@ -150,7 +156,7 @@ print('{:.3f}'.format(detect_sycophancy(votes)))
150
156
  if [ "$approve_count" -eq "$council_size" ]; then
151
157
  local threshold="${LOKI_COUNCIL_SYCOPHANCY_THRESHOLD:-0.6}"
152
158
  local should_challenge
153
- should_challenge=$(python3 -c "print('yes' if float('$sycophancy_score') >= float('$threshold') else 'no')" 2>/dev/null || echo "no")
159
+ should_challenge=$(python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; print('yes' if float('$sycophancy_score') >= float('$threshold') else 'no')" 2>/dev/null || echo "no")
154
160
 
155
161
  if [ "$should_challenge" = "yes" ]; then
156
162
  log_warn "Sycophancy score $sycophancy_score >= $threshold -- adding devil's advocate"
@@ -167,7 +173,7 @@ print('{:.3f}'.format(detect_sycophancy(votes)))
167
173
  # Same trust rule as the main tally: an unparseable devil's
168
174
  # advocate did not vote REJECT. Defaulting to REJECT here would
169
175
  # silently overturn a unanimous APPROVE on a transient failure.
170
- da_verdict=$(cat "$da_vote" | python3 -c "import sys,json; print(json.load(sys.stdin).get('verdict','').upper())" 2>/dev/null || echo "INCONCLUSIVE")
176
+ da_verdict=$(cat "$da_vote" | python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]; import json; print(json.load(sys.stdin).get('verdict','').upper())" 2>/dev/null || echo "INCONCLUSIVE")
171
177
  if [ "$da_verdict" = "INCONCLUSIVE" ]; then
172
178
  log_warn "Devil's advocate produced no verdict -- unanimous approval left UNCHANGED (not overturned)"
173
179
  elif [ "$da_verdict" = "REJECT" ]; then
@@ -201,7 +207,7 @@ print('{:.3f}'.format(detect_sycophancy(votes)))
201
207
  final_decision="reject"
202
208
  fi
203
209
 
204
- python3 -c "
210
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
205
211
  import sys
206
212
  sys.path.insert(0, '${COUNCIL_V2_DIR}/../swarm')
207
213
  from calibration import CalibrationTracker
@@ -388,7 +394,7 @@ Respond ONLY with a valid JSON object. No markdown fencing."
388
394
  --json-schema "$_c2_schema_content" --output-format json 2>/dev/null)" || _c2_json=""
389
395
  if [ -n "$_c2_json" ]; then
390
396
  # Pull the schema-validated object out of the envelope.
391
- result="$(printf '%s' "$_c2_json" | python3 -c 'import sys,json
397
+ result="$(printf '%s' "$_c2_json" | python3 -E -c 'import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]; import json
392
398
  try:
393
399
  e=json.load(sys.stdin)
394
400
  p=e.get("structured_output")
@@ -490,7 +496,7 @@ except Exception:
490
496
  # or neither, stays INCONCLUSIVE -- never guessed.
491
497
  if [ -z "$extracted" ] && [ -n "${result:-}" ]; then
492
498
  local _recovered
493
- _recovered="$(printf '%s' "$result" | _LOKI_RAW="$result" python3 -c '
499
+ _recovered="$(printf '%s' "$result" | _LOKI_RAW="$result" python3 -E -c 'import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
494
500
  import os, re, sys, json
495
501
  raw = os.environ.get("_LOKI_RAW", "")
496
502
  # Standalone words only: "APPROVE" not "approved-by", and not inside a URL.