feat(l4): add l4.measurement-backed — the autonomy-without-guardrails check - #48
Open
sroberts wants to merge 1 commit into
Open
feat(l4): add l4.measurement-backed — the autonomy-without-guardrails check#48sroberts wants to merge 1 commit into
sroberts wants to merge 1 commit into
Conversation
… check The second of the two anti-patterns CLAUDE.md says the assessor should flag. The L3 one got a detector in #44; this is its counterpart. Modelled the same way, for the same reason: it asks the positive question — is the autonomy in this repo backed by a gate that can stop it? — and returns Missing for the anti-pattern. Found keeps meaning good across the catalog and level math needs no inverted case. NA when there is no repo-modifying automation, which excludes it from the level average. The paper's claim is that levels are sequential: L4 without L3 is not most of the way to L4, it is a machine committing to a codebase nothing is checking. Asked in the form a static scan can answer: does automation that mutates the repo or its tracker (create-pull-request, git push, gh pr merge, gh issue create, automerge actions) coexist with a push/PR-triggered workflow containing something that can fail? Scheduled workflows deliberately do not count as guardrails. A nightly suite reports; it does not block a merge. Counting one would pass exactly the repos this signal exists to catch, so there is a test pinning that. Limits ship in the result notes, not just SPEC.md: a pass means a blocking gate exists in the same repo as the autonomy. It does not establish that the gate covers the code path the automation touches, or that branch protection requires the check — branch protection is repo configuration, not filesystem state, and plumbline does not read it. The skill-body drift test added in #44 caught the stale signal list on the first full run, without being prompted. That is the second thing it has caught, both times before review. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XtNwLDzRYmPrXcYeQypTf9
There was a problem hiding this comment.
Pull request overview
Adds a new Level 4 (“Adaptive”) signal to Plumbline’s ACMM catalog to detect the autonomy-without-guardrails anti-pattern by checking whether repo-modifying automation is accompanied by a push/PR-triggered workflow that can fail (scheduled workflows explicitly don’t count as guardrails).
Changes:
- Introduces
l4.measurement-backeddetector (internal/signals/l4/measurement_backed.go) and registers it in the default signal set. - Adds unit tests covering NA / Missing / Found behavior and the “scheduled suites don’t count” rule.
- Updates the signal catalog documentation and the embedded skill “stable contracts” list to include the new signal.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| SPEC.md | Documents the new L4 signal and its intended semantics/limits in the catalog spec. |
| internal/skill/skill.go | Adds measurement-backed to the stable list of L4 signal IDs. |
| internal/signals/l4/measurement_backed.go | Implements the new detector and registration. |
| internal/signals/l4/l4_test.go | Adds test coverage for the new detector, including the scheduled-guardrail exclusion. |
| docs/SIGNALS.md | Regenerates the signal catalog docs to include the new signal and updated count. |
| .plumbline.toon | Regenerates the repo’s snapshot output to include the new signal and updated L4 score. |
Suppressed comments (1)
internal/signals/l4/measurement_backed.go:38
gateUsesREcurrently treatscodecovand anysonarsourceaction as a blocking gate, but these are often metric publishers/scanners that don’t necessarily fail a PR/push. This can produce falseFoundresults for “guardrails” when the workflow only uploads/reports. Consider restricting this to actions that are clearly used as failing lint/analysis gates (similar tol3.build-lint-gate’s action vocabulary).
gateRunRE = regexp.MustCompile(`(?m)(exit\s+1|::error::|go\s+test|pytest|npm\s+(run\s+)?test|cargo\s+test|--fail)`)
gateUsesRE = regexp.MustCompile(`(?i)(golangci|staticcheck|codecov|sonarsource|reviewdog)`)
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+32
to
+34
| autonomyUsesRE = regexp.MustCompile(`(?i)(peter-evans/create-pull-request|peter-evans/enable-pull-request-automerge|pascalgn/automerge-action|actions/github-script)`) | ||
| autonomyRunRE = regexp.MustCompile(`(?m)(git\s+push|gh\s+pr\s+(merge|create)|gh\s+issue\s+(create|close|edit)|--auto\b)`) | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The second of the two anti-patterns
CLAUDE.mdsays the assessor should flag. The L3 one — the dashboard graveyard — gotl3.metrics-acted-onin #44. This is its counterpart, and it completes the pair.Design: same inversion as the L3 one
Status: Foundmeans "present" everywhere in the catalog, so a detector that fires on something bad would raise the level score by finding it. This asks the positive question — is the autonomy in this repo backed by a gate that can stop it? — and returnsMissingfor the anti-pattern.NAwhen there's no repo-modifying automation, which excludes it from the level average per §7.Detection
The paper's claim is that levels are sequential: L4 without L3 isn't "most of the way to L4", it's a machine committing to a codebase nothing is checking. Asked in the form a static scan can answer:
create-pull-request, an automerge action,github-script, or runninggit push/gh pr merge/gh issue create.push/pull_request-triggered workflow containing something that can fail:exit 1,::error::, a test runner, a linter action.Autonomy with no guardrail →
Missing. Both →Found. No autonomy →NA.Scheduled workflows deliberately don't count as guardrails. A nightly suite reports; it doesn't block a merge. Counting one would pass exactly the repos this signal exists to catch — automation running against a codebase whose only checks happen after the fact. There's a test pinning that behaviour, because it's the kind of thing a later "improvement" would quietly relax.
What a pass does not mean
Both caveats ship in the result's
notes, not just in SPEC.md, since the notes are what someone reads when they see a green result:Worth stating plainly given this repo's own history:
mainhere has no branch protection at all, so every gate inci.ymlis advisory. This signal still returnsFoundfor plumbline — correctly by its rule, and incompletely by any stricter reading. Confidence is capped at medium for exactly this reason.The drift gate earned its keep
The skill-body test from #44 failed on the first full run of this branch, unprompted:
Second thing it's caught, both times before review.
Effect on plumbline's own score
L4 goes 0.8 → 0.833; verdict stays level 5.
docs/SIGNALS.mdand.plumbline.toonregenerated (signals[23]). Full suite,go vet,gofmtclean.🤖 Generated with Claude Code
https://claude.ai/code/session_01XtNwLDzRYmPrXcYeQypTf9