feat(agent-audit): implement ADR-0016's reserved SUGGESTION for unenforceable tool-restriction claims #126
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found during the #99 ADR-0020 retrofit and the follow-up audit pass on
refactor/adr0020-skill-retrofit. Not fixed there — it is new gate behaviour ADR-0016 already reserved and explicitly deferred, not a defect introduced by the retrofit.What the ADR reserved
docs/adr/0016-apm-agent-primitive-drops-provider-specific-fields.md:50, verbatim:Still accurate. Reading
check_apm_agent_file()atplugins/kyberforge/.apm/skills/agent-audit/scripts/validate.sh:1391in the working tree, the function checks: unreadable file, unparsable frontmatter, leftover template HTML comments, the field allowlist,name(present / kebab-case / matches filename stem),description(present / no placeholder / ADR-0020 budget / boundary clause), and body (non-empty / no placeholder / Copilot truncation limit). No heuristic for prose-asserted tool restriction.The SUGGESTION tier itself is already wired —
suggest()is used in the same function for the Copilot body-length case — so this is a new check on existing machinery, not new plumbing.The concrete instance
plugins/kyberforge/.apm/agents/apm-orchestrate.agent.mdpromises, in its Hard rules:Its frontmatter carries
disallowedTools: Edit, Write, NotebookEdit, which is the maximum ADR-0016 permits: the 2026-08-14 amendment readmits the denylist and keeps the allowlist-shapedtools:excluded, because Claude Code and Copilot readtools:from incompatible vocabularies. An absenttools:means inherit-all on both harnesses.So
Bashremains available — and the agent's own Process step 4 requires it (Confirmapm --versionsucceeds before dispatching any operation). A heredoc, a>redirect, orapm compilewrites files. The guarantee in that Hard rule holds by prose only. Nothing in the frontmatter enforces it and nothing can, which is precisely the visibility gap the ADR reserved a SUGGESTION for.What implementing it would surface today
Three of the four plugin-scope agents, all carrying the same shape — an explicit never-writes promise plus
disallowedTools: Edit, Write, NotebookEdit:kyberforge/apm-orchestrategitea/gitea-orchestratelint/lint-runnergit/git-orchestratewould not be surfaced, and correctly so: it carries nodisallowedToolsand no never-writes claim. Its "you do not execute git logic yourself, you delegate to domain skills" is a routing statement, not a tool-restriction claim.That distribution is a useful property for calibration — a heuristic that fires on all four is too loose.
Design note
The cheapest defensible heuristic is the conjunction, not either half alone: an agent that both (a) makes a never-writes / read-only claim in description or body, and (b) has no way to enforce it — either
disallowedToolsis absent, or it is present butBash(unrestricted) remains, which under ADR-0016 it always does. Firing on (a) alone would flag correct authoring; firing on (b) alone would flag every agent in the repo.The ADR's wording is broader than tool restriction ("or a Claude-only behavior the frontmatter can no longer express"). That second half has no live instance in the corpus right now and can be deferred; the tool-restriction half has three.
Files
plugins/kyberforge/.apm/skills/agent-audit/scripts/validate.sh:1391—check_apm_agent_file()docs/adr/0016-apm-agent-primitive-drops-provider-specific-fields.md:50— the reservation, and the 2026-08-14 amendment that fixesdisallowedToolsas the ceilingplugins/{kyberforge,gitea,lint}/.apm/agents/*.agent.md— the three instancesRelated
apm-orchestratefindings from this passWont fix, not a significant enough issue