Skip to content

chore: delete orphaned mechanisms and enforce the rule in CI - #603

Merged
chubes4 merged 1 commit into
mainfrom
chore/dead-mechanism-audit
Sep 17, 2026
Merged

chubes4 merged 1 commit into
mainfrom
chore/dead-mechanism-audit

Conversation

@chubes4

@chubes4 chubes4 commented Sep 17, 2026

Copy link
Copy Markdown
Member

Implements the rule proposed in #601 §6, and applies it.

Why this is the follow-up to #601

#601 was not really a bug about sudoers. lib/systems-capabilities.sh had a correct, validated grant installer; its only consumer was retired; the function stayed with zero call sites. The next component that needed a grant didn't find it and wrote its own — which installed the file before validating it, and could leave a rejected policy in /etc/sudoers.d that locks every user out of sudo.

The duplicate was the symptom. The cause is that an orphaned mechanism is invisible: it reads as supported infrastructure, it has a docblock describing what it does, and nothing tells the next author it's already dead.

Judgement doesn't catch this — two implementations of sudoers installation survived months of review. A grep does, cheaply, on every push.

What the audit found

Ten functions, 120 lines. Most are one story: vestigial entrypoints left behind by the convergence refactor.

runtime_guidance_desired_state_apply()  { reconciler_apply_plan; }
runtime_guidance_desired_state_verify() { reconciler_verify_plan; }
integration_adapters_verify()           { reconciler_verify_plan; }

Once convergence_apply / convergence_verify became the single entrypoint, each module's own apply/verify pass-through stopped being called and stayed — three alternative front doors to one room, all bricked up.

install_chat_bridge is the sharpest example. Its docblock:

install_chat_bridge — setup-time entrypoint, dispatched from setup.sh.

setup.sh has gone through the convergence orchestrator for some time and never calls it. The comment documents an architecture that no longer exists, which is worse than no comment: it's a confident wrong answer to "how does the bridge get installed?"

The rest: reconciler_mark_changed (a dead twin of reconciler_adapter_changed, which has 14 call sites — the same duplicate-mechanism shape as #601, caught before it could be the survivor), runtime_sync_instructions in runtimes/codex.sh (a hook the contract dropped in favour of runtime_generate_instructions, which all three runtimes implement), homeboy_json_array, _datamachine_worker_shell_quote, and _resolve_claude_code_agent_slug.

Dead code hides more dead code. Removing _resolve_claude_code_agent_slug orphaned _dm_agent_slug_exists, its only consumer — caught on the audit's next pass. Run to a fixpoint, the repo is clean.

On _resolve_claude_code_agent_slug specifically: it's unreachable, so AGENT_SLUG already stays empty on upgrade unless --agent-slug is passed. That is a handled state — hooks/dm-agent-sync.sh falls back to discovering all active agents, as the function's own comment said it would. Behaviour is unchanged by deleting it. If pinning a single agent on upgrade is wanted, it should be wired to a caller, not left as a 37-line unreachable statement of intent.

The check

tests/dead-mechanism.sh, wired into CI. Bash dispatches indirectly, so a function can be live without its name ever appearing at a call site. Rather than hardcode the dispatchers, it reads the prefixes out of the source:

indirect-dispatch prefixes discovered: bridge_, bridge_service_adapter_apply_,
                                       bridge_service_adapter_verify_, guidance_

so a new dispatcher is understood the moment it's written. Anything under a discovered prefix is treated as reachable — a deliberate blind spot, documented in the file. Dead code under bridge_ or guidance_ won't be caught. Narrow and honest beats broad and wrong: a checker with false positives gets an allowlist, then gets ignored, then gets deleted. ALLOWED exists and is empty; if it grows, the rule is being worked around rather than followed.

Before:

audited 579 production functions across 51 files
9 function(s) defined with no reachable caller

After, at fixpoint:

audited 569 production functions across 51 files
no orphaned mechanisms

Verification

Full suite on Linux: 71 pass, 4 fail. The same 4 fail on a pristine main clone on the same host — datamachine-worker, opencode-general-dispatch, opencode-subagents, workspace-materialization — all environment-dependent there (/tmp is world-writable, wp resolves to an absolute path), not regressions. Verified by cloning main and running them side by side rather than assuming.

bash -n clean across every .sh. No dangling references to any removed name. tests/ci-coverage.sh — the sibling check that catches tests CI never runs — passes with the new job wired.


AI assistance: audited and implemented by Claude Opus 4.5 via Claude Code, driven by Chris. The model wrote the reachability audit, manually verified its output against the dispatchers to confirm zero false positives before trusting it, removed the dead set to a fixpoint, and ran the full suite against both this branch and pristine main on a Linux host to separate regressions from pre-existing environmental failures.

#601 was not really about sudoers. lib/systems-capabilities.sh had a correct,
validated grant installer whose only consumer was retired; the function stayed
with zero call sites. The next component that needed one did not find it and
wrote a weaker copy that installed before validating. The duplicate was the
symptom; the cause is that an orphaned mechanism is invisible -- it reads as
supported infrastructure, it has a docblock, and nothing tells the next author
it is already dead.

An audit found ten across the repo, 120 lines. Most are vestigial entrypoints
left by the convergence refactor: runtime_guidance_desired_state_apply,
integration_adapters_verify and friends are one-line pass-throughs to
reconciler_apply_plan and reconciler_verify_plan, superseded by
convergence_apply/convergence_verify and called by nothing. install_chat_bridge
still documented itself as 'the setup-time entrypoint, dispatched from
setup.sh' -- setup.sh has gone through the convergence orchestrator for some
time. Deleting _resolve_claude_code_agent_slug orphaned its only helper, which
the audit then caught on the next pass: dead code hides more dead code.

tests/dead-mechanism.sh makes the rule enforceable. Bash dispatches indirectly,
so it reads the three dispatch prefixes out of the source rather than
hardcoding them, and treats anything under a discovered prefix as reachable --
a deliberate blind spot, because a checker with false positives gets an
allowlist, then gets ignored, then gets deleted.

Judgement does not catch this: two implementations of sudoers installation
survived months of review. A grep does, on every push.

Refs #601
@chubes4
chubes4 merged commit 7da728f into main Sep 17, 2026
72 checks passed
@chubes4
chubes4 deleted the chore/dead-mechanism-audit branch September 17, 2026 02:51
chubes4 added a commit that referenced this pull request Sep 17, 2026
…604)

The sibling finding to #603. That audit asked which mechanisms have no
consumer; this one asks which have two bodies.

Escaping was written three times. Two JSON escapers handled backslash, quote
and newline; lib/agent-state-ownership.sh's handled only backslash and quote,
so a value containing a newline emitted a literal newline inside a JSON string
literal -- invalid JSON, in the one copy whose output is machine-read. Nothing
exercised the newline case, which is why the drift survived. XML text escaping
was triplicated across the kimaki bridge and both launchd services, still
identical, waiting to do the same thing.

json_escape and xml_escape now live in lib/common.sh with one implementation
each. Escaping is exactly the code that must exist once: short enough to feel
harmless to re-type, consequential enough that a divergence is a correctness
bug rather than a style difference.

setup_ai_gateway and upgrade_ai_gateway had identical bodies. Two names for one
behaviour reads as 'these differ somehow' to anyone who has not diffed them.
One ai_gateway_apply, called from both.

tests/duplicate-mechanism.sh makes the rule enforceable, comparing normalised
bodies and reporting only exact matches -- near-duplicates are a judgement call,
and a checker that makes judgement calls gets argued with rather than fixed.

tests/escaping-helpers.sh covers the behaviour, including the newline case that
was missing. Verified to fail against the pre-consolidation escaper and pass
against the shared one.

Refs #601
chubes4 added a commit that referenced this pull request Sep 17, 2026
…605)

Block-level duplication, which the function-level audits in #603 and #604 could
not see: the plist document frame was copy-pasted into six renderers across
three bridges and two services.

The copies had already disagreed. Both services ran their values through
xml_escape; all three bridges interpolated them raw. A SITE_PATH, service home,
log directory, model name, or bot token containing an ampersand rendered a plist
that is not well-formed XML, which launchd refuses to load -- so the agent never
starts, with no failing test anywhere to say why. Verified against main: a path
with '&' in it produces a ParseError at the WorkingDirectory line.

The snapshot fixtures could not catch this because they use tidy values like
/var/www/site. A golden file locks in whatever was rendered the day it was
written, including a bug.

Only the frame is shared. The bodies genuinely differ -- the worker schedules
with StartInterval where the bridges use KeepAlive, and the WordPress service
renders no EnvironmentVariables -- so they stay as readable heredocs. A single
renderer taking seven parameters and three optional blocks to absorb that
variation would be harder to read than the duplication it removed.

All 8 committed snapshots remain byte-identical, so this changes nothing for
values that were already safe.

tests/plist-rendering.sh renders every plist with a value carrying & < > and
asserts the result parses as XML and still contains the value. It fails against
main and passes here.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant