From efbb43094f90f1690a1e9ed6f7822848c6c2daa7 Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Sat, 18 Apr 2026 18:06:37 +0200 Subject: [PATCH] =?UTF-8?q?fix(ultraplan-local):=20v2.3.2=20=E2=80=94=20sk?= =?UTF-8?q?ill-drafter=20slug-collision=20hint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit skill-drafter now reads {catalog_root}/.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/.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}/.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 --- CLAUDE.md | 2 +- README.md | 4 +- .../.claude-plugin/plugin.json | 2 +- plugins/ultraplan-local/CHANGELOG.md | 44 +++++ plugins/ultraplan-local/CLAUDE.md | 1 + plugins/ultraplan-local/README.md | 4 +- .../ultraplan-local/agents/skill-drafter.md | 71 +++++++- .../skill-drafter/slug-collision-expected.md | 159 ++++++++++++++++++ 8 files changed, 276 insertions(+), 11 deletions(-) create mode 100644 plugins/ultraplan-local/tests/fixtures/skill-drafter/slug-collision-expected.md diff --git a/CLAUDE.md b/CLAUDE.md index e4c809d..7c2417c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,7 +12,7 @@ plugins/ llm-security/ v6.0.0 — Security scanning, auditing, threat modeling ms-ai-architect/ v1.8.0 — Microsoft AI architecture (Cosmo Skyberg persona) okr/ v1.0.0 — OKR guidance for Norwegian public sector - ultraplan-local/ v2.3.1 — Brief, research, architect, plan, execute (five-command pipeline + skill-factory Fase 1) + ultraplan-local/ v2.3.2 — Brief, research, architect, plan, execute (five-command pipeline + skill-factory Fase 1) ``` Hvert plugin er selvstendig med egen CLAUDE.md, README, hooks, agents og commands. diff --git a/README.md b/README.md index d6572be..8a5bcf6 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Key commands: `/config-audit posture`, `/config-audit feature-gap`, `/config-aud --- -### [Ultra {brief | research | architect | plan | execute} - local](plugins/ultraplan-local/) `v2.3.1` +### [Ultra {brief | research | architect | plan | execute} - local](plugins/ultraplan-local/) `v2.3.2` Deep requirements gathering, research, Claude Code feature matching, implementation planning, self-verifying execution, and skill-factory authoring with specialized agent swarms, adversarial review, IP-hygiene scoring, and failure recovery. @@ -76,7 +76,7 @@ Five core commands plus an authoring command, one pipeline with clear division o All artifacts land in one project directory: `.claude/projects/{YYYY-MM-DD}-{slug}/` contains `brief.md`, `research/NN-*.md`, `architecture/` *(v2.2)*, `plan.md`, `sessions/`, and `progress.json`. `--project ` works across `/ultraresearch-local`, `/ultra-cc-architect-local`, `/ultraplan-local`, and `/ultraexecute-local`. -v2.3 (non-breaking) ships the skill-factory Fase 1 MVP: `/ultra-skill-author-local` plus four supporting agents (1 opus orchestrator + 3 sonnet workers) and `scripts/ngram-overlap.mjs` (pure Node stdlib, word-5-gram containment + longest-run secondary signal, calibrated against three source/draft fixture pairs). Catalog growth is now tractable without touching the architect's hallucination gate. Non-goals stay explicit: no automation, no batch, no decision-layer skills, no remote sources — manual `mv` from `.drafts/` to catalog root is the promotion mechanism. v2.3.1 adds a qualified-slug convention (`[-]-.md`) so one feature can host multiple named patterns at different abstraction levels without displacing the baseline — resolved a collision surfaced in v2.3.0 dogfood. +v2.3 (non-breaking) ships the skill-factory Fase 1 MVP: `/ultra-skill-author-local` plus four supporting agents (1 opus orchestrator + 3 sonnet workers) and `scripts/ngram-overlap.mjs` (pure Node stdlib, word-5-gram containment + longest-run secondary signal, calibrated against three source/draft fixture pairs). Catalog growth is now tractable without touching the architect's hallucination gate. Non-goals stay explicit: no automation, no batch, no decision-layer skills, no remote sources — manual `mv` from `.drafts/` to catalog root is the promotion mechanism. v2.3.1 adds a qualified-slug convention (`[-]-.md`) so one feature can host multiple named patterns at different abstraction levels without displacing the baseline — resolved a collision surfaced in v2.3.0 dogfood. v2.3.2 closes the UX gap: `skill-drafter` now reads `{catalog_root}/.md` before writing and surfaces a collision warning in its confirmation output with a suggested qualified slug, so users see the overwrite risk before running `mv` — not after. v2.2 (non-breaking) adds the optional `/ultra-cc-architect-local` step between research and planning. The architect phase is backed by a versioned catalog skill (`cc-architect-catalog`) with 10 seed entries across three layers (reference, pattern, decision). Gaps are captured as issue-ready drafts so the catalog grows from real usage rather than speculation. `/ultraplan-local` auto-discovers the architecture note — existing pipelines keep working unchanged. diff --git a/plugins/ultraplan-local/.claude-plugin/plugin.json b/plugins/ultraplan-local/.claude-plugin/plugin.json index d22502b..0c35aae 100644 --- a/plugins/ultraplan-local/.claude-plugin/plugin.json +++ b/plugins/ultraplan-local/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "ultraplan-local", "description": "Five-command context-engineering pipeline (brief → research → architect → plan → execute) with project folders, CC-feature matching, specialized agent swarms, external research triangulation, adversarial review, session decomposition, and headless execution.", - "version": "2.3.1", + "version": "2.3.2", "author": { "name": "Kjell Tore Guttormsen" }, diff --git a/plugins/ultraplan-local/CHANGELOG.md b/plugins/ultraplan-local/CHANGELOG.md index f357a4d..5dfb93e 100644 --- a/plugins/ultraplan-local/CHANGELOG.md +++ b/plugins/ultraplan-local/CHANGELOG.md @@ -4,6 +4,50 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [2.3.2] - 2026-04-18 + +### Fixed — skill-drafter slug-collision hint + +`skill-drafter` now checks for an existing file at +`{catalog_root}/.md` before writing its draft to `.drafts/`. +When a collision is detected, the agent prepends a warning block to +its confirmation output showing the overwrite risk and a suggested +qualified slug derived from the concept handle. The draft is still +written to `.drafts/.md` — the check is a hint, not a block. + +**Why.** v2.3.0 dogfood surfaced the risk (logged as +`post_dogfood_findings[0]` in that run's `progress.json`): when the +drafter produced `.drafts/hooks-pattern.md` with an existing approved +`hooks-pattern.md` seed present at the catalog root, the pipeline +gave no signal that manual `mv` during promotion would silently +overwrite the seed. The v2.3.1 qualified-slug convention gave us the +mechanism to resolve collisions, but `skill-drafter` still didn't +surface them at the right moment — before promotion, not after. + +**Changes.** + +- `agents/skill-drafter.md` — new Step 2 "Check for slug collision at + the catalog root" between slug computation (Step 1) and reading the + source (Step 3). Subsequent workflow steps renumbered 3→7. New + "Suggesting a qualifier" guidance derives a kebab-case qualifier + from the `concept` field (or source basename as fallback). Output + format gains a `Collision:` field (`none | approved | pending | + auto-merged | soft`) and an optional warning block when the + collision is non-none. New Hard Rule "Slug-collision pre-write + check". +- `tests/fixtures/skill-drafter/slug-collision-expected.md` — new + reference fixture documenting the expected confirmation-output + shape across four scenarios (no collision, approved collision, + soft pending collision, collision with no good qualifier). + Skill-drafter is prompt-driven and not auto-tested; the fixture + anchors the shape for human verification and downstream parsers. + +**Non-breaking.** No changes to `.drafts/` layout, frontmatter +contract, tool scope, or filename regex. Existing pipelines see an +extra field (`Collision:`) and an optional warning block — both +purely additive. No version-gated changes in +`skill-author-orchestrator` or `ip-hygiene-checker`. + ## [2.3.1] - 2026-04-18 ### Added — Qualified slug convention for cc-architect-catalog diff --git a/plugins/ultraplan-local/CLAUDE.md b/plugins/ultraplan-local/CLAUDE.md index 5a829ce..1da02dc 100644 --- a/plugins/ultraplan-local/CLAUDE.md +++ b/plugins/ultraplan-local/CLAUDE.md @@ -130,6 +130,7 @@ Architect sits between `/ultraresearch-local` and `/ultraplan-local`. It matches - **Matcher logic:** `feature-matcher` builds `cc_feature → {layer → [skills]}` and prefers the unqualified baseline when the brief does not specifically justify a variant. Multiple skills can be proposed together when they cover non-overlapping aspects of the same feature. - **Critic enforcement:** `architecture-critic` verifies every cited `supporting_skill` name exists as a real file in the catalog (blocker severity). The `cc_feature` hallucination gate is unchanged — still validates against the taxonomy, not slugs. - **Collision handling:** skill-factory drafts that would overwrite an approved slug are a hard error. Resolution is either to qualify the new slug or revise the existing baseline. +- **Drafter collision hint (v2.3.2):** `skill-drafter` reads `{catalog_root}/.md` before writing, and prepends a warning block to its confirmation output when an existing skill would be overwritten during manual `mv` promotion. The warning cites the existing file's `review_status` and suggests a qualified slug derived from the `concept` handle. The draft is still written to `.drafts/.md` — the check is a hint, not a block. Seeds v2.3.1: 11 skills across 8 features — one qualified pattern (`hooks-observability-pattern.md`, promoted from `ai-psychosis/README.md`, ngram-overlap 0.01, approved). Decision-layer intentionally empty pending skill-factory Fase 2. diff --git a/plugins/ultraplan-local/README.md b/plugins/ultraplan-local/README.md index b7ddea2..fc0f388 100644 --- a/plugins/ultraplan-local/README.md +++ b/plugins/ultraplan-local/README.md @@ -1,6 +1,6 @@ # ultraplan-local — Brief, Research, Architect, Plan, Execute -![Version](https://img.shields.io/badge/version-2.3.1-blue) +![Version](https://img.shields.io/badge/version-2.3.2-blue) ![License](https://img.shields.io/badge/license-MIT-green) ![Platform](https://img.shields.io/badge/platform-Claude%20Code-purple) @@ -226,7 +226,7 @@ Downstream: `/ultraplan-local` auto-discovers `architecture/overview.md` in proj The architect command reads from `skills/cc-architect-catalog/`, a plugin-internal catalog of hand-written skills covering each CC feature at one or more layers (`reference`, `pattern`, `decision`). v2.2 shipped 10 seeds covering all 8 features at the reference layer (plus pattern layer for hooks and subagents). The catalog is designed for expansion via the skill-factory process (v2.3) — gaps surfaced by the architect command are the backlog for that work. -**Slug convention (v2.3):** files follow `[-]-.md`. Unqualified slugs (e.g., `hooks-pattern.md`) are the baseline/canonical entry for a `(feature, layer)` pair. Qualified slugs (e.g., `hooks-observability-pattern.md`) cover specific sub-patterns without displacing the baseline. `feature-matcher` prefers the baseline when the brief does not specifically justify a qualified variant; it may propose multiple supporting skills when they cover non-overlapping aspects. Slug collisions with approved skills are a hard error — skill-factory drafts must qualify or revise instead. +**Slug convention (v2.3):** files follow `[-]-.md`. Unqualified slugs (e.g., `hooks-pattern.md`) are the baseline/canonical entry for a `(feature, layer)` pair. Qualified slugs (e.g., `hooks-observability-pattern.md`) cover specific sub-patterns without displacing the baseline. `feature-matcher` prefers the baseline when the brief does not specifically justify a qualified variant; it may propose multiple supporting skills when they cover non-overlapping aspects. Slug collisions with approved skills are a hard error — skill-factory drafts must qualify or revise instead. **v2.3.2:** `skill-drafter` performs a pre-write check against `{catalog_root}/.md` and prepends a warning block to its confirmation when the proposed slug would collide, suggesting a qualified slug derived from the concept handle. The draft still writes to `.drafts/` — the warning exists so users see the overwrite risk before running `mv`. ### Hallucination gate diff --git a/plugins/ultraplan-local/agents/skill-drafter.md b/plugins/ultraplan-local/agents/skill-drafter.md index 799cefd..d500b3e 100644 --- a/plugins/ultraplan-local/agents/skill-drafter.md +++ b/plugins/ultraplan-local/agents/skill-drafter.md @@ -54,13 +54,48 @@ message — do not write a file with an invalid name. The draft file path is `{catalog_root}/.drafts/.md`. -### 2. Read the source +### 2. Check for slug collision at the catalog root + +Before proceeding, attempt to `Read` `{catalog_root}/.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/.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 +`--.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/.md`. Overwrite if it exists — the @@ -147,9 +182,30 @@ After writing the file, return a short confirmation: Drafted: .md> Word count: Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null +Collision: Next: ip-hygiene-checker for IP scoring ``` +If Step 2 detected a collision at `{catalog_root}/.md`, prepend +a warning block to the confirmation: + +``` +⚠️ Slug collision at catalog root + Existing: {catalog_root}/.md (review_status=) + Draft: {catalog_root}/.drafts/.md (this run) + Risk: manual `mv` during promotion will silently overwrite the existing file. + Suggested qualified slug: --.md + Reason for qualifier: + 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}/.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`. diff --git a/plugins/ultraplan-local/tests/fixtures/skill-drafter/slug-collision-expected.md b/plugins/ultraplan-local/tests/fixtures/skill-drafter/slug-collision-expected.md new file mode 100644 index 0000000..941afe7 --- /dev/null +++ b/plugins/ultraplan-local/tests/fixtures/skill-drafter/slug-collision-expected.md @@ -0,0 +1,159 @@ +# Skill-drafter slug-collision — expected output fixture + +This fixture documents the expected confirmation-message shape from +`skill-drafter` when it detects a slug collision at the catalog root. +It is a reference fixture — not an auto-executed test — used to +verify the agent by running a synthetic scenario by hand and +comparing output against the shapes below. + +## Scenario A — no collision (baseline) + +### Synthetic input + +- **Catalog root:** `skills/cc-architect-catalog/` +- **Concept JSON (from concept-extractor):** + ```json + { + "cc_feature": "worktrees", + "layer": "pattern", + "concept": "parallel feature isolation", + "description": "Isolate concurrent feature work in per-task worktrees to avoid git race conditions.", + "source_path": "/tmp/worktrees-notes.md", + "out_of_scope": false + } + ``` +- **Catalog state at time of run:** no `worktrees-pattern.md` present + at catalog root (only `worktrees-reference.md`). + +### Expected confirmation output + +``` +Drafted: /Users/…/skills/cc-architect-catalog/.drafts/worktrees-pattern.md +Word count: 312 +Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null +Collision: none +Next: ip-hygiene-checker for IP scoring +``` + +No warning block. `Collision: none`. + +## Scenario B — approved collision (primary case) + +### Synthetic input + +- **Catalog root:** `skills/cc-architect-catalog/` +- **Concept JSON:** + ```json + { + "cc_feature": "hooks", + "layer": "pattern", + "concept": "observability progressive alerts", + "description": "Progressive-alert observability pattern for hook-driven telemetry.", + "source_path": "/tmp/hooks-telemetry-notes.md", + "out_of_scope": false + } + ``` +- **Catalog state:** `hooks-pattern.md` exists with + `review_status: approved` (the v2.3.0 seed). + +### Expected confirmation output + +``` +⚠️ Slug collision at catalog root + Existing: skills/cc-architect-catalog/hooks-pattern.md (review_status=approved) + Draft: skills/cc-architect-catalog/.drafts/hooks-pattern.md (this run) + Risk: manual `mv` during promotion will silently overwrite the existing file. + Suggested qualified slug: hooks-observability-pattern.md + Reason for qualifier: concept handle names "observability" as the named sub-pattern. + Action: rename the draft before `mv`, or revise the existing baseline. + +Drafted: /Users/…/skills/cc-architect-catalog/.drafts/hooks-pattern.md +Word count: 287 +Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null +Collision: approved +Next: ip-hygiene-checker for IP scoring +``` + +The warning is prepended. The draft is still written — the collision +check is a hint, not a block. `Collision: approved` appears in the +confirmation for downstream-log parsers. + +## Scenario C — soft collision (pending existing) + +### Synthetic input + +- **Catalog state:** `subagents-pattern.md` exists with + `review_status: pending` (a prior draft that was `mv`-ed up without + the status being flipped, or a skill-factory auto-merged entry). + +### Expected confirmation output + +``` +⚠️ Slug collision at catalog root + Existing: skills/cc-architect-catalog/subagents-pattern.md (review_status=pending) + Draft: skills/cc-architect-catalog/.drafts/subagents-pattern.md (this run) + Risk: manual `mv` during promotion will silently overwrite the existing file. + Suggested qualified slug: subagents-delegation-pattern.md + Reason for qualifier: concept handle centers on "delegation chains". + Action: rename the draft before `mv`, or revise the existing baseline. + +Drafted: /Users/…/skills/cc-architect-catalog/.drafts/subagents-pattern.md +Word count: 256 +Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null +Collision: pending +Next: ip-hygiene-checker for IP scoring +``` + +`Collision: pending` signals a soft collision — the existing file is +not necessarily a guaranteed baseline. Reviewer decides. + +## Scenario D — collision but no good qualifier + +### Synthetic input + +- **Concept handle:** `generic feature note` (no specific noun) +- **Catalog state:** `skills-reference.md` exists (approved). + +### Expected confirmation output + +``` +⚠️ Slug collision at catalog root + Existing: skills/cc-architect-catalog/skills-reference.md (review_status=approved) + Draft: skills/cc-architect-catalog/.drafts/skills-reference.md (this run) + Risk: manual `mv` during promotion will silently overwrite the existing file. + Suggested qualified slug: none — reviewer must pick one manually. + Action: rename the draft before `mv`, or revise the existing baseline. + +Drafted: /Users/…/skills/cc-architect-catalog/.drafts/skills-reference.md +Word count: 198 +Frontmatter: 9 fields, review_status=pending, ngram_overlap_score=null +Collision: approved +Next: ip-hygiene-checker for IP scoring +``` + +The fallback line replaces the "Suggested qualified slug" value. +`Reason for qualifier` is omitted. + +## How to verify against this fixture + +This is not an auto-run test. To verify: + +1. Stage a synthetic concept JSON matching one of the scenarios above. +2. Invoke `skill-drafter` via the `Agent` tool with the concept JSON, + source path, and catalog root. +3. Capture the confirmation output. +4. Compare structurally against the corresponding scenario. The exact + word counts and paths will differ; the warning block, collision + field, and suggested-slug line are the load-bearing shapes. + +If a future change alters the confirmation format, update this file +alongside the agent prompt so the two remain in lockstep. + +## Why a reference fixture and not a unit test + +`skill-drafter` is a prompt-driven Sonnet agent. There is no in-repo +harness that executes prompts deterministically, so a unit test is +not practical. The reference fixture is the next-best anchor — it +documents the expected shape for human verification and for +downstream agents that parse the confirmation (e.g., the +skill-author-orchestrator's summary phase).