fix(ultraplan-local): v2.3.2 — skill-drafter slug-collision hint
skill-drafter now reads {catalog_root}/<slug>.md before writing its
draft and prepends a warning block to its confirmation output when
an existing skill would be overwritten during manual `mv` promotion.
The draft is still written to .drafts/<slug>.md — the check is a
hint, not a block.
Closes v2.3.0 dogfood finding (post_dogfood_findings[0]): the
drafter produced .drafts/hooks-pattern.md when an approved
hooks-pattern.md seed already existed, giving no signal that `mv`
during promotion would silently overwrite the seed. v2.3.1
introduced the qualified-slug mechanism to resolve such collisions;
v2.3.2 surfaces them at the right moment — before promotion.
Changes:
- agents/skill-drafter.md — new Step 2 between slug computation and
source reading. Reads {catalog_root}/<slug>.md, inspects
review_status, derives a kebab-case qualifier from the concept
handle (or source basename fallback). Subsequent steps renumbered
3→7. Output format gains Collision: field and optional warning
block. New Hard Rule.
- tests/fixtures/skill-drafter/slug-collision-expected.md — reference
fixture documenting expected confirmation shape across four
scenarios (no collision, approved collision, soft pending
collision, collision with no good qualifier). Skill-drafter is
prompt-driven; fixture anchors shape for human verification and
downstream parsers.
- CHANGELOG [2.3.2], plugin.json 2.3.1→2.3.2, README badge, plugin
CLAUDE.md slug-convention Collision-hint bullet, marketplace root
README summary, marketplace root CLAUDE.md plugin table.
Non-breaking. No frontmatter/drafts-layout/tool-scope/regex changes.
Existing pipelines see one extra field and an optional warning —
both purely additive.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
4bbd17cbfa
commit
efbb43094f
8 changed files with 276 additions and 11 deletions
|
|
@ -54,13 +54,48 @@ message — do not write a file with an invalid name.
|
|||
|
||||
The draft file path is `{catalog_root}/.drafts/<slug>.md`.
|
||||
|
||||
### 2. Read the source
|
||||
### 2. Check for slug collision at the catalog root
|
||||
|
||||
Before proceeding, attempt to `Read` `{catalog_root}/<slug>.md` (the
|
||||
approved location, NOT the draft location).
|
||||
|
||||
- If the read fails because the file does not exist → no collision.
|
||||
Proceed to Step 3. Record `collision: false` for the summary.
|
||||
- If the read succeeds → inspect the frontmatter for `review_status`.
|
||||
- `review_status: approved` → **collision**. Record it and derive a
|
||||
suggested qualified slug (see "Suggesting a qualifier" below).
|
||||
- `review_status: pending` or `auto-merged` → **soft collision**.
|
||||
Still record and surface it, but the existing file is not a
|
||||
guaranteed baseline; the human reviewer can decide.
|
||||
- Missing or malformed frontmatter → treat as soft collision. Note
|
||||
it in the summary so the reviewer can inspect.
|
||||
|
||||
**Do not block** on any of these outcomes. The draft is still
|
||||
written to `.drafts/<slug>.md` in Step 7. The collision check exists
|
||||
to surface the overwrite risk in your confirmation output so the
|
||||
user sees it before running `mv` during manual promotion.
|
||||
|
||||
**Suggesting a qualifier.** Pick a short, descriptive kebab-case
|
||||
word from the `concept` field (3–6 word handle from
|
||||
`concept-extractor`). Strip stopwords like "the", "a", "and". Prefer
|
||||
the most specific noun or named pattern in the handle. If the
|
||||
concept is generic and no good qualifier emerges, fall back to the
|
||||
source basename (e.g., `docs/hooks-recipes.md` → `recipes`).
|
||||
|
||||
The suggested qualified slug is
|
||||
`<cc_feature>-<qualifier>-<layer>.md`. Validate it against the
|
||||
filename regex just like Step 1. If the suggestion collides with
|
||||
another existing skill (approved or pending), try the next candidate
|
||||
qualifier from the concept handle. If no candidate is collision-free,
|
||||
report `suggested_slug: none — reviewer must pick`.
|
||||
|
||||
### 3. Read the source
|
||||
|
||||
Read the source file in full. Extract the load-bearing ideas that map
|
||||
to the concept handle. You are not summarizing the source verbatim —
|
||||
you are reframing it as catalog skill content.
|
||||
|
||||
### 3. Compose the frontmatter
|
||||
### 4. Compose the frontmatter
|
||||
|
||||
The frontmatter MUST have exactly these 9 fields, in this order, with
|
||||
exactly these values:
|
||||
|
|
@ -85,7 +120,7 @@ not 0). `review_status` MUST be `pending` (not `approved`, not
|
|||
populates `ngram_overlap_score`; the human reviewer in promotion
|
||||
flips `review_status`.
|
||||
|
||||
### 4. Compose the body
|
||||
### 5. Compose the body
|
||||
|
||||
The body is 150 to 600 words. Use progressive disclosure: short
|
||||
headings, bullet notes, no long prose paragraphs. Imperative voice,
|
||||
|
|
@ -115,7 +150,7 @@ For `layer: pattern`, structure as:
|
|||
Each section gets 2–4 short bullets or one short paragraph. Skip
|
||||
sections that have no content rather than padding them.
|
||||
|
||||
### 5. Rephrase — do not copy
|
||||
### 6. Rephrase — do not copy
|
||||
|
||||
You MUST NOT copy verbatim phrases from the source. Rephrase every
|
||||
sentence in your own words. The downstream `ip-hygiene-checker` runs
|
||||
|
|
@ -130,7 +165,7 @@ a fixed YAML schema), do not draft it. Stop and emit a short
|
|||
escalate. Better to skip than to ship a draft that will fail
|
||||
hygiene.
|
||||
|
||||
### 6. Write the file
|
||||
### 7. Write the file
|
||||
|
||||
Use the `Write` tool to create the draft at
|
||||
`{catalog_root}/.drafts/<slug>.md`. Overwrite if it exists — the
|
||||
|
|
@ -147,9 +182,30 @@ After writing the file, return a short confirmation:
|
|||
Drafted: <full path to .drafts/<slug>.md>
|
||||
Word count: <body word count>
|
||||
Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null
|
||||
Collision: <none | approved | pending | auto-merged | soft>
|
||||
Next: ip-hygiene-checker for IP scoring
|
||||
```
|
||||
|
||||
If Step 2 detected a collision at `{catalog_root}/<slug>.md`, prepend
|
||||
a warning block to the confirmation:
|
||||
|
||||
```
|
||||
⚠️ Slug collision at catalog root
|
||||
Existing: {catalog_root}/<slug>.md (review_status=<status>)
|
||||
Draft: {catalog_root}/.drafts/<slug>.md (this run)
|
||||
Risk: manual `mv` during promotion will silently overwrite the existing file.
|
||||
Suggested qualified slug: <cc_feature>-<qualifier>-<layer>.md
|
||||
Reason for qualifier: <one short sentence citing the concept handle>
|
||||
Action: rename the draft before `mv`, or revise the existing baseline.
|
||||
```
|
||||
|
||||
If no collision-free qualifier could be derived, replace the
|
||||
"Suggested qualified slug" line with:
|
||||
|
||||
```
|
||||
Suggested qualified slug: none — reviewer must pick one manually.
|
||||
```
|
||||
|
||||
If you stopped because of `too-technical-to-paraphrase`, return:
|
||||
|
||||
```
|
||||
|
|
@ -180,6 +236,11 @@ No file written.
|
|||
copied draft is wasted work.
|
||||
- **`.drafts/` only.** Never write to the catalog root. Promotion is
|
||||
manual `mv` by the user (fase-1 boundary).
|
||||
- **Slug-collision pre-write check.** Always `Read`
|
||||
`{catalog_root}/<slug>.md` before writing the draft. If the file
|
||||
exists, surface the collision in the confirmation output with a
|
||||
suggested qualified slug. Never block the draft write — the warning
|
||||
exists so the user sees the overwrite risk before running `mv`.
|
||||
- **Privacy.** Strip any secret-looking strings from the source
|
||||
before drafting; if the source is meaningfully about credentials,
|
||||
abort with `too-technical-to-paraphrase`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue