feat(boatstack): repeated denials escalate their solutions, never their severity - #228
Merged
Conversation
…ir severity An agent that hits the same guardrail repeatedly is signalling that the stated law is not reaching it, and under that pressure agents drift toward worse moves. The guard now keeps a bounded per-worktree denial ledger (.git/boatstack/guard/denials.json, declared in the state-ownership map, guard-protected like all runtime state). From the third identical denial (category at stage) the rendering escalates its corrective information: the pick list lifts from three commands to the full legal set and the denial prescribes a fresh diagnostic (boatstack-helper doctor) — the fresh-probe discipline. Admissibility never changes: what was denied stays denied, and the constitutional corpus floor is untouched. Any ALLOWED mutation-capable call is forward progress and clears the ledger, so a stale streak never escalates an unrelated denial; read-only allows do not reset. Bookkeeping is fail-calm end to end: a corrupt or unwritable ledger degrades to the unescalated rendering — a denial never becomes a crash or an allow because bookkeeping failed. Conformance (denial_escalation_conformance_test.go): third-identical escalates end to end through HookDecision, allowed-mutation reset, key isolation (category and stage), corrupt-ledger and unresolvable-repo degradation, ledger bound, and escalation-lifts-cap-not-severity. The statemap gains the guard-denial-ledger entry + GuardDir resolver, held by the existing ownership conformance and mirrored in artifacts.md. control-law: repeated-denials-escalate-to-solutions Disclosure-Reviewed: reviewed — public-safe only, private facet kept out of this commit
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.
What
Builds on #226/#227. An agent that hits the same guardrail repeatedly is signalling that the stated law is not reaching it — and under that pressure agents drift toward worse moves, not better ones (observed live: sixteen identical no-progress repair attempts ending in a protected-boundary write attempt). The guard now keeps a bounded per-worktree denial ledger; from the third identical denial (same category at the same stage) the message escalates its corrective information: the
You can:pick list lifts from 3 commands to the full legal set, and the denial prescribes a fresh diagnostic (boatstack-helper doctor) — the fresh-probe discipline. Structured payload gainsescalated+repeat_count.How
denial_ledger.go:.git/boatstack/guard/denials.json— keyed(category, workflow_stage), bounded (≤32 keys, oldest pruned), fail-calm end to end (corrupt/unwritable ledger ⇒ unescalated rendering; a denial never becomes a crash or an allow because bookkeeping failed).safety.go:HookDecisionbumps the ledger on every deny and resets it on any allowed mutation-capable call (forward progress; read-only allows do not reset).SafetyFinding.RepeatCountcarries the count to the renderer.denial.go: escalation lifts the pick cap and appends the repeat notice in all three render modes.statemap.go/paths.go: newguard-denial-ledgerentry (runtime-worktree, per-worktree, gitignored, guard-protected — already inside thedeliveryStatePathPatterndeny set) +GuardDir()resolver; mirrored inreferences/artifacts.mdand held by the existing ownership conformance.Boundary conformance
.git/boatstack/guard/).repeated-denials-escalate-to-solutions.safety-hook/ambient-safety-hook); raw mutation of the ledger is guard-denied like all.git/boatstackstate.denial_escalation_conformance_test.go— third-identical escalates end to end throughHookDecision; allowed-mutation reset; key isolation (category and stage); corrupt-ledger and unresolvable-repo degradation; ledger bound; escalation-lifts-cap-not-severity (option SET identical, severity identical). Statemap conformance green with the new entry; ownership doc mirror updated.Verification
go build ./... && go vet ./...clean; fullgo test ./...green across all three packages.2026-07-27-repeated-denials-escalate.md; preflight passes.