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.
@@ -36,6 +36,11 @@
36
36
  # the single injection seam, mirroring autonomy/lib/prd-enrich.sh.
37
37
  #
38
38
  # No emojis. No em dashes. bash 3.2 safe. Honors `set -uo pipefail`.
39
+ #
40
+ # Inline Python (D7): the gate runs with the cwd inside the agent's repo, so
41
+ # every python3 here runs -E and drops '' and '.' from sys.path before any other
42
+ # import; a committed json.py or sitecustomize.py cannot turn the verdict done.
43
+ # Pinned by tests/test-reuse-done-recognition.sh case (d7).
39
44
 
40
45
  # Bound the single model call so a huge PRD or test log cannot run away.
41
46
  : "${LOKI_DONE_RECOG_TIMEOUT:=180}" # seconds for the single model call
@@ -122,7 +127,7 @@ _loki_done_recog_invoke() {
122
127
  --json-schema "$_dr_schema_content" --output-format json 2>/dev/null) || _dr_json=""
123
128
  fi
124
129
  if [ -n "$_dr_json" ]; then
125
- _dr_obj=$(printf '%s' "$_dr_json" | python3 -c 'import sys,json
130
+ _dr_obj=$(printf '%s' "$_dr_json" | python3 -E -c 'import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]; import json
126
131
  try:
127
132
  e=json.load(sys.stdin)
128
133
  p=e.get("structured_output")
@@ -194,7 +199,7 @@ _loki_done_recog_prd_sha() {
194
199
  sha256sum "$prd_file" 2>/dev/null | awk '{print $1}'
195
200
  else
196
201
  # Last-resort: a python hash, still deterministic over the same bytes.
197
- LOKI_DR_PRD="$prd_file" python3 -c "
202
+ LOKI_DR_PRD="$prd_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
198
203
  import hashlib, os
199
204
  p = os.environ.get('LOKI_DR_PRD','')
200
205
  try:
@@ -275,7 +280,8 @@ reuse_done_recognition_gate() {
275
280
  LOKI_DR_CHECKLIST="$loki_dir/checklist/checklist.json" \
276
281
  LOKI_DR_MAX_PRD="${LOKI_DONE_RECOG_MAX_PRD_CHARS}" \
277
282
  LOKI_DR_MAX_TEST="${LOKI_DONE_RECOG_MAX_TEST_CHARS}" \
278
- python3 << 'DR_PROMPT_EOF'
283
+ python3 -E << 'DR_PROMPT_EOF'
284
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
279
285
  import json, os, sys
280
286
 
281
287
  def read_capped(path, cap):
@@ -376,7 +382,8 @@ DR_PROMPT_EOF
376
382
  LOKI_DR_TESTS="$_test_results" \
377
383
  LOKI_DR_ACTION="$action" \
378
384
  LOKI_DR_PRD="$prd_path" \
379
- python3 << 'DR_PARSE_EOF'
385
+ python3 -E << 'DR_PARSE_EOF'
386
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
380
387
  import json, os, re, sys
381
388
 
382
389
  resp = os.environ.get("LOKI_DR_RESP", "")
@@ -674,7 +681,7 @@ DR_PARSE_EOF
674
681
  fi
675
682
 
676
683
  local verdict
677
- verdict=$(printf '%s' "$parsed" | python3 -c "import json,sys;print(json.load(sys.stdin).get('verdict',''))" 2>/dev/null)
684
+ verdict=$(printf '%s' "$parsed" | 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',''))" 2>/dev/null)
678
685
 
679
686
  case "$verdict" in
680
687
  done)
@@ -687,7 +694,7 @@ DR_PARSE_EOF
687
694
  ;;
688
695
  *)
689
696
  local _reason
690
- _reason=$(printf '%s' "$parsed" | python3 -c "import json,sys;print(json.load(sys.stdin).get('reason','') or 'unverifiable')" 2>/dev/null)
697
+ _reason=$(printf '%s' "$parsed" | 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('reason','') or 'unverifiable')" 2>/dev/null)
691
698
  log_info "Done-recognition: could not confirm the existing code already satisfies the reused spec (${_reason}). Proceeding to build to be safe."
692
699
  return 1
693
700
  ;;
@@ -723,10 +730,10 @@ _loki_done_recog_finish() {
723
730
  mkdir -p "$loki_dir/state" 2>/dev/null || true
724
731
 
725
732
  local summary met total axis
726
- summary=$(printf '%s' "$parsed" | python3 -c "import json,sys;print(json.load(sys.stdin).get('summary','') or 'Project already satisfies its spec.')" 2>/dev/null)
727
- met=$(printf '%s' "$parsed" | python3 -c "import json,sys;print(json.load(sys.stdin).get('met_count',0))" 2>/dev/null)
728
- total=$(printf '%s' "$parsed" | python3 -c "import json,sys;print(json.load(sys.stdin).get('total_count',0))" 2>/dev/null)
729
- axis=$(printf '%s' "$parsed" | python3 -c "import json,sys;print(json.load(sys.stdin).get('tests_axis','unknown'))" 2>/dev/null)
733
+ summary=$(printf '%s' "$parsed" | 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('summary','') or 'Project already satisfies its spec.')" 2>/dev/null)
734
+ met=$(printf '%s' "$parsed" | 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('met_count',0))" 2>/dev/null)
735
+ total=$(printf '%s' "$parsed" | 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('total_count',0))" 2>/dev/null)
736
+ axis=$(printf '%s' "$parsed" | 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('tests_axis','unknown'))" 2>/dev/null)
730
737
  [ -n "$met" ] || met=0
731
738
  [ -n "$total" ] || total=0
732
739
  [ -n "$axis" ] || axis="unknown"
@@ -766,7 +773,7 @@ _loki_done_recog_finish() {
766
773
  echo ""
767
774
  echo "## Per-requirement evidence"
768
775
  echo ""
769
- printf '%s' "$parsed" | python3 -c "
776
+ printf '%s' "$parsed" | python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
770
777
  import json, sys
771
778
  try:
772
779
  d = json.load(sys.stdin)
@@ -785,7 +792,7 @@ for t in d.get('satisfied', []):
785
792
  LOKI_DR_MET="$met" \
786
793
  LOKI_DR_TOTAL="$total" \
787
794
  LOKI_DR_TS="$ts" \
788
- python3 -c "
795
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
789
796
  import json, os, tempfile
790
797
  out = os.environ['LOKI_DR_OUT']
791
798
  def i(v):
@@ -856,7 +863,7 @@ _loki_done_recog_write_manifest() {
856
863
  LOKI_DR_PARSED="$parsed" \
857
864
  LOKI_DR_SHA="$prd_sha" \
858
865
  LOKI_DR_TS="$ts" \
859
- python3 -c "
866
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
860
867
  import json, os, sys, tempfile
861
868
  out = os.environ['LOKI_DR_OUT']
862
869
  try:
@@ -897,7 +904,8 @@ except Exception:
897
904
  if [ -f "$loki_dir/queue/pending.json" ]; then
898
905
  # Drop prior PRD-sourced tasks so the incremental pass is the source of
899
906
  # truth; non-PRD tasks (if any) are preserved.
900
- LOKI_DR_PENDING="$loki_dir/queue/pending.json" python3 - <<'RESET_EOF' 2>/dev/null || true
907
+ LOKI_DR_PENDING="$loki_dir/queue/pending.json" python3 -E - <<'RESET_EOF' 2>/dev/null || true
908
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
901
909
  import json, os, tempfile
902
910
  p = os.environ.get("LOKI_DR_PENDING", ".loki/queue/pending.json")
903
911
  try:
@@ -921,8 +929,8 @@ RESET_EOF
921
929
  fi
922
930
 
923
931
  local met total
924
- met=$(printf '%s' "$parsed" | python3 -c "import json,sys;print(json.load(sys.stdin).get('met_count',0))" 2>/dev/null)
925
- total=$(printf '%s' "$parsed" | python3 -c "import json,sys;print(json.load(sys.stdin).get('total_count',0))" 2>/dev/null)
932
+ met=$(printf '%s' "$parsed" | 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('met_count',0))" 2>/dev/null)
933
+ total=$(printf '%s' "$parsed" | 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('total_count',0))" 2>/dev/null)
926
934
  local unmet=$(( ${total:-0} - ${met:-0} ))
927
935
  log_info "Done-recognition: ${met:-0} of ${total:-0} requirements already satisfied; building only the ${unmet} unmet. Pass --fresh-prd to rebuild from scratch."
928
936
  }
@@ -26,6 +26,11 @@
26
26
  #
27
27
  # This function is only ever called when the operator opted in (the call site
28
28
  # guards on LOKI_PROVEN_PR_CHECK=1). It is also safe if called directly.
29
+ #
30
+ # Inline Python (D7): the call site's cwd is the agent's repo, so the proof
31
+ # readers run python3 -E and drop '' and '.' from sys.path first; a committed
32
+ # json.py or sitecustomize.py cannot change the headline. Pinned by
33
+ # tests/test-proven-pr-check.sh (D7 section).
29
34
 
30
35
  # Double-source guard.
31
36
  [ -n "${_PROOF_CHECK_SH:-}" ] && return 0
@@ -53,7 +58,8 @@ _proof_check_headline() {
53
58
  command -v python3 >/dev/null 2>&1 || { printf '%s' ""; return 0; }
54
59
 
55
60
  local headline=""
56
- headline="$(python3 - "$proof_path" <<'PY' 2>/dev/null || true
61
+ headline="$(python3 -E - "$proof_path" <<'PY' 2>/dev/null || true
62
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
57
63
  import json, sys
58
64
  try:
59
65
  with open(sys.argv[1], "r", encoding="utf-8") as fh:
@@ -84,7 +90,8 @@ _proof_check_proof_head_sha() {
84
90
  command -v python3 >/dev/null 2>&1 || { printf '%s' ""; return 0; }
85
91
 
86
92
  local sha=""
87
- sha="$(python3 - "$proof_path" <<'PY' 2>/dev/null || true
93
+ sha="$(python3 -E - "$proof_path" <<'PY' 2>/dev/null || true
94
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
88
95
  import json, sys
89
96
  try:
90
97
  with open(sys.argv[1], "r", encoding="utf-8") as fh:
@@ -118,7 +125,8 @@ _proof_check_run_id() {
118
125
  command -v python3 >/dev/null 2>&1 || { printf '%s' ""; return 0; }
119
126
 
120
127
  local rid=""
121
- rid="$(python3 - "$proof_path" <<'PY' 2>/dev/null || true
128
+ rid="$(python3 -E - "$proof_path" <<'PY' 2>/dev/null || true
129
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
122
130
  import json, sys
123
131
  try:
124
132
  with open(sys.argv[1], "r", encoding="utf-8") as fh:
@@ -26,6 +26,11 @@
26
26
  # on success, 1 on any fallback
27
27
  # condition (caller falls through
28
28
  # to existing heuristic dispatch).
29
+ #
30
+ # Inline Python (D7): the dispatch runs with the cwd inside the agent's repo, so
31
+ # every python3 here runs -E and drops '' and '.' from sys.path before any other
32
+ # import; a committed json.py or sitecustomize.py cannot read the votes.
33
+ # Pinned by tests/test-voter-agents-json.sh (Case D).
29
34
 
30
35
  # Guard against double-source.
31
36
  if [ "${__LOKI_VOTER_AGENTS_SH_LOADED:-0}" = "1" ]; then
@@ -59,7 +64,7 @@ loki_voter_agents_json() {
59
64
  _VA_PRD="$prd" \
60
65
  _VA_TIER="$tier" \
61
66
  _VA_COMPLEXITY="${LOKI_COMPLEXITY:-standard}" \
62
- python3 -c '
67
+ python3 -E -c 'import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
63
68
  import json, os
64
69
  iter_n = os.environ.get("_VA_ITER", "0")
65
70
  prd = os.environ.get("_VA_PRD", "")
@@ -128,7 +133,7 @@ print(json.dumps(agents, separators=(",", ":")))
128
133
  # Arg $1: terse base findings summary used to brief the DA prompt.
129
134
  loki_devils_advocate_json() {
130
135
  local summary="${1:-}"
131
- _VA_SUMMARY="$summary" python3 -c '
136
+ _VA_SUMMARY="$summary" python3 -E -c 'import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
132
137
  import json, os
133
138
  summary = os.environ.get("_VA_SUMMARY", "")[:1000]
134
139
  agents = {
@@ -349,7 +354,7 @@ loki_council_dispatch_agents() {
349
354
  _VA_VDIR="$verdicts_dir" \
350
355
  _VA_RFILE="$votes_dir/round-${iteration}.json" \
351
356
  _VA_EXPECTED="${COUNCIL_SIZE:-3}" \
352
- python3 -c '
357
+ python3 -E -c 'import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
353
358
  import json, os, sys
354
359
  from datetime import datetime, timezone
355
360
 
@@ -3,8 +3,11 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
+ import hashlib
6
7
  import os
8
+ import stat as _stat
7
9
  import subprocess
10
+ import sys
8
11
 
9
12
 
10
13
  _EMPTY = {"count": 0, "insertions": 0, "deletions": 0, "files": []}
@@ -29,6 +32,95 @@ def _excluded(path):
29
32
  return path == ".loki" or path.startswith(".loki/")
30
33
 
31
34
 
35
+ # Written by run.sh setup_agent_branch (_loki_snapshot_preexisting): the paths
36
+ # git did not track when the session started, untracked and gitignored,
37
+ # NUL-delimited and relative to the repo top. An entry ending in "/" is an
38
+ # ignored directory and covers its subtree. The sibling holds "<sha256> <path>"
39
+ # records, one per file entry, written by write_snapshot_hashes below.
40
+ _SNAPSHOT = "preexisting-untracked.z"
41
+ _SNAPSHOT_HASHES = "preexisting-untracked.sha.z"
42
+
43
+
44
+ def _content_hash(path):
45
+ """sha256 of a regular file's bytes or a symlink's target, else None.
46
+
47
+ The snapshot writer and the receipt reader both call this, so the two sides
48
+ always agree (git hash-object varies with filters and object format).
49
+ """
50
+ try:
51
+ st = os.lstat(path)
52
+ digest = hashlib.sha256()
53
+ if _stat.S_ISLNK(st.st_mode):
54
+ digest.update(b"link\0" + os.fsencode(os.readlink(path)))
55
+ elif _stat.S_ISREG(st.st_mode):
56
+ with open(path, "rb") as fh:
57
+ for chunk in iter(lambda: fh.read(1 << 20), b""):
58
+ digest.update(chunk)
59
+ else:
60
+ return None
61
+ return digest.hexdigest()
62
+ except OSError:
63
+ return None
64
+
65
+
66
+ def write_snapshot_hashes(top, snapshot):
67
+ """Record a content hash for every file entry of ``snapshot`` that exists
68
+ now (a directory entry or a missing path gets none), atomically, into the
69
+ sibling hashes file."""
70
+ with open(snapshot, "rb") as fh:
71
+ raw = fh.read()
72
+ top_b = os.fsencode(top)
73
+ records = []
74
+ for path in raw.split(b"\0"):
75
+ if not path or path.endswith(b"/"):
76
+ continue
77
+ digest = _content_hash(os.path.join(top_b, path))
78
+ if digest:
79
+ records.append(digest.encode("ascii") + b" " + path + b"\0")
80
+ dest = os.path.join(os.path.dirname(snapshot), _SNAPSHOT_HASHES)
81
+ with open(dest + ".tmp", "wb") as fh:
82
+ fh.write(b"".join(records))
83
+ os.replace(dest + ".tmp", dest)
84
+
85
+
86
+ def _preexisting_untracked(repo_dir):
87
+ """The session-start snapshot: (prefix of repo_dir inside the repo, set of
88
+ repo-top-relative paths, {path: content hash}). Those paths are not this
89
+ run's work, so the receipt lists one only when its content changed;
90
+ tree_sha256 still binds their bytes. Empty when absent."""
91
+ state = os.path.join(repo_dir, ".loki", "state")
92
+ try:
93
+ with open(os.path.join(state, _SNAPSHOT), "rb") as fh:
94
+ raw = fh.read()
95
+ except OSError:
96
+ return "", frozenset(), {}
97
+ paths = frozenset(p.decode("utf-8", "surrogateescape") for p in raw.split(b"\0") if p)
98
+ hashes = {}
99
+ try:
100
+ with open(os.path.join(state, _SNAPSHOT_HASHES), "rb") as fh:
101
+ raw = fh.read()
102
+ except OSError:
103
+ raw = b""
104
+ for record in raw.split(b"\0"):
105
+ digest, sep, path = record.partition(b" ")
106
+ if sep:
107
+ hashes[path.decode("utf-8", "surrogateescape")] = digest.decode("ascii", "replace")
108
+ return (_git(repo_dir, ["rev-parse", "--show-prefix"]) or "").strip(), paths, hashes
109
+
110
+
111
+ def _covered(key, paths):
112
+ """True when ``key`` or one of its parent directories ("a/", "a/b/") is in
113
+ ``paths``: an ignored directory entry covers everything below it."""
114
+ if key in paths:
115
+ return True
116
+ cut = key.find("/")
117
+ while cut != -1:
118
+ if key[:cut + 1] in paths:
119
+ return True
120
+ cut = key.find("/", cut + 1)
121
+ return False
122
+
123
+
32
124
  def _parse_numstat(raw):
33
125
  files = []
34
126
  for record in (raw or "").split("\0"):
@@ -107,7 +199,19 @@ def collect_workspace_diff(repo_dir, base, include_diffs=False):
107
199
  diffs.append({"path": path, "patch": chunk})
108
200
 
109
201
  untracked = _git(repo_dir, ["ls-files", "--others", "--exclude-standard", "-z"])
202
+ prefix, preexisting, hashes = _preexisting_untracked(repo_dir)
110
203
  for path in sorted(p for p in (untracked or "").split("\0") if p and not _excluded(p)):
204
+ key = prefix + path
205
+ if _covered(key, preexisting):
206
+ # The user's file, never committed. Listed only when the run changed
207
+ # it, with no counts and no patch: the old bytes were never stored,
208
+ # and its content (a config.local.json the agent un-ignored) must
209
+ # not land in the receipt.
210
+ recorded = hashes.get(key)
211
+ if recorded and _content_hash(os.path.join(repo_dir, path)) != recorded:
212
+ files.append({"path": path, "insertions": 0, "deletions": 0,
213
+ "status": "preexisting_modified"})
214
+ continue
111
215
  stat = _git(
112
216
  repo_dir,
113
217
  ["diff", "--no-index", "--no-renames", "--numstat", "-z", "--", "/dev/null", path],
@@ -138,4 +242,11 @@ def collect_workspace_diff(repo_dir, base, include_diffs=False):
138
242
  }, diffs
139
243
 
140
244
 
141
- __all__ = ["collect_workspace_diff"]
245
+ __all__ = ["collect_workspace_diff", "write_snapshot_hashes"]
246
+
247
+
248
+ if __name__ == "__main__":
249
+ # run.sh: python3 -E workspace_diff.py hash-snapshot <repo top> <snapshot>
250
+ if len(sys.argv) != 4 or sys.argv[1] != "hash-snapshot":
251
+ sys.exit("usage: workspace_diff.py hash-snapshot <repo top> <snapshot>")
252
+ write_snapshot_hashes(sys.argv[2], sys.argv[3])
@@ -18,6 +18,13 @@
18
18
  # LOKI_CHECKLIST_TIMEOUT - Timeout per check in seconds (default: 30)
19
19
  # LOKI_CHECKLIST_ENABLED - Enable/disable checklist (default: true)
20
20
  #
21
+ # Inline Python (D7): verification runs with the cwd inside the agent's repo,
22
+ # so every python3 here runs -E (an empty PYTHONPATH component would load a
23
+ # committed sitecustomize.py) and every -c / - body drops '' and '.' from
24
+ # sys.path before any other import (a committed json.py would print the
25
+ # verdict). Pinned by tests/moat/p2-honest-verdict.sh
26
+ # P2.checklist-verify-not-shadowed.
27
+ #
21
28
  # Data:
22
29
  # .loki/checklist/checklist.json - Full checklist with verification
23
30
  # .loki/checklist/verification-results.json - Summary of last verification
@@ -198,7 +205,8 @@ checklist_oracle_triangulate() {
198
205
  _ORACLE_OUT="$findings_file" \
199
206
  _ORACLE_PROJECT="$project_dir" \
200
207
  _ORACLE_INSTALL_DIR="$oracle_install_dir" \
201
- python3 - > "$status_file" 2>/dev/null <<'ORACLE_PY'
208
+ python3 -E - > "$status_file" 2>/dev/null <<'ORACLE_PY'
209
+ import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
202
210
  import json, os, re, sys, tempfile, glob
203
211
 
204
212
  spec_path = os.environ["_ORACLE_SPEC"]
@@ -693,7 +701,7 @@ checklist_oracle_evidence() {
693
701
  if [ ! -f "$findings_file" ]; then
694
702
  return 0
695
703
  fi
696
- _ORACLE_OUT="$findings_file" python3 -c '
704
+ _ORACLE_OUT="$findings_file" python3 -E -c 'import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
697
705
  import json, os
698
706
  try:
699
707
  with open(os.environ["_ORACLE_OUT"]) as f:
@@ -797,7 +805,7 @@ checklist_select_heldout() {
797
805
  # items the build loop already saw in earlier prompts (the hidden-from-loop
798
806
  # guarantee is best-effort once the checklist ids change mid-run).
799
807
  local status_token
800
- status_token=$(_CHECKLIST_FILE="$CHECKLIST_FILE" _HELDOUT_FILE="$heldout_file" python3 -c "
808
+ status_token=$(_CHECKLIST_FILE="$CHECKLIST_FILE" _HELDOUT_FILE="$heldout_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
801
809
  import json, os, sys, hashlib, tempfile
802
810
 
803
811
  cl_path = os.environ['_CHECKLIST_FILE']
@@ -945,7 +953,7 @@ checklist_heldout_ids() {
945
953
  if [ ! -f "$heldout_file" ]; then
946
954
  return 0
947
955
  fi
948
- _HELDOUT_FILE="$heldout_file" python3 -c "
956
+ _HELDOUT_FILE="$heldout_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
949
957
  import json, os
950
958
  try:
951
959
  with open(os.environ['_HELDOUT_FILE']) as f:
@@ -991,7 +999,7 @@ checklist_verify() {
991
999
 
992
1000
  log_step "Running PRD checklist verification..."
993
1001
 
994
- python3 "$verify_script" \
1002
+ python3 -E "$verify_script" \
995
1003
  --checklist "$CHECKLIST_FILE" \
996
1004
  --timeout "$CHECKLIST_TIMEOUT" 2>/dev/null || true
997
1005
 
@@ -1023,7 +1031,7 @@ checklist_summary() {
1023
1031
  _CHECKLIST_RESULTS="$CHECKLIST_RESULTS_FILE" \
1024
1032
  _CHECKLIST_WAIVERS="${CHECKLIST_DIR:-".loki/checklist"}/waivers.json" \
1025
1033
  _CHECKLIST_HELDOUT="${CHECKLIST_DIR:-".loki/checklist"}/held-out.json" \
1026
- python3 -c "
1034
+ python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1027
1035
  import json, sys, os
1028
1036
  try:
1029
1037
  fpath = os.environ.get('_CHECKLIST_RESULTS', '')
@@ -1126,7 +1134,7 @@ checklist_as_evidence() {
1126
1134
  echo "## PRD Checklist Verification"
1127
1135
  echo ""
1128
1136
 
1129
- _CHECKLIST_RESULTS="$CHECKLIST_RESULTS_FILE" python3 -c "
1137
+ _CHECKLIST_RESULTS="$CHECKLIST_RESULTS_FILE" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1130
1138
  import json, os
1131
1139
  try:
1132
1140
  data = json.load(open(os.environ['_CHECKLIST_RESULTS']))
@@ -1162,7 +1170,7 @@ checklist_waiver_load() {
1162
1170
  if [ ! -f "$waivers_file" ]; then
1163
1171
  return 0
1164
1172
  fi
1165
- _WAIVERS_FILE="$waivers_file" python3 -c "
1173
+ _WAIVERS_FILE="$waivers_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1166
1174
  import json, sys, os
1167
1175
  try:
1168
1176
  waivers_file = os.environ['_WAIVERS_FILE']
@@ -1186,7 +1194,7 @@ checklist_waiver_add() {
1186
1194
  local timestamp
1187
1195
  timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
1188
1196
 
1189
- _WAIVERS_FILE="$waivers_file" python3 -c "
1197
+ _WAIVERS_FILE="$waivers_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1190
1198
  import json, os, sys
1191
1199
 
1192
1200
  waivers_file = os.environ['_WAIVERS_FILE']
@@ -1239,7 +1247,7 @@ checklist_waiver_remove() {
1239
1247
  return 1
1240
1248
  fi
1241
1249
 
1242
- _WAIVERS_FILE="$waivers_file" python3 -c "
1250
+ _WAIVERS_FILE="$waivers_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1243
1251
  import json, os, sys
1244
1252
 
1245
1253
  waivers_file = os.environ['_WAIVERS_FILE']
@@ -1275,7 +1283,7 @@ checklist_waiver_list() {
1275
1283
  return 0
1276
1284
  fi
1277
1285
 
1278
- _WAIVERS_FILE="$waivers_file" python3 -c "
1286
+ _WAIVERS_FILE="$waivers_file" python3 -E -c "import sys; sys.path[:] = [p for p in sys.path if p not in ('', '.')]
1279
1287
  import json, os
1280
1288
  waivers_file = os.environ['_WAIVERS_FILE']
1281
1289
  with open(waivers_file) as f: