fix(acr): honest absence-state copy for two GAP enhancement findings (M-BUG-15)

The t2_3 ("No path-scoped rules") and t3_6 ("No subagent isolation")
feature-gap checks iterate a collection (rule files / agent files) and return
false for an EMPTY one — so they fire even when the user has zero rules / zero
subagents, the same state their presence-gap siblings flag. But the humanized
titles presupposed the feature already exists:
  - "Your rules all load on every conversation" (with zero rules)
  - "Your subagents share Claude's main work folder" (with zero subagents)
The second directly contradicts GAP-005 "You haven't set up any specialized
helper agents yet" in the same report — a user cannot simultaneously have no
subagents and have subagents that lack isolation. Found by dogfooding the
analyze pipeline against linkedin-posts (premise-verifying each finding before
trusting the analyzer-agent's report).

Decided fix = align the two titles with the house "You haven't set up X yet"
absence framing (state-neutral: honest for both the zero-state and the
has-but-unconfigured state), NOT a base-feature presence gate in the scanner —
that would change the frozen v5.0.0 marketplace-medium baseline (zero
rules/agents, freezes these gaps firing) and break the RAW byte contract.
Mirrors M-BUG-14's humanizer-layer, copy-only approach.

- humanizer-data.mjs: title "Your rules all load on every conversation" ->
  "You haven't set up path-scoped rules yet"; title "Your subagents share
  Claude's main work folder" -> "You haven't set up subagent isolation yet".
  description + recommendation unchanged. t3_5/t3_7 ("Your skills don't ...")
  left as-is: their possessive is correct in the common case where skills
  exist; the zero-skills edge is latent, not manifest here.
- RED-first unit test pins both titles existence-neutral (forbids "your rules
  all load" / "your subagents"; feature still named).

Frozen v5.0.0 snapshots untouched (RAW bypasses humanizer); default-output
snapshot regenerated (2 titles only, no collateral). Verified on linkedin-posts:
GAP-004/005/011 now all consistently absence-framed. Suite 1356->1357/0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01683eAqVecv9VZfQzL8CQ9h
This commit is contained in:
Kjell Tore Guttormsen 2026-06-30 12:57:40 +02:00
commit 2975b0563f
3 changed files with 28 additions and 4 deletions

View file

@ -440,7 +440,7 @@ export const TRANSLATIONS = {
recommendation: 'Break out long sections into separate files and link them with `@import`.',
},
'No path-scoped rules': {
title: 'Your rules all load on every conversation',
title: 'You haven\'t set up path-scoped rules yet',
description: 'Path-scoped rules only load when you\'re working with files that match — keeps each conversation focused.',
recommendation: 'Add scoping to your rules so they only load for the files they apply to.',
},
@ -490,7 +490,7 @@ export const TRANSLATIONS = {
recommendation: 'Add fields like `model`, `tools`, or `description` to your skill files where useful.',
},
'No subagent isolation': {
title: 'Your subagents share Claude\'s main work folder',
title: 'You haven\'t set up subagent isolation yet',
description: 'Isolated subagents run in their own copy of the repo so they can\'t accidentally disturb your main work.',
recommendation: 'Add `isolation: worktree` to subagents that do destructive or experimental work.',
},

View file

@ -179,6 +179,30 @@ test('GAP "CLAUDE.md not modular" copy is size-neutral (M-BUG-14)', () => {
assert.ok(/split/.test(desc), `description should keep structural split framing: "${t.description}"`);
});
test('GAP enhancement-gap titles do not presuppose the feature exists (M-BUG-15)', () => {
// t2_3 ("No path-scoped rules") and t3_6 ("No subagent isolation") iterate a
// collection and return false for an EMPTY one — so they fire even when the
// user has zero rules / zero subagents. The humanized title must therefore
// not assert the feature exists, or it contradicts the sibling presence gap
// ("No custom subagents" → "You haven't set up any specialized helper agents
// yet"). Mirror the house "You haven't set up X yet" framing — honest for
// both the zero-state and the has-but-unconfigured state.
const rules = TRANSLATIONS.GAP.static['No path-scoped rules'];
const iso = TRANSLATIONS.GAP.static['No subagent isolation'];
assert.ok(rules, 'GAP static map missing "No path-scoped rules"');
assert.ok(iso, 'GAP static map missing "No subagent isolation"');
// Title must not presuppose existing rules / subagents.
assert.ok(!/your rules all load/i.test(rules.title),
`t2_3 title presupposes existing rules: "${rules.title}"`);
assert.ok(!/your subagents/i.test(iso.title),
`t3_6 title presupposes existing subagents: "${iso.title}"`);
// Title must still name the feature it points at.
assert.ok(/path-scoped rules/i.test(rules.title),
`t2_3 title should still name path-scoped rules: "${rules.title}"`);
assert.ok(/isolation/i.test(iso.title),
`t3_6 title should still name subagent isolation: "${iso.title}"`);
});
test('CNF, COL, PLH have at least one pattern entry (template-literal titles)', () => {
// These scanners use template-literal titles for some findings.
for (const prefix of ['CNF', 'COL', 'PLH']) {

View file

@ -165,7 +165,7 @@
"id": "CA-GAP-003",
"scanner": "GAP",
"severity": "low",
"title": "Your rules all load on every conversation",
"title": "You haven't set up path-scoped rules yet",
"description": "Path-scoped rules only load when you're working with files that match — keeps each conversation focused.",
"file": null,
"line": null,
@ -309,7 +309,7 @@
"id": "CA-GAP-012",
"scanner": "GAP",
"severity": "info",
"title": "Your subagents share Claude's main work folder",
"title": "You haven't set up subagent isolation yet",
"description": "Isolated subagents run in their own copy of the repo so they can't accidentally disturb your main work.",
"file": null,
"line": null,