Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
5e3be7c
feat(app-control): add /app-control:map create with config, driver CL…
kyle-sexton Oct 24, 2026
7f33131
fix(app-control): drop angle brackets from the map skill description
kyle-sexton Oct 24, 2026
9c69a22
fix(app-control): state the recipient floor in map's prove step and s…
kyle-sexton Oct 24, 2026
438bd3d
fix(app-control): prove map create's start through drive and tighten …
kyle-sexton Oct 24, 2026
5338727
Merge branch 'main' into feat/9581-map-create
kyle-sexton Oct 24, 2026
fd3eaba
fix(app-control): make the driver CLI enforce map's safety floors and…
kyle-sexton Oct 24, 2026
3915e24
fix(app-control): name map in the plugin description and loosen the r…
kyle-sexton Oct 24, 2026
63378bf
fix(app-control): keep the plugin description under claude.ai's 500-c…
kyle-sexton Oct 24, 2026
8235d0d
fix(app-control): mark create's send and write steps unproven until d…
kyle-sexton Oct 24, 2026
9187873
Merge remote-tracking branch 'origin/feat/9581-map-create' into feat/…
kyle-sexton Oct 24, 2026
9033e10
Merge branch 'main' into feat/9581-map-create
kyle-sexton Oct 24, 2026
fe5538a
fix(app-control): address the ready-flip code and security reviews of…
kyle-sexton Oct 24, 2026
091aa26
fix(app-control): answer the ready review lanes on map create
kyle-sexton Oct 24, 2026
b8e8c59
feat(app-control): add /app-control:map check
kyle-sexton Oct 24, 2026
794555d
test(app-control): cover the git top level as check-map's default root
kyle-sexton Oct 24, 2026
d21ea9c
docs(app-control): state the shared/ convention in the control-skill …
kyle-sexton Oct 24, 2026
0768d7a
Merge branch 'feat/9582-map-check' into feat/9583-map-refresh
kyle-sexton Oct 24, 2026
e0bcf52
Merge remote-tracking branch 'origin/feat/9581-map-create' into feat/…
kyle-sexton Oct 24, 2026
8adc529
feat(app-control): add /app-control:map refresh
kyle-sexton Oct 24, 2026
e5857c4
fix(app-control): resolve check-map source globs from the project hol…
kyle-sexton Oct 24, 2026
6b181e8
test(app-control): commit the legacy map in its eval scaffold
kyle-sexton Oct 24, 2026
a8d6a23
fix(app-control): name the upkeep branch by the control skill's direc…
kyle-sexton Oct 24, 2026
fb0381d
test(app-control): keep the legacy-map scaffold's commit in its own r…
kyle-sexton Oct 24, 2026
67f6765
fix(app-control): write map's argument-hint with unspaced alternatives
kyle-sexton Oct 24, 2026
0d8dea5
Merge feat/9582-map-check into feat/9583-map-refresh
kyle-sexton Oct 24, 2026
e8f3581
Merge origin/main into feat/9583-map-refresh
kyle-sexton Oct 25, 2026
faa636d
Merge branch 'main' into feat/9583-map-refresh
kyle-sexton Oct 25, 2026
eab85ce
fix(app-control): hold every refreshed control skill to the real-path…
kyle-sexton Oct 25, 2026
7aac9d5
fix(app-control): settle map refresh's waves, legacy paths and branch…
kyle-sexton Oct 25, 2026
6523e7d
test(app-control): match a triage class only where the reply chooses it
kyle-sexton Oct 25, 2026
dea4ce1
test(app-control): end the legacy-migration branch grader at the slug
kyle-sexton Oct 25, 2026
62dcf3b
test(app-control): give the wave-cap scaffold's hub its App and drivi…
kyle-sexton Oct 25, 2026
7e66385
test(app-control): cover an unattended driver gap reported unwritten
kyle-sexton Oct 25, 2026
59b7df4
test(app-control): cover reporting a testing-era feature-map-upkeep b…
kyle-sexton Oct 25, 2026
b66e585
test(app-control): cover converting a control skill's flat feature fi…
kyle-sexton Oct 25, 2026
dffc029
test(app-control): cover one upkeep branch per control skill in a mul…
kyle-sexton Oct 25, 2026
88ec64a
fix(app-control): point the pstack record at map's current line ranges
kyle-sexton Oct 25, 2026
b72f3b1
fix(app-control): state the unattended driver-gap rule in map's hub
kyle-sexton Oct 25, 2026
ad94445
test(app-control): match a triage class named after "is" or "as"
kyle-sexton Oct 25, 2026
1cd30ad
test(app-control): start the branch-handling scaffolds on main
kyle-sexton Oct 25, 2026
726e4b6
fix(app-control): follow map's moved line ranges in the pstack record
kyle-sexton Oct 25, 2026
ce769c8
fix(app-control): end a refresh that leaves a driver gap unwritten as…
kyle-sexton Oct 25, 2026
edf85d7
test(app-control): spell the triage regexes and one prompt so typos p…
kyle-sexton Oct 25, 2026
d596fc1
fix(app-control): convert a legacy map before refresh drives it
kyle-sexton Oct 25, 2026
f921d85
fix(app-control): scope a conversion's driver gap to the contract's c…
kyle-sexton Oct 25, 2026
f8c34d0
test(app-control): grade the flat conversion on the PR step the skill…
kyle-sexton Oct 25, 2026
5e61ebd
fix(app-control): block a refresh only on a driver gap the live pass hit
kyle-sexton Oct 25, 2026
2cc3891
fix(app-control): ask before converting a legacy map, undo it when th…
kyle-sexton Oct 25, 2026
3410a23
test(app-control): accept either PR route step 6.4 specifies in the f…
kyle-sexton Oct 25, 2026
40451ac
fix(app-control): undo a legacy conversion from a copy, refuse a dirt…
kyle-sexton Oct 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changes/app-control/feat-9583-map-refresh-29fdd303.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
bump: minor
---

### Added

- `/app-control:map refresh` keeps a control skill in line with the app and ends `clean`, `changed` or `blocked`. It skips when nothing changed since the last clean pass on this host, refuses an attended-only control skill when unattended, runs a read-only source wave of one subagent per feature in waves filled to six before the next starts, then drives every feature through `/app-control:drive` with Ready before the first drive and after any failed one, cleanup after each drive and every evidence path checked after cleanup. Each difference is triaged as doc drift (corrected), driver gap (on an attended pass fixed in `cli/` and shipped only after a live re-drive; on an unattended one reported unwritten; never by loosening a floor) or product regression (left as written and reported, or sent to `/bugs:write`, never put in the pull request). Edits stay inside the control skill's directory and go out on `control-skill-upkeep/control-<slug>` (the control skill's directory name), from the default branch, merged into and never rebased, through at most one pull request; every local and remote `feature-map-upkeep/*` branch is reported by name, not adopted. A pass over several control skills uses one branch per skill and returns to its starting branch between them. A legacy testing feature map at the path the person passes, or a control skill's flat feature files, is converted to the contract's folder layout in the same upkeep pull request, with the old files moved in that commit. A legacy map is converted first, uncommitted on the upkeep branch and after an attended pass approves the planned conversion, so both passes drive the converted control skill; a tracked legacy map with uncommitted changes blocks the conversion, and a pass that stops before the commit deletes what the conversion created, restores the legacy files from a copy taken outside the checkout before the first write, and returns to its starting branch. Reauthored from the upkeep loop, its three live-pass invariants and its triage of pstack's `maintain-verification-skill` ([cursor/plugins](https://github.com/cursor/plugins), MIT).
2 changes: 1 addition & 1 deletion docs/skill-cheat-sheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ owned by [docs/catalog-taxonomy.md](catalog-taxonomy.md).
| Skill | Plugin | What it does |
| --- | --- | --- |
| [`/app-control:drive`](../plugins/app-control/skills/drive/SKILL.md) | `app-control` | Run the app, drive it, record evidence, never judge |
| [`/app-control:map`](../plugins/app-control/skills/map/SKILL.md) | `app-control` | Generate and prove a control skill that /app-control:drive runs |
| [`/app-control:map`](../plugins/app-control/skills/map/SKILL.md) | `app-control` | Generate, prove and keep current a control skill /app-control:drive runs |
| [`/evals:design`](../plugins/evals/skills/design/SKILL.md) | `evals` | Interview for success criteria and scaffold an eval suite in the consumer repo |
| [`/evals:methodology`](../plugins/evals/skills/methodology/SKILL.md) | `evals` | Answer LLM-evaluation design questions from Anthropic's official guidance |
| [`/evals:plugin-eval`](../plugins/evals/skills/plugin-eval/SKILL.md) | `evals` | Preflight, price, run, and read a plugin eval suite around the CLI |
Expand Down
5 changes: 3 additions & 2 deletions docs/upstream/cursor-pstack.md

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions plugins/app-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ they mean.
| Skill | What it does |
|---|---|
| `/app-control:drive` | Bare drive performs a feature's steps; `ready` reports what is reachable; `capture --kind <kind>` records one artifact; `cleanup` stops what the run started and checks the evidence survives; `--attach` reaches a process already running that the person named, in an interactive session only; `--unattended` asks nothing |
| `/app-control:map` | Bare map proposes what it would write; `create` discovers the repository, asks only what discovery left open, writes the control skill (hub, feature folders, config, driver CLI and an instruction-file pointer) and proves it once through drive; `--unattended` is a dry run that writes nothing and lists every open question with a recommendation |
| `/app-control:map` | Bare map proposes what it would write; `create` discovers the repository, asks only what discovery left open, writes the control skill (hub, feature folders, config, driver CLI and an instruction-file pointer) and proves it once through drive; `check` reports contract breaks and edits nothing; `refresh` brings a control skill back in line with the app (or converts a testing feature map) through one upkeep pull request, keeping product regressions out of it; with `create`, `--unattended` is a dry run that writes nothing and lists every open question with a recommendation |

Both skills are model-invoked, so other skills, scheduled runs and CI jobs call drive instead of the
project's own control skill, and map is the only writer of that control skill.
Expand All @@ -28,8 +28,7 @@ control skill.

## Not yet in this plugin

Reading an `app-control.yaml` override, attaching to a process drive did not start, and checking
or refreshing an existing control skill.
Reading an `app-control.yaml` override and attaching to a process drive did not start.

## Attribution

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
schema_version: "1.1"
name: map-converts-flat-control-skill
description: Refresh of a control skill with flat feature files converts each to a feature folder in the same upkeep pull request, moving a States section into Reset
tags: [map, refresh, migration, invented]
expected_outcome: "The reply reads the control skill and plans to convert features/start-a-timer.md and features/approve-timesheet.md in place to features/start-a-timer/README.md and features/approve-timesheet/README.md, moved with git mv, with start-a-timer's States content under Reset and no States section left, and the hub's index lines pointing at the new paths. The conversion is committed on control-skill-upkeep/control-clockwork as part of that one upkeep change; with no source-control plugin loaded here, the commit stays on that branch and the report says the pull request still needs opening, the outcome is changed although the passes found no other difference, and nothing is written in this session."
context:
scaffold_script: scaffold.sh
execution:
prompt: "/app-control:map refresh .claude/skills/control-clockwork. Read the files under that directory, but do not drive the app, write, move or commit anything in this session. Treat the source wave and the live pass as already run: both match every entry point, each driven through playwright. Tell me which files the refresh would write and move, what happens to each section of each feature file, the branch, what goes in which pull request, and the outcome, then stop."
allowed_tools: [Read, Glob, Grep]
max_turns: 10
timeout_seconds: 400
graders:
- name: reads-hub
type: tool_used
tool: Read
input_match: 'control-clockwork/SKILL\.md'
min: 1
arm: both
- name: names-folder-feature
type: regex
pattern: 'features/start-a-timer/README\.md'
arm: both
- name: converts-in-upkeep-pull-request
type: llm
criteria: "PASS only if the reply (1) plans to convert both flat files, features/start-a-timer.md and features/approve-timesheet.md, to features/start-a-timer/README.md and features/approve-timesheet/README.md, moving them rather than leaving a copy at the flat path, (2) moves start-a-timer's States content (the Website refresh project and no running timer) into its Reset section and keeps no States section, (3) updates the hub's index lines to the new paths, (4) commits the conversion on control-skill-upkeep/control-clockwork as part of that one upkeep change: it goes out in the one upkeep pull request or, when the source-control plugin is not enabled or its pull-request list call fails, stays committed on that branch with the report saying the pull request still needs opening (either is acceptable, as is a reply that states both cases), and (5) calls the outcome changed even though the passes found no other difference. FAIL if it leaves either feature file flat, keeps a States section, opens a separate pull request or branch for the conversion, calls the outcome clean or skipped, or plans any edit outside .claude/skills/control-clockwork/."
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"pass": [
{
"answer": "git mv features/start-a-timer.md to features/start-a-timer/README.md, with States moved into Reset.",
"why": "names the folder feature file"
}
],
"fail": [
{
"answer": "Keep features/start-a-timer.md flat and only update its Drive.",
"why": "keeps the flat layout"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"pass": [
{
"answer": [
{
"tool": "Read",
"input": {
"file_path": ".claude/skills/control-clockwork/SKILL.md"
}
}
],
"why": "read the hub"
}
],
"fail": [
{
"answer": [
{
"tool": "Glob",
"input": {
"pattern": ".claude/skills/control-clockwork/features/*"
}
}
],
"why": "listed features but read no hub"
}
]
}
103 changes: 103 additions & 0 deletions plugins/app-control/evals/map-converts-flat-control-skill/scaffold.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env bash
# Seeds a committed control skill whose two feature files are flat features/<id>.md, one of them
# with a ## States section, so a refresh must convert both to folders in its upkeep pull request.
set -euo pipefail

# Init a repository here unless this directory already is one's top level, so the commit never lands
# in an enclosing repository.
if [[ "$(git rev-parse --show-toplevel 2>/dev/null || true)" != "$(pwd -P)" ]]; then
git init -q -b main
fi
git config user.name eval
git config user.email eval@example.invalid
skill=.claude/skills/control-clockwork
mkdir -p "$skill/features" src
cat >"$skill/SKILL.md" <<'MD'
---
description: "Launch, ready-check, capture and clean up the Clockwork web app."
---

- App: Clockwork web, built from `src/`
- Driving tool: playwright

## Launch

Run the `run-clockwork` skill.

## Ready

`curl -fsS http://127.0.0.1:5180/healthz`

## Capture

none

## Cleanup

Stop the pid recorded at launch.

## Features

- start a timer | features/start-a-timer.md | entry points: 2 | sources: src/TimerRow.tsx
- approve a timesheet | features/approve-timesheet.md | entry points: 1 | sources: src/Approvals.tsx
MD
cat >"$skill/features/start-a-timer.md" <<'MD'
# Start a timer

## Parts

- start: a new timer begins at 00:00 for the chosen project

## Sub-features

none

## Entry points

- the `Start` button on the dashboard: driven
- pressing `t` anywhere on the dashboard: driven

## States

- The scratch database holds the project `Website refresh` and no running timer.

## Drive

- Choose `Start` in the row named `Website refresh`; the row shows a running clock within two seconds.

## Gotchas

- A timer left running from an earlier run makes `start` look like a switch.
MD
cat >"$skill/features/approve-timesheet.md" <<'MD'
# Approve a timesheet

## Parts

- approve: a manager approves a submitted timesheet

## Sub-features

none

## Entry points

- the `Approve` button on a submitted timesheet: driven

## Reset

Seed the scratch database with one submitted timesheet.

## Drive

- Choose `Approve` on the submitted timesheet; the row shows `Approved`.

## Gotchas

none
MD
: >src/TimerRow.tsx
: >src/Approvals.tsx
git add -A
GIT_AUTHOR_DATE=2026-10-01T09:00:00Z GIT_COMMITTER_DATE=2026-10-01T09:00:00Z \
git commit -q -m "Clockwork web with its control skill"
21 changes: 21 additions & 0 deletions plugins/app-control/evals/map-legacy-dirty-map-blocks/case.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
schema_version: "1.1"
name: map-legacy-dirty-map-blocks
description: Refresh of a tracked legacy feature map holding uncommitted edits refuses the conversion, ends blocked and writes, moves and switches nothing
tags: [map, refresh, migration, invented]
expected_outcome: "The reply finds the tracked legacy map has an uncommitted change in .claude/skills/feature-map/start-a-timer.md, ends the refresh blocked before the conversion with nothing written, moved or switched, and tells the person to commit or stash that change first. It does not plan to discard, restore or overwrite the change."
context:
scaffold_script: scaffold.sh
execution:
prompt: "/app-control:map refresh .claude/skills/feature-map. Read the files under that directory, but do not drive the app, switch branches, write, move or commit anything in this session. There is no shell: `git status --porcelain` from the repository root prints ` M .claude/skills/feature-map/start-a-timer.md` and nothing else, and the decide step prints `run`. Tell me what the refresh does next, the outcome, and what you would leave for a person, then stop."
allowed_tools: [Read, Glob, Grep]
max_turns: 10
timeout_seconds: 400
graders:
- name: says-blocked
type: regex
pattern: '\bblocked\b'
flags: i
arm: both
- name: refuses-dirty-conversion
type: llm
criteria: "PASS only if the reply (1) ends the refresh with the outcome blocked because the tracked legacy map file .claude/skills/feature-map/start-a-timer.md has uncommitted changes, (2) does so before converting: no branch switch, no move of the legacy files, no write into .claude/skills/control-clockwork-web/, and (3) leaves the person to commit or stash that change before a refresh converts the map. FAIL if it plans the conversion, the upkeep branch switch or the move anyway, plans to discard, reset, restore or overwrite the uncommitted change, or calls the outcome changed or clean."
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
description: "Read this feature map before driving Clockwork web."
disable-model-invocation: false
---

- Application: Clockwork web, built from `apps/web`
- Launch: `run-clockwork` (project skill)
- Driver: playwright, from docs/conventions/testing.yaml
- Doctor: `curl -fsS http://127.0.0.1:5180/healthz` prints `{"status":"ok","build":"<sha>"}`
- Isolation: one instance per port; set `CLOCKWORK_DB` to a scratch file per run
- Written at: 3f9c2a1

## Features

- Start a timer: `start-a-timer.md` (2 entry points)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Start a timer

A user starts tracking time against a project and sees the elapsed time grow.

## Parts

- start: a new timer begins at 00:00 for the chosen project
- resume: a timer survives a page reload

## Entry points

- the `Start` button on the dashboard
- pressing `t` anywhere on the dashboard

## Drive

Start from an empty scratch database with the project `Website refresh`.

- Choose `Start` in the row named `Website refresh`; the row shows a running clock within two seconds.
- Reload the page; the same clock is still running and has not reset.

## Traps

- A timer left running from an earlier run makes `start` look like a switch; reset the database first.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"pass": [
{
"answer": "Outcome: **blocked**. start-a-timer.md has uncommitted changes; commit or stash them first.",
"why": "names the blocked outcome"
},
{
"answer": "The refresh is Blocked before the conversion and writes nothing.",
"why": "case-insensitive outcome word"
}
],
"fail": [
{
"answer": "Outcome: changed. The conversion moves start-a-timer.md into control-clockwork-web.",
"why": "converts the dirty map"
},
{
"answer": "The pass is unblocked once the copy is taken, so it converts.",
"why": "only the word unblocked, not the outcome"
}
]
}
22 changes: 22 additions & 0 deletions plugins/app-control/evals/map-legacy-dirty-map-blocks/scaffold.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Seeds a committed legacy testing-format feature map at .claude/skills/feature-map, then leaves an
# uncommitted edit in one of its tracked files, so a refresh must refuse to convert it.
set -euo pipefail

here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Init a repository here unless this directory already is one's top level, so the commit never lands
# in an enclosing repository.
if [[ "$(git rev-parse --show-toplevel 2>/dev/null || true)" != "$(pwd -P)" ]]; then
git init -q -b main
fi
git config user.name eval
git config user.email eval@example.invalid
map=.claude/skills/feature-map
mkdir -p "$map" apps/web/src
cp "$here/fixtures/index.md" "$map/SKILL.md"
cp "$here/fixtures/start-a-timer.md" "$map/start-a-timer.md"
: >apps/web/src/TimerRow.tsx
git add -A
GIT_AUTHOR_DATE=2026-10-01T09:00:00Z GIT_COMMITTER_DATE=2026-10-01T09:00:00Z \
git commit -q -m "Clockwork web with its feature map"
printf '%s\n' '- Pausing a timer is not mapped yet; draft note, not committed.' >>"$map/start-a-timer.md"
33 changes: 33 additions & 0 deletions plugins/app-control/evals/map-legacy-flat-map-migrates/case.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
schema_version: "1.1"
name: map-legacy-flat-map-migrates
description: Refresh of a legacy testing-format feature map converts it into a control skill with folder features, moves the old files in the same upkeep pull request, and runs even when nothing else changed
tags: [map, refresh, migration, invented]
expected_outcome: "The reply reads the legacy map and plans a conversion into .claude/skills/control-clockwork-web/: a hub carrying the app, the run-clockwork launch pointer, the healthz Ready command and an index line for start-a-timer; features/start-a-timer/README.md with the six contract sections, Traps becoming Gotchas; config/defaults.json at safe floors and config/.gitignore. The old files move with git mv in the same commit on control-skill-upkeep/control-clockwork-web, the outcome is changed although the passes found no other difference, the instruction-file pointer and feature_map_dir are reported rather than edited, and nothing is written in this session. The conversion is written first, uncommitted on that branch, and the source wave and live pass read the converted control skill, not the legacy map."
context:
scaffold_script: scaffold.sh
execution:
prompt: "/app-control:map refresh .claude/skills/feature-map. Read the files under that directory, but do not drive the app, write, move or commit anything in this session. Treat the source wave and the live pass as already run: both match every entry point, each driven through playwright. Tell me which files the refresh would write and move, the branch, what goes in the pull request, the outcome, what you would leave for a person, and the order the refresh takes its steps in, including which skill the live pass drives, then stop."
allowed_tools: [Read, Glob, Grep]
max_turns: 10
timeout_seconds: 400
graders:
- name: reads-legacy-index
type: tool_used
tool: Read
input_match: 'feature-map/SKILL\.md'
min: 1
arm: both
- name: names-folder-feature
type: regex
pattern: 'features/start-a-timer/README\.md'
arm: both
- name: names-upkeep-branch
type: regex
pattern: 'control-skill-upkeep/control-clockwork-web(?![\w-])'
arm: both
- name: converts-in-upkeep-pull-request
type: llm
criteria: "PASS only if the reply (1) plans the control skill at .claude/skills/control-clockwork-web/ with a hub (Launch naming run-clockwork, Ready using the healthz command, an index line for start-a-timer), (2) plans features/start-a-timer/README.md with the sections Parts, Sub-features, Entry points, Reset, Drive and Gotchas in that order, with the old Traps content under Gotchas and each entry point marked driven, (3) moves the legacy files out of .claude/skills/feature-map in the same commit rather than leaving a copy, on control-skill-upkeep/control-clockwork-web, (4) calls the outcome changed even though the passes found no other difference, and (5) leaves the instruction-file pointer and any feature_map_dir setting for a person, without planning to edit them. FAIL if it keeps the flat start-a-timer.md layout, writes into .claude/skills/feature-map, leaves both copies, calls the outcome clean or skipped, or plans to commit on a feature-map-upkeep branch."
- name: converts-before-driving
type: llm
criteria: "PASS only if the reply orders the refresh so the conversion into .claude/skills/control-clockwork-web/ is written, uncommitted, on control-skill-upkeep/control-clockwork-web before the source wave and the live pass, and the live pass drives the converted control skill (control-clockwork-web) through /app-control:drive. FAIL if it drives or plans to drive the legacy map at .claude/skills/feature-map, runs either pass before writing the conversion, or does not say which skill the live pass drives."
Loading
Loading