diff --git a/.console/backlog.md b/.console/backlog.md index d1357f1c..6feae5bb 100644 --- a/.console/backlog.md +++ b/.console/backlog.md @@ -2,8 +2,76 @@ _Durable work inventory. Update after each meaningful chunk of progress._ +## Up Next + +### Vulture has never actually run in the audit gate (⚠️ OPEN — needs a decision) +- **Discovered**: 2026-08-04, while pinning vulture (below). +- **Symptom**: the `audit` gate reports `VULTURE: status=pass count=0`. Run the same + tool by hand and it emits **621 findings** and exits 3. +- **Cause**: the SHA-pinned Custodian (`d6ba8ab`) builds + `vulture --min-confidence=60 ` — the `tests` positional lands *after* + the flag, vulture's argparse rejects it (`unrecognized arguments: tests`), and it + exits 2 with empty stdout. That pinned adapter has no returncode guard, so empty + stdout is read as "no dead code" → `status: pass`. The gate has been green for a + tool that never analysed anything. +- **Already fixed upstream**: current Custodian main puts every path before the + options *and* emits TOOL_ERROR when the returncode is not 0/3 with empty stdout. +- **The decision**: bumping the Custodian SHA (worth doing anyway — main now carries + the `find_tool` fix from Custodian#72) makes those 621 findings real and reds the + audit. They are LOW/advisory and look heavily false-positive (test `side_effect` + attributes, pydantic `model_config`, public-API methods), so the likely resolutions + are a `.vulture_whitelist.py`, a higher `vulture_min_confidence`, or turning + `vulture: false` in `.custodian/config.yaml`. Needs an operator call, not a + unilateral one. + ## Done +### 2026-08-04: Pin vulture — the last unpinned lint tool (✅ COMPLETE) +- **Objective**: close the drift class that red-failed main for a week. +- **What changed**: `vulture==2.16` added to `[project.optional-dependencies].dev`; + the separate `pip install vulture` dropped from `custodian-audit.yml` so it now + arrives via `pip install -e ".[dev]"` alongside ruff and ty. +- **Verification**: `ruff check .` clean under the pinned 0.15.13; audit clean; + vulture 2.16 resolves from the OC venv. +- **Note**: this makes vulture's behaviour deterministic but does NOT make it run — + see the open item above. + +### 2026-08-04: CI lint toolchain pinned (#492) (✅ COMPLETE) +- **Problem**: CI failed on `main` every day from ~2026-07-29. Both lint gates + installed ruff unpinned (`ci.yml` had `pip install "ruff>=0.5"`, + `custodian-audit.yml` had `pip install ruff vulture ty`) while the repo pins + `ruff==0.15.13`. Ruff floated to 0.16.1: `ruff check .` went from clean to **1996 + errors** and the audit to **1222 findings**, none of them real — + `[tool.ruff.lint]` records BLE001 and S110 as deliberately dropped, and a newer + ruff re-enables exactly those (BLE001 ×316, UP045 ×290). +- **Fix**: both jobs install `-e ".[dev]"`, so the version comes from pyproject — + one source of truth, no version literal left in the workflows. Also dropped + `|| true` from the repo install: on failure the adapters found no ruff, Custodian + reported it "not installed" and skipped it, and the gate passed vacuously. +- **Verified**: main green on `f349d0e8` (CI + custodian-audit both success), the + first green main since before 2026-07-29. + +### 2026-08-04: Executor-backend self-heal widened to critique_executor (#491) (✅ COMPLETE) +- **Problem**: `ensure_executor_backends()` in `scripts/operations-center.sh` covered + only two of the three backends OC imports — it probed + `import team_executor, dag_executor` and looped over `TeamExecutor DAGExecutor`. + `critique_executor` (sibling `../CritiqueExecutor`, imported by + `backends/critique_executor/adapter.py`) was in neither, so a `uv sync` or + venv-recreate that dropped it was never auto-repaired and every critique-topology + task failed at execute with `No module named 'critique_executor'`. +- **Root cause**: the probe and the install loop were two hardcoded lists inside one + function, so widening one without the other was silent. Collapsed to a single + `EXECUTOR_BACKENDS` array of `:` pairs that both + derive from; cross-reference comments added in `scripts/operations-center.sh` and + `backends/factory.py`. +- **Also fixed**: `.hooks/pre-push` computed `workspace_root` as `$repo_root/..`, + which inside a git worktree resolves to `.claude/worktrees` — no siblings, so the + boundary-artifact glob matched nothing and every push from a worktree failed + closed. Now derived from `git rev-parse --git-common-dir`. +- **Verified**: against the live stack — probe builds exactly + `import team_executor, dag_executor, critique_executor`; a throwaway empty venv + had all three installed by the real `uv` path and a second call was a silent no-op. + ### 2026-07-15: Stage 4 — Refactor existing code to use the new shared helper (✅ COMPLETE) - **Objective**: Independently re-verify Stage 2's migration against the "refactor existing code" acceptance bar (identified/updated all relevant callsites, replaced redundant diff --git a/.console/log.md b/.console/log.md index aae1f04d..521c68bc 100644 --- a/.console/log.md +++ b/.console/log.md @@ -1,3 +1,45 @@ +## 2026-08-04 — fix(deps): pin vulture — and discover the audit never ran it + +Closing the last unpinned lint tool after #492. `.custodian/config.yaml` sets +`vulture: true`, so the audit gate runs it, but `pyproject.toml` pinned only ruff, +ty and custodian@SHA; `custodian-audit.yml` installed vulture separately and +unpinned. That is the identical drift class that red-failed main for a week. +`vulture==2.16` now lives in the dev extras and the separate install is gone, so it +arrives via `pip install -e ".[dev]"` with everything else. + +Verifying the pin turned up something larger. The audit reports +`VULTURE: status=pass count=0`. Running the same tool by hand: + + vulture src tests --min-confidence=60 -> exit 3, 621 findings + vulture src --min-confidence=60 tests -> exit 2, 0 lines + "unrecognized arguments: tests" + +The second is what OC's gate actually runs. The SHA-pinned Custodian (`d6ba8ab`) +builds the command as `[vulture, src_root, --min-confidence=N, tests_root]` — the +`tests` positional lands after the flag, vulture's argparse rejects it, and it exits +2 with empty stdout. That adapter version has no returncode guard, so empty stdout is +indistinguishable from a clean repo and the pattern is recorded `status: pass`. The +gate has been green for a tool that never analysed a line. This is exactly the +vacuous-green failure #492's commit message described when it removed `|| true` from +the repo install — the same shape, one layer down, and it was already there. + +Current Custodian main fixes both halves (all paths before the options; TOOL_ERROR +when the returncode is not 0/3 with empty stdout), so bumping the SHA — worth doing +regardless, since main now carries the `find_tool` fix from Custodian#72 — will make +those 621 findings real and red the audit. They are LOW/advisory and read as heavily +false-positive (test `side_effect` attributes, pydantic `model_config`, public-API +methods vulture cannot see called), so the resolution is a `.vulture_whitelist.py`, a +higher `vulture_min_confidence`, or `vulture: false`. That is an operator call about +what the gate should assert, not something to decide inside a pinning change, so it +is recorded in `.console/backlog.md` under Up Next rather than resolved here. + +Pinning does not make vulture run. It makes its behaviour deterministic, so when the +SHA is bumped the 621 are a stable number to triage rather than a moving one. + +Also backfills `.console/backlog.md`, which CLAUDE.md requires updating after +meaningful progress and which had not been touched since #474 — entries added for +#491 and #492 alongside this work. + ## 2026-08-03 — fix(hooks): pre-push resolved the wrong workspace root inside a git worktree `.hooks/pre-push` locates the boundary disclosure artifact by globbing sibling diff --git a/.github/workflows/custodian-audit.yml b/.github/workflows/custodian-audit.yml index 04ec4842..f300dfda 100644 --- a/.github/workflows/custodian-audit.yml +++ b/.github/workflows/custodian-audit.yml @@ -26,10 +26,12 @@ jobs: run: | python -m pip install --upgrade pip pip install "custodian[tools] @ git+https://github.com/ProtocolWarden/Custodian.git@d6ba8ab245c6f4e79e9f8fffd4e4221bfaf266e8" - pip install vulture - name: Install repo and its pinned lint toolchain - # `.[dev]` (not plain `.`) so the adapters run OC's OWN pinned ruff/ty. + # `.[dev]` (not plain `.`) so the adapters run OC's OWN pinned ruff/ty/vulture. + # vulture used to be `pip install vulture` in the step above — the last + # unpinned lint tool, and the same drift class as the ruff one below. It now + # comes from the dev extras with everything else. # The reproducibility argument in the step above applies one level down: # pinning Custodian while installing `ruff` unpinned just moves the moving # part. It floated to 0.16.1 and this gate reported 1222 findings against a diff --git a/pyproject.toml b/pyproject.toml index 9d3d96d1..c7c672e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -137,6 +137,11 @@ dev = [ "pytest-cov>=6.0", "ruff==0.15.13", "ty==0.0.40", + # Pinned for the same reason as ruff/ty: `.custodian/config.yaml` sets + # `vulture: true`, so the audit gate runs it, and an unpinned lint tool is how + # main stayed red for a week (see #492 — `ruff>=0.5` floated to 0.16.1 and + # produced 1222 phantom findings). Custodian resolves it from this venv. + "vulture==2.16", "custodian @ git+https://github.com/ProtocolWarden/Custodian.git@d6ba8ab245c6f4e79e9f8fffd4e4221bfaf266e8", ]