Skip to content

fix(claude-config): audit-prompting-postures' contract disagrees with itself in eight places #2281

Description

@kyle-sexton

Eight residual gaps in claude-config:audit-prompting-postures, all of one kind: the skill's own
contract does not line up with itself. What it inventories does not cover where a posture's presence
evidence lives; the verdict vocabulary it publishes excludes two tokens its own body mandates; the
surface set it inherits is wider than the scope filter that names surfaces; the fetch-set predicate has
two incompatible readings; a catalog row omits the model condition the skill's own gotcha demands; the
report-only contract is enforced by model obedience where the frontmatter offers a mechanical lever;
routing is one-way with nothing testing auto-discovery; and the sole durable artifact still sits in a
directory an uninstall reaps.

None of these is a wrong or unsafe action on its own. Together they are a coherence pass a maintainer
would do in one sitting.

Rows

  • CC-F3reference/postures.md:73-79 vs SKILL.md:51-53 — P7 accepts "a deny-by-default hook or script gate" as presence evidence, but Phase B inventories instruction text only: settings.json permissions.deny and hook scripts are outside the set. Related: destructive-capable is defined in capability terms (postures.md:19) while classification is stated in purpose terms (postures.md:13).
  • CC-F5SKILL.md:43, :76, :151-152wording-unverified (Phase A) and info (Phase D) have no home in the published three-verdict schema, and there is no abort threshold if the best-practices page is unreachable.
  • CC-F6SKILL.md:3 vs audit-instructions/SKILL.md:3, :83 — the surface set is inherited by reference from a sibling that versions independently, and the two have already diverged: output-styles is inventoried and unnameable by this skill's filter.
  • CC-F10SKILL.md:40-43 — "Before judging anything … a model-specific subpage only when a posture row names it" is statically true of a subpage P1's row names, so a literal reading requires fetching it every run; the efficient reading defers part of Phase A past Phase C.
  • CC-F7reference/postures.md:81-87 vs SKILL.md:163-165 — P8's row carries no model condition, though the skill's own gotcha requires model-conditional postures to stay conditional and the guide section P8 points at is model-scoped.
  • CC-F4SKILL.md:1-9, contract at :169 — "Never edits a component and never auto-applies a proposal" is enforced entirely by model obedience; the frontmatter declares no disallowed-tools.
  • CC-F8audit-instructions/SKILL.md (zero occurrences of this skill's name) and evals/evals.json — routing is one-way, and with disable-model-invocation: false no eval exercises description-driven selection.
  • CC-F11 — informational — uninstalling from the last remaining scope deletes ${CLAUDE_PLUGIN_DATA}, which holds the sole copy of the audit artifact; the description measures 1,290 of the 1,536-char cap and when_to_use is unused.

Evidence

CC-F3 — presence evidence lives outside the inventory

reference/postures.md:73-79 at HEAD:

### P7 — Destructive-action confirmation

- **Predicate:** destructive-capable.
- **Present when:** hard-to-reverse, shared-system, or destructive actions require confirmation or
  an equivalent mechanical gate, and obstacles must not be shortcut destructively. A deny-by-
  default hook or script gate satisfies this without any prose.

SKILL.md:51-53 — what Phase B actually enumerates:

Enumerate locally-owned instruction components in scope (same surface set and liveness rules as
`audit-instructions` Phase A — resolve `${CLAUDE_CONFIG_DIR:-~/.claude}`, project `.claude/`,
CLAUDE.md files, hook instruction text of both kinds).

Hook instruction text, not hook scripts, and no settings file. So the one form of presence evidence
P7 explicitly blesses is the one form Phase B cannot see — producing false MISSING findings on the
posture where a false positive is most expensive.

The classification half: postures.md:19 defines destructive-capable as "can delete, reset,
force-push, publish, or mutate shared state", while postures.md:13 frames classification as "what its
body has the model DO". Read literally, can … matches every component with Bash access; the only
thing narrowing it is the do-not-manufacture fence at SKILL.md:66-67, in a different file from the
predicate.

CC-F5 — two mandated tokens outside the published vocabulary, and no abort threshold

SKILL.md:43 → "wording-unverified and cite the pointer rather than inventing text."
SKILL.md:76 → "Findings a verifier refutes are dropped or demoted to info."
SKILL.md:151-152 — the published schema:

Verdicts: `MISSING` (finding, with proposed addition as a fenced diff), `PRESENT` (where it is),
`NOT-APPLICABLE` (with the failed predicate).

Neither wording-unverified nor info has a home there. The fifth report column is headed "Proposed
addition" but sometimes carries a URL. And if the best-practices page is unreachable every posture
degrades at once with nothing telling the run to stop — a fail-open on the skill's single
non-negotiable input. The sibling demonstrates the alternative:
plugins/claude-config/skills/audit-instructions/SKILL.md:106 → "Normalization MUST stop in that case
by ABORTING the run with an error that names the exact…".

(The unreachable-fetch case was never induced; this row is text-coherence analysis, not observed
behavior.)

CC-F6 — the inherited surface set has already diverged

plugins/claude-config/skills/audit-prompting-postures/SKILL.md:3:

argument-hint: "[scope] — scope: skills|agents|hooks|claude-md|rules|all (default: all)"

plugins/claude-config/skills/audit-instructions/SKILL.md:3:

argument-hint: "[scope] [--target-model <version>] [--opinion] [--no-stopping-condition] — scope: claude-md|rules|skills|agents|hooks|output-styles|conflicts|all (default: all)"

and audit-instructions/SKILL.md:83 → "output-styles — findings on output-style markdown". This
skill's own description (SKILL.md:2) lists "skill bodies, agent definitions, hook instruction text,
CLAUDE.md, rules" with output styles absent. So a whole surface class is inventoried by inheritance and
unnameable by the filter — and the coupling guarantees it drifts again.

CC-F10 — the fetch-set predicate has two readings

SKILL.md:40-43:

It deliberately carries no copied sample text. Before judging anything, WebFetch the pages the
catalog names (the best-practices page always; a model-specific subpage only when a posture row
names it) and hold the current wording.

"Before judging anything" and "when a posture row names it" conflict with the efficient reading (fetch
only what an applicable row needs), which requires deferring part of Phase A past Phase C. The
observed run took the efficient reading, which is the sensible one — the wording should say so.

CC-F7 — a catalog row that violates the skill's own gotcha

reference/postures.md:81-87:

### P8 — Context-budget reassurance

- **Predicate:** context-surfacing.
- **Present when:** the surfaced figure is accompanied by do-not-wrap-up-early framing (or the
  component deliberately avoids surfacing raw countdowns at all — the stronger form).
- **Pointer:** main page, "Context awareness and multiwindow workflows"; Fable 5 subpage, "Rare
  cases of context-budget concern".

No model condition on the row. The gotcha it violates, SKILL.md:163-165:

- **Model-conditional postures stay conditional.** Where the guide ties a posture to specific
  models, the proposal must be model-neutral or carry the same condition — components here run on
  any consumer model.

One leg is unconfirmed by the validation pass and should be re-checked before the fix: the model
list the pointed-at guide section carries ("Claude Sonnet 5, Claude Sonnet 4.6, Claude Sonnet 4.5, and
Claude Haiku 4.5 feature context awareness…") lives on platform.claude.com, not code.claude.com; it
was fetched by the auditor on 2026-08-11 and not re-fetched. The structural half — the row carries no
condition while the gotcha requires one — does not depend on it.

CC-F4 — a prose-only read-only contract

SKILL.md:1-9 frontmatter carries description, argument-hint, user-invocable,
disable-model-invocation, metadata and no disallowed-tools key. The contract it would enforce
is SKILL.md:169 → "Never edits a component and never auto-applies a proposal."

The nuance the fix must keep: a blanket disallowed-tools: Write would break the mandated persist at
SKILL.md:78-79, so only Edit/NotebookEdit are free. One doc leg is auditor-confirmed rather
than verifier-confirmed
: the frontmatter reference's disallowed-tools semantics, including its
"the restriction clears when you send your next message" clause, was fetched 2026-08-11 by the auditor
and not independently re-fetched. Re-fetch before relying on that clause.

This is one line and mechanical; the observed behavior held (every audited file retained its pre-audit
mtime), so this is an absent guarantee rather than an observed violation.

CC-F8 — one-way routing, untested selection

grep -c "audit-prompting-postures" plugins/claude-config/skills/audit-instructions/SKILL.md0.
The token appears nowhere in the sibling, not merely absent from its description. This skill's
evals/evals.json carries 5 cases at HEAD (three original plus the two #2259 added), and every one
of them invokes /claude-config:audit-prompting-postures explicitly. SKILL.md:5 is
disable-model-invocation: false, so the description drives auto-discovery and nothing tests it. (The
"description drives auto-discovery" claim rests on the skills page, auditor-fetched 2026-08-11 and not
re-fetched; the two grep facts stand independently.)

CC-F11 — informational

Uninstalling from the last remaining scope deletes ${CLAUDE_PLUGIN_DATA} by default (--keep-data
preserves it), and that directory holds the sole copy of the audit artifact — so it remains an
amplifier even now that #2250 has keyed the path per project. The description at SKILL.md:2
measures 1,290 characters against the documented 1,536 cap (re-measured at this HEAD — unchanged by
#2259, which edited the body only; the item's 1,295 was the 0.29.0 figure), and when_to_use is unused. (The uninstall sentence was fetched from
the plugins reference by two independent auditors on 2026-08-11 and not re-fetched by the validation
pass.)

Not in this issue, on purpose

Provenance

Severity: MED (cluster highest; CC-F7, CC-F8, CC-F10, CC-F11 are LOW) · Provenance: AUDITOR_VERIFIED, with three legs marked unverified by the validation pass inline: the P8 model list on platform.claude.com (CC-F7), the disallowed-tools frontmatter sentence (CC-F4), and the description-drives-auto-discovery claim (CC-F8). Every file:line and quoted line was independently re-verified against HEAD.
Origin: handoff-inbox item 20260811-021645-plugin-audit-four-components-and-guard-deadlock-ownership
Ledger: .work/handoff-inbox-batch-4/ledgers/I9-021645-four-components.md § Lane A (CC-F3 … CC-F11)
Verified against repo HEAD 9b34a82a. Every anchor past SKILL.md:78 was re-derived — #2259 added 67 lines there. Severities are the verifier's re-grades, not the original auditor's.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions