From 4c29236e093539894b85c4ea3fb54f6d21b2bf80 Mon Sep 17 00:00:00 2001 From: ProtocolWarden <32967198+ProtocolWarden@users.noreply.github.com> Date: Mon, 3 Aug 2026 16:01:34 -0400 Subject: [PATCH 1/2] fix(OperationsCenter): widen executor-backend self-heal to critique_executor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ensure_executor_backends()` in scripts/operations-center.sh reinstalls dropped executor sibling checkouts at every fleet launch, but covered only two of the three backends OC imports: it probed `import team_executor, dag_executor` and looped over `TeamExecutor DAGExecutor`. `critique_executor` — imported as a library by backends/critique_executor/adapter.py, backed by the sibling checkout ../CritiqueExecutor — was in neither list. A `uv sync` or venv-recreate that dropped it was therefore NOT auto-repaired, so every critique-topology task failed at execute with `No module named 'critique_executor'` until a human noticed: the exact failure mode the self-heal exists to prevent for the other two. The drift was structural — the probe and the install loop were two separate hardcoded lists inside one function, so widening one without the other was easy and silent. Collapsed them into a single EXECUTOR_BACKENDS array of `:` pairs; both the probe's import statement and the install loop derive from it. Behavior is otherwise unchanged (still all-or-nothing: any missing module reinstalls all siblings; missing `uv` or a missing checkout still degrades to a WARNING rather than aborting launch). Not sourced from Python, deliberately. The nearest real Python lists are BackendName / EXECUTOR_LANE_NAMES (contracts/enums.py) and the backends/factory.py registry, but neither carries the checkout-dir half of each pair and it is not derivable (`dag_executor` -> `DAGExecutor`, not `DagExecutor`). More fundamentally, this self-heal has to run precisely when the venv is too broken to import operations_center. Cross-reference comments added in both scripts/operations-center.sh and backends/factory.py, each naming the other, so adding a backend updates both. Verified against the live stack (siblings at ~/GitHub/{TeamExecutor,DAGExecutor,CritiqueExecutor}): `bash -n` clean; the probe builds exactly `import team_executor, dag_executor, critique_executor`; silent no-op with rc=0 against the real fleet venv; against a throwaway empty venv the real `uv` path installed all three (+ critique-executor==0.1.0 from file:///home/diane/GitHub/CritiqueExecutor), all three then imported, and a second call was a silent no-op. Fleet venv untouched. tests/unit/backends/test_factory.py + test_critique_executor_adapter.py: 5 passed. ruff check + format clean. Co-Authored-By: Claude Opus 5 --- .console/log.md | 42 ++++++++++++++++++++ scripts/operations-center.sh | 47 +++++++++++++++++------ src/operations_center/backends/factory.py | 7 ++++ 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/.console/log.md b/.console/log.md index 05306f9b0..515feb077 100644 --- a/.console/log.md +++ b/.console/log.md @@ -1,3 +1,45 @@ +## 2026-08-03 — fix(launcher): widen executor-backend self-heal to critique_executor + +`ensure_executor_backends()` in `scripts/operations-center.sh` self-heals dropped +executor sibling checkouts at every fleet launch, but covered only two of the three +OC actually 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 left every critique-topology task failing at +execute with `No module named 'critique_executor'` — the exact failure the self-heal +exists to prevent for the other two — until a human noticed. + +Root cause of the drift was structural: the probe and the install loop were TWO +hardcoded lists inside one function, so widening one without the other was easy and +silent. Collapsed to a single `EXECUTOR_BACKENDS` array of +`:` pairs; the probe's import statement and the +install loop are both derived from it. Behavior is otherwise unchanged (still +all-or-nothing: any missing module reinstalls all siblings). + +Did NOT source the list from Python. The task note assumed +`entrypoints/setup/main.py` already held an authoritative `EXECUTOR_BACKENDS` +tuple — it does not, and no such constant exists anywhere in the repo (verified at +bb65da3b in both the Windows and WSL2 checkouts). The nearest real Python lists are +`BackendName` / `EXECUTOR_LANE_NAMES` (`contracts/enums.py`) and the +`backends/factory.py` registry, but neither carries the checkout-dir half of each +pair, and it is not derivable (`dag_executor` → `DAGExecutor`, not `DagExecutor`). +Sourcing is also wrong in principle here: this self-heal must run precisely when the +venv is too broken to import `operations_center`. Took the stated fallback instead — +cross-reference comments in both `scripts/operations-center.sh` and +`backends/factory.py`, each naming the other and stating that adding a backend means +updating both. + +Verified against the live WSL2 stack (~/GitHub, siblings at +{TeamExecutor,DAGExecutor,CritiqueExecutor}): `bash -n` clean (after CRLF +normalization — the Windows checkout is CRLF, pre-existing); probe builds exactly +`import team_executor, dag_executor, critique_executor`; no-op + rc=0 against the +real fleet venv where all three already import; against a throwaway empty venv the +real `uv` path installed all three (`+ critique-executor==0.1.0 from +file:///home/diane/GitHub/CritiqueExecutor`) and a second call was a silent no-op. +Missing-`uv` and missing-checkout paths still degrade to a WARNING rather than +aborting launch. Fleet venv untouched. `tests/unit/backends/test_factory.py` + +`test_critique_executor_adapter.py` 5 passed. + ## 2026-07-15 — feat(reviewer): ACTIVATE the council — populate guardrail_paths (§G1) The council's go-live. C1/C2/C3 all merged; `reviewer.council.guardrail_paths` diff --git a/scripts/operations-center.sh b/scripts/operations-center.sh index 1c7ebc82d..d811423ab 100755 --- a/scripts/operations-center.sh +++ b/scripts/operations-center.sh @@ -69,22 +69,45 @@ ensure_venv() { ensure_executor_backends } -# The execute backends (team_executor, dag_executor) are sibling CHECKOUTS, not -# declared OC dependencies — `uv pip install -e .[dev]` never installs them and a -# `uv sync` / venv-recreate actively DROPS them. When that happens the executor -# can't load its backend ("team_executor not installed: No module named -# 'team_executor'") and EVERY goal task fails at execute → the whole lane stalls -# with no obvious cause. Self-heal: whenever the backends aren't importable, (re)install -# them editable. Runs every launch but the import check is ~free and the install only -# fires when actually missing, so a mid-life drop recovers on the next fleet start -# rather than blocking autonomy until a human notices. +# The execute backends (team_executor, dag_executor, critique_executor) are sibling +# CHECKOUTS, not declared OC dependencies — `uv pip install -e .[dev]` never installs +# them and a `uv sync` / venv-recreate actively DROPS them. When that happens the +# executor can't load its backend ("team_executor not installed: No module named +# 'team_executor'") and EVERY task routed to that lane fails at execute → the lane +# stalls with no obvious cause. Self-heal: whenever the backends aren't importable, +# (re)install them editable. Runs every launch but the import check is ~free and the +# install only fires when actually missing, so a mid-life drop recovers on the next +# fleet start rather than blocking autonomy until a human notices. +# +# ONE list, `:` — the probe and the install loop +# below are both derived from it. They used to be two hardcoded lists and drifted: +# critique_executor was in neither, so critique-topology tasks failed at execute with +# `No module named 'critique_executor'` until a human noticed. +# +# CROSS-REFERENCE: the authoritative backend registry is the Python side — +# `src/operations_center/backends/factory.py` (adapter registry) and `BackendName` / +# `EXECUTOR_LANE_NAMES` in `src/operations_center/contracts/enums.py`. Bash cannot +# source those: the checkout-dir half of each pair exists nowhere in Python (and is +# not derivable — `dag_executor` → `DAGExecutor`, not `DagExecutor`), and this +# self-heal has to run when the venv is too broken to import operations_center at +# all. ADDING AN EXECUTOR BACKEND MEANS UPDATING BOTH SIDES. +EXECUTOR_BACKENDS=( + team_executor:TeamExecutor + dag_executor:DAGExecutor + critique_executor:CritiqueExecutor +) + ensure_executor_backends() { - if "${VENV_DIR}/bin/python" -c "import team_executor, dag_executor" 2>/dev/null; then + local _spec _sib _imports="" + for _spec in "${EXECUTOR_BACKENDS[@]}"; do + _imports="${_imports:+${_imports}, }${_spec%%:*}" + done + if "${VENV_DIR}/bin/python" -c "import ${_imports}" 2>/dev/null; then return 0 fi echo "operations-center.sh: executor backends missing — (re)installing siblings" >&2 - local _sib - for _sib in TeamExecutor DAGExecutor; do + for _spec in "${EXECUTOR_BACKENDS[@]}"; do + _sib="${_spec##*:}" if [[ -f "${ROOT_DIR}/../${_sib}/pyproject.toml" ]]; then uv pip install --python "${VENV_DIR}/bin/python" -e "${ROOT_DIR}/../${_sib}" \ || echo "operations-center.sh: WARNING failed to install ${_sib} — execute backend unavailable" >&2 diff --git a/src/operations_center/backends/factory.py b/src/operations_center/backends/factory.py index 849ad4d82..e4a9fc4b7 100644 --- a/src/operations_center/backends/factory.py +++ b/src/operations_center/backends/factory.py @@ -5,6 +5,13 @@ The registry resolves a routed backend name to a canonical adapter that accepts ExecutionRequest and returns ExecutionResult. + +CROSS-REFERENCE: the executor-lane adapters (team_executor, dag_executor, +critique_executor) import sibling CHECKOUTS that are not declared OC dependencies. +`ensure_executor_backends()` in ``scripts/operations-center.sh`` keeps them installed +in the fleet venv and hardcodes its own ``:`` list +(bash cannot source this module — the self-heal must run when the venv is too broken +to import operations_center). ADDING AN EXECUTOR BACKEND MEANS UPDATING BOTH. """ from __future__ import annotations From 89903c07cfbe2d379e5c5b46eaf925f6a5988c70 Mon Sep 17 00:00:00 2001 From: ProtocolWarden <32967198+ProtocolWarden@users.noreply.github.com> Date: Mon, 3 Aug 2026 16:56:50 -0400 Subject: [PATCH 2/2] fix(hooks): resolve the workspace root from --git-common-dir, not $repo_root/.. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `.hooks/pre-push` finds the boundary disclosure artifact by globbing sibling checkouts of the main clone: workspace_root="$(cd "$repo_root/.." && pwd)" "$workspace_root"/*/dist/boundary_disclosure_artifact.json That assumes $repo_root is the main clone. Inside a git worktree it is not: repo_root is .../OperationsCenter/.claude/worktrees/, so workspace_root resolved to .../.claude/worktrees — a directory with no siblings. The glob matched nothing and every push from a worktree failed closed with "missing REPOGRAPH_BOUNDARY_ARTIFACT_FILE", pointing the operator at a generation step they had already done one directory over. `git rev-parse --git-common-dir` is shared by the main clone and all of its worktrees, so its parent is always the main clone root and that clone's parent is the real workspace root. In a worktree it returns an absolute .../OperationsCenter/.git; in the main clone a bare ".git" — hence resolving it relative to $repo_root and taking the realpath via cd. Verified from both: the worktree now auto-discovers PrivateManifest/dist/boundary_disclosure_artifact.json, and the main clone resolves to the identical path it did before, so there is no behaviour change anywhere the old code already worked. `bash -n` clean. Co-Authored-By: Claude Opus 5 --- .console/log.md | 33 +++++++++++++++++++++++++++++++++ .hooks/pre-push | 15 ++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/.console/log.md b/.console/log.md index 515feb077..cc6f3911d 100644 --- a/.console/log.md +++ b/.console/log.md @@ -1,3 +1,36 @@ +## 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 +checkouts: `workspace_root="$(cd "$repo_root/.." && pwd)"`, then +`$workspace_root/*/dist/boundary_disclosure_artifact.json`. That assumes +`$repo_root` is the main clone. Inside a **git worktree** it is not — repo_root is +`.../OperationsCenter/.claude/worktrees/`, so workspace_root resolved to +`.../.claude/worktrees`, a directory with no siblings at all. The glob matched +nothing, and every push from a worktree died on +`missing REPOGRAPH_BOUNDARY_ARTIFACT_FILE; failing closed` — a file it had no way +to find and that the operator had already generated one directory over. + +Fixed by deriving the main clone root from `git rev-parse --git-common-dir`, which +the main clone and all of its worktrees share. Its parent is always the main clone, +whose parent is the real workspace root. Verified from both: the worktree now +auto-discovers `PrivateManifest/dist/boundary_disclosure_artifact.json`, and the +main clone resolves to exactly the same path it did before (no behaviour change +where the old code already worked). + +Found while triaging why this branch could not be pushed. Two further faults sat on +top of it, neither in this repo, both since fixed: +- The WSL2 fleet clone had no boundary artifact anywhere under `~/GitHub`, so its + own pre-push failed at B2 before Custodian even ran. PrivateManifest was not + checked out there at all; it now is, and the artifact is generated from it. The + real hook now passes unaided in the fleet clone: 0 findings, exit 0. +- Custodian's `find_tool()` preferred *its own* venv over the audited repo's, so a + globally-installed `custodian-multi` audited OC (pinned `ruff==0.15.13`) with a + system-wide ruff 0.16.1 and produced 1222 phantom findings against a tree that is + clean. Fixed upstream in ProtocolWarden/Custodian#72. + +The OC baseline itself was never dirty: with the right toolchain and the artifact +configured, the gate returns 0 findings / 0 HIGH / 0 MED / clean. + ## 2026-08-03 — fix(launcher): widen executor-backend self-heal to critique_executor `ensure_executor_backends()` in `scripts/operations-center.sh` self-heals dropped diff --git a/.hooks/pre-push b/.hooks/pre-push index 2b21a167a..d043d92e2 100755 --- a/.hooks/pre-push +++ b/.hooks/pre-push @@ -3,7 +3,20 @@ set -e repo_root="$(git rev-parse --show-toplevel)" -workspace_root="$(cd "$repo_root/.." && pwd)" + +# Sibling checkouts (the private manifest holding the boundary artifact, Custodian) +# live next to the MAIN clone, so workspace_root must be the main clone's parent. +# `$repo_root/..` gets that wrong inside a git worktree: repo_root is then +# .../OperationsCenter/.claude/worktrees/, so workspace_root resolved to +# .../.claude/worktrees — a directory with no siblings, the artifact glob below +# matched nothing, and every push from a worktree failed closed on a missing +# REPOGRAPH_BOUNDARY_ARTIFACT_FILE it could not have found. `--git-common-dir` is +# shared by the main clone and all its worktrees, so its parent is always the main +# clone root (in a worktree it is an absolute .../OperationsCenter/.git; in the main +# clone a bare ".git", hence the -C "$repo_root" and the realpath via cd). +git_common_dir="$(cd "$repo_root" && cd "$(git rev-parse --git-common-dir)" && pwd)" +main_clone_root="$(cd "$git_common_dir/.." && pwd)" +workspace_root="$(cd "$main_clone_root/.." && pwd)" if [ -z "${REPOGRAPH_BOUNDARY_ARTIFACT_FILE:-}" ]; then shopt -s nullglob