Skip to content

Guard semantics the lane's consumers restate in prose have no drift detection #1265

Description

@kyle-sexton

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:

  1. 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.
  2. 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.
  3. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.priority: mediumReal value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.work-class: structuralRefactors, migrations, contract changes; cross-cutting and hard to reverse.

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions