@@ -4,45 +4,23 @@ _Chronological continuity log. Decisions, stop points, what changed and why._
44
55## 2026-08-03 — fix(adapters): find_tool must prefer the AUDITED repo's venv
66
7- Found while triaging why OperationsCenter's Custodian pre-push gate failed. A
8- globally-installed ` custodian-multi ` audited OC — which pins ` ruff==0.15.13 ` —
9- using a system-wide ** ruff 0.16.1** , and reported ** 1222 findings** against a tree
10- OC's own ` ruff check ` calls clean (BLE001 ×316, UP045 ×290, UP037 ×118, …). Same
11- repo, same ` .custodian/config.yaml ` , ruff 0.15.13: ** 0 findings** . Vulture skewed
12- the same way (621). Every one of those was phantom.
13-
14- Root cause: ` find_tool() ` resolved ` Path(sys.executable).parent / name ` — i.e. the
15- venv ** Custodian itself** is installed in — then fell back to PATH. For a
16- * multi-repo* auditor that is backwards. Each repo pins the toolchain its config was
17- written against, so the audit is only meaningful when it runs those versions; the
18- venv Custodian happens to live in has no authority over the repo in front of it. It
19- was right by accident in the single-repo case (Custodian installed into the audited
20- repo's venv) and silently wrong everywhere else.
21-
22- Second, smaller bug in the same three lines: ` Path(sys.executable).parent / name `
23- can never match on Windows, where console scripts are ` ruff.exe ` and live in
24- ` Scripts/ ` rather than ` bin/ ` . So the venv branch was dead code on that platform and
25- every lookup fell through to PATH.
26-
27- Fix: resolution order is now (1) the audited repo's own venv, (2) Custodian's venv,
28- (3) PATH; ` _executable() ` tries ` .exe ` /` .bat ` /` .cmd ` on Windows and both ` bin/ ` and
29- ` Scripts/ ` are accepted on either host (a venv built under WSL and audited from
30- Windows over /mnt/c carries the other platform's layout). The audited repo is scoped
31- by a ` ContextVar ` + ` audited_repo() ` context manager rather than a parameter, because
32- ` is_available() ` takes no arguments and it and ` run() ` must agree on which binary
33- they are discussing — ` cli/runner._run_adapters ` wraps its loop in it.
34-
35- Verified: 1238 passed, 5 skipped. Six new tests cover repo-venv preference, the
36- no-venv fallback, both script-dir spellings, and that the ContextVar does not leak
37- past the loop (a leak would make later repos in a ` --repos a b c ` run inherit the
38- first repo's toolchain). Custodian's own audit is unchanged from baseline — the one
39- remaining finding (W2, ` core.hooksPath ` unset) is environmental and pre-existing.
40- Live proof on this machine: under ` audited_repo(~/GitHub/OperationsCenter) ` ,
41- ` find_tool('ruff') ` returns OC's pinned ` .venv/bin/ruff ` instead of Custodian's own.
42-
43- Noted, not fixed (pre-existing, reproduces at origin/main): ` tests/test_reconcile.py `
44- does not isolate ` $REPOGRAPH_BOUNDARY_ARTIFACT_FILE ` , so two tests fail whenever that
45- variable is set in the caller's environment.
7+ ` find_tool() ` resolved tools from the venv ** Custodian itself** runs in, then PATH.
8+ For a multi-repo auditor that is backwards: each repo pins the toolchain its config
9+ was written against. A globally-installed ` custodian-multi ` therefore audited
10+ OperationsCenter (pins ` ruff==0.15.13 ` ) with a system-wide ruff 0.16.1 and reported
11+ ** 1222 phantom findings** against a tree OC's own ` ruff check ` calls clean. Right by
12+ accident when Custodian is installed into the audited repo's venv, silently wrong
13+ otherwise — and silent is the problem, since the output is a plausible wall of real
14+ rule codes. Same three lines hid a second bug: that lookup can never match on
15+ Windows, where scripts are ` ruff.exe ` under ` Scripts/ ` , so the branch was dead code
16+ there. Order is now audited repo's venv → Custodian's venv → PATH, with both
17+ script-dir spellings and Windows suffixes handled. Scoped by a ContextVar +
18+ ` audited_repo() ` rather than a parameter because ` is_available() ` takes no arguments
19+ and must agree with ` run() ` . 1238 passed, 5 skipped; 6 new tests, including that the
20+ ContextVar cannot leak across repos in a ` --repos a b c ` run. Details in PR #72 .
21+
22+ Pre-existing, noted not fixed: ` tests/test_reconcile.py ` does not isolate
23+ ` $REPOGRAPH_BOUNDARY_ARTIFACT_FILE ` , so two tests fail when it is set.
4624
4725## 2026-08-03 — docs(adr): ask ContextLifecycle to split .console/log.md
4826
@@ -403,32 +381,13 @@ itself flagged as an unused variable.
403381Verified: ruff clean, vulture clean, suite unchanged at 1153 passed / 16
404382pre-existing Windows-only failures, audit 0 findings under CI conditions.
405383
406- ## 2026-07-10 — fix(c32): reject punctuation-only values as credentials
407-
408- C32 (hardcoded credential) fired a HIGH false positive on a downstream repo's
409- ` _TOKEN_STRIP = ".,!?;:\"'()—-" ` — the name contains "token" so ` _is_credential_name `
410- matched, and the punctuation value passed ` _is_real_credential ` (not a placeholder,
411- not a URL, not ALL_CAPS). A real secret carries alphanumeric entropy; a value with
412- zero alphanumeric characters can never be a credential. Added that guard to
413- ` _is_real_credential ` + a regression test (` test_c32_skips_punctuation_only_value ` ).
414- 12 C32 tests pass.
415-
416- ## 2026-06-20 — feat: INJ1 prompt-injection signature detector
417-
418- New audit_kit detector (HARNESS_TRUST_HARDENING §2.2.6, the outer INJ layer):
419- detect_inj1 scans tracked text for invisible/bidi control characters (the
420- unambiguous injection/homoglyph-smuggling signal). Mirrors the boundary-detector
421- shape; wired into the runner as deprecated=True so it is SKIPPED by the default
422- gate (opt-in via --only INJ1 --include-deprecated) — a repo's own injection-
423- handling code must not red the fleet-wide audit. Reports codepoint+position only
424- (never surrounding text, D-INJ-3); legitimate handlers opt out via a
425- custodian: allow-invisible-chars content marker; \u escapes so it never
426- self-triggers. 7 tests; full suite 1126 passed.
427-
428384<!-- Reconciled 2026-08-03 (RC1): `## Stop Points`, `## Recent Decisions`
429385 (2026-05 material) and entries through 2026-06-18 pruned to stay under
430386 the 400-line budget. Full history is in git — `git log -p .console/log.md`.
431- See docs/architecture/adr/0001-split-console-log-by-responsibility.md. -->
387+ See docs/architecture/adr/0001-split-console-log-by-responsibility.md.
388+ Second pass, same day: the 2026-06-20 (INJ1 detector) and 2026-07-10
389+ (C32 punctuation-only values) entries pruned as well — the first pass
390+ landed at 395/400, leaving no room for the next entry to be written. -->
432391
433392## Archived
434393
0 commit comments