Problem
A consumer configuring a host permission classifier for this plugin's lane has to restate, in prose, facts that actually live in this repository's code. Four rounds of independent review on melodic-software/dotfiles#315 produced a wrong statement about one of these three separate times, and each time the only thing that caught it was a human or agent reading both the prose and the source side by side.
The facts being restated, with where they really live:
- Resolver flag semantics.
babysit_resolve_thread.py enforces bot-only at line 189 iff --include-human is absent, and the isOutdated check at 193 iff --autonomous or --only-outdated. The pin chain at 325 → 345 → 362 is what makes --autonomous mean "single pinned thread" rather than "bulk". A consumer's permission rule that says "resolves only outdated bot threads" is true only for a specific flag combination.
- Where a refusal lives.
bin/source-control-babysit-merge refuses --allow-unpinned-head in bash; babysit_merge.py accepts it as an ordinary argparse flag. Whether an invocation is safe depends on which of the two you called, and nothing in the Python says so.
- Which helpers mutate.
request_review.py --apply posts a comment, prune_babysit_worktrees.py --apply runs git worktree remove, the lease and ledger helpers write state. A consumer that classifies these as read-only is wrong, and the scripts' names do not say which is which.
- What a script actually calls.
refresh_pr_branch.py requests GitHub's server-side update-branch endpoint rather than pushing — safer than it reads, but a consumer reasoning about push guards will reason about the wrong mechanism.
Why it drifts silently
Nothing connects the two. If a flag is added, if the merge wrapper's refusal moves into Python, if a helper starts mutating, the consumer's prose keeps asserting the old behavior — and autoUpdate: true on the marketplace carries the code change to every machine while the prose stays exactly where it was.
So a consumer's permission configuration is verified as of a commit and has no mechanism to stay verified. That is the opposite of how the rest of this repo treats its contracts: test_skill_contract.py exists precisely because prose about behavior rots.
What would fix it
Not another documentation pass. Something that fails when the semantics change. Rough shapes, unranked:
- A machine-readable capability manifest per lane script — mutating vs read-only, which flags gate which guard, which entry point carries a refusal the other does not — emitted from the code (argparse introspection gets most of it) and asserted by a test.
- A contract test that pins the specific guard predicates a consumer is told to rely on, so changing line 189's condition fails CI with a message naming the downstream claim.
- A documented "what a permission rule may assume" section with a stability commitment, so consumers cite a contract rather than reverse-engineering the source. Weakest of the three — still prose — but it puts the burden in one reviewable place.
Option 1 has a second payoff: /source-control:setup's new lane-script reachability probe (#787, PR #1264) currently has to name the plugin's scripts from prose too. A manifest would let it enumerate them instead.
Context
Problem
A consumer configuring a host permission classifier for this plugin's lane has to restate, in prose, facts that actually live in this repository's code. Four rounds of independent review on
melodic-software/dotfiles#315produced a wrong statement about one of these three separate times, and each time the only thing that caught it was a human or agent reading both the prose and the source side by side.The facts being restated, with where they really live:
babysit_resolve_thread.pyenforces bot-only at line 189 iff--include-humanis absent, and theisOutdatedcheck at 193 iff--autonomousor--only-outdated. The pin chain at 325 → 345 → 362 is what makes--autonomousmean "single pinned thread" rather than "bulk". A consumer's permission rule that says "resolves only outdated bot threads" is true only for a specific flag combination.bin/source-control-babysit-mergerefuses--allow-unpinned-headin bash;babysit_merge.pyaccepts it as an ordinary argparse flag. Whether an invocation is safe depends on which of the two you called, and nothing in the Python says so.request_review.py --applyposts a comment,prune_babysit_worktrees.py --applyrunsgit worktree remove, the lease and ledger helpers write state. A consumer that classifies these as read-only is wrong, and the scripts' names do not say which is which.refresh_pr_branch.pyrequests GitHub's server-sideupdate-branchendpoint rather than pushing — safer than it reads, but a consumer reasoning about push guards will reason about the wrong mechanism.Why it drifts silently
Nothing connects the two. If a flag is added, if the merge wrapper's refusal moves into Python, if a helper starts mutating, the consumer's prose keeps asserting the old behavior — and
autoUpdate: trueon the marketplace carries the code change to every machine while the prose stays exactly where it was.So a consumer's permission configuration is verified as of a commit and has no mechanism to stay verified. That is the opposite of how the rest of this repo treats its contracts:
test_skill_contract.pyexists precisely because prose about behavior rots.What would fix it
Not another documentation pass. Something that fails when the semantics change. Rough shapes, unranked:
Option 1 has a second payoff:
/source-control:setup's new lane-script reachability probe (#787, PR #1264) currently has to name the plugin's scripts from prose too. A manifest would let it enumerate them instead.Context
melodic-software/dotfiles#315is the consumer configuration that surfaced this. Its audit trail has the specific instances.isOutdateda weak signal — itself a guard semantics fact consumers restate).