create-claude-cabinet 0.24.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/lib/cli.js +81 -2
- package/lib/verify-setup.js +140 -0
- package/package.json +1 -1
- package/templates/skills/debrief/phases/verify-coverage.md +101 -0
- package/templates/skills/execute/phases/verify-emit.md +104 -0
- package/templates/skills/plan/phases/verify-plan.md +97 -0
- package/templates/skills/verify/SKILL.md +228 -0
- package/templates/skills/verify/install.sh +342 -0
- package/templates/skills/verify/phases/calibrate.md +115 -0
- package/templates/skills/verify/phases/discover.md +114 -0
- package/templates/skills/verify/phases/draft.md +92 -0
- package/templates/skills/verify/phases/generate.md +71 -0
- package/templates/skills/verify/phases/scenario-template.md +119 -0
- package/templates/skills/verify/phases/update.md +81 -0
- package/templates/verify-runtime/CONVENTIONS.md +331 -0
- package/templates/verify-runtime/README.md +59 -0
- package/templates/verify-runtime/package-lock.json +2008 -0
- package/templates/verify-runtime/package.json +34 -0
- package/templates/verify-runtime/src/auto-check.ts +56 -0
- package/templates/verify-runtime/src/cli/preflight.ts +14 -0
- package/templates/verify-runtime/src/cli/report-last.ts +191 -0
- package/templates/verify-runtime/src/cli/report-status.ts +365 -0
- package/templates/verify-runtime/src/fixture-loader.ts +87 -0
- package/templates/verify-runtime/src/fresh-pass-cache.ts +193 -0
- package/templates/verify-runtime/src/human-verdict.ts +194 -0
- package/templates/verify-runtime/src/index.ts +66 -0
- package/templates/verify-runtime/src/manual-runner.ts +257 -0
- package/templates/verify-runtime/src/output.ts +177 -0
- package/templates/verify-runtime/src/path-hash.ts +241 -0
- package/templates/verify-runtime/src/preflight.ts +120 -0
- package/templates/verify-runtime/src/verdict-recorder.ts +318 -0
- package/templates/verify-runtime/src/world.ts +188 -0
- package/templates/verify-runtime/test/fixtures/sample.feature +17 -0
- package/templates/verify-runtime/test/fresh-pass-cache.test.ts +289 -0
- package/templates/verify-runtime/test/path-hash.test.ts +264 -0
- package/templates/verify-runtime/test/verdict-recorder.test.ts +58 -0
- package/templates/verify-runtime/tsconfig.json +16 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ gives Claude a memory, 31 domain experts, a planning process, and the
|
|
|
5
5
|
habit of starting sessions informed and ending them properly.
|
|
6
6
|
|
|
7
7
|
Built by a guy who'd rather talk to Claude than write code. Most of it
|
|
8
|
-
was built by Claude. I just complained until it worked.
|
|
8
|
+
was built by Claude. I just complained until it (mostly) worked.
|
|
9
9
|
|
|
10
10
|
## The Idea
|
|
11
11
|
|
|
@@ -63,8 +63,8 @@ automatically.
|
|
|
63
63
|
|
|
64
64
|
- **`/orient`** — open every session with this. Claude reads project
|
|
65
65
|
state, checks health, surfaces what needs attention, and briefs you
|
|
66
|
-
so you never start blind. Think of it as the
|
|
67
|
-
|
|
66
|
+
so you never start blind. Think of it as the briefing before the
|
|
67
|
+
cabinet gets to work.
|
|
68
68
|
- **`/debrief`** — close every session with this. Claude marks work
|
|
69
69
|
done, records lessons, updates state, and prepares the briefing for
|
|
70
70
|
next time. Without debrief, the next orient starts with stale
|
|
@@ -134,7 +134,7 @@ hooks — things that keep going wrong become things that can't go wrong.
|
|
|
134
134
|
|
|
135
135
|
## Your Workflow
|
|
136
136
|
|
|
137
|
-
The
|
|
137
|
+
The rhythm of each session:
|
|
138
138
|
|
|
139
139
|
1. **Start a session** → `/orient` (get briefed)
|
|
140
140
|
2. **Do your work** → talk to Claude, use `/plan` for anything non-trivial
|
|
@@ -227,7 +227,7 @@ other.
|
|
|
227
227
|
## Philosophy
|
|
228
228
|
|
|
229
229
|
This started as the process layer of [Flow](https://github.com/orenmagid/flow),
|
|
230
|
-
a cognitive workspace built on Claude Code over months of
|
|
230
|
+
a cognitive workspace built on Claude Code over months of intensive use. The
|
|
231
231
|
patterns that emerged — the session loop, cabinet-style audits, feedback
|
|
232
232
|
enforcement — turned out to be transferable to any project.
|
|
233
233
|
|
package/lib/cli.js
CHANGED
|
@@ -8,6 +8,7 @@ const { mergeSettings } = require('./settings-merge');
|
|
|
8
8
|
const { create: createMetadata, read: readMetadata } = require('./metadata');
|
|
9
9
|
const { setupDb } = require('./db-setup');
|
|
10
10
|
const { setupOmega } = require('./omega-setup');
|
|
11
|
+
const { setupVerifyRuntime } = require('./verify-setup');
|
|
11
12
|
const { reset } = require('./reset');
|
|
12
13
|
|
|
13
14
|
const VERSION = require('../package.json').version;
|
|
@@ -451,6 +452,20 @@ const MODULES = {
|
|
|
451
452
|
needsOmega: true,
|
|
452
453
|
templates: ['skills/memory', 'scripts/cabinet-memory-adapter.py', 'scripts/migrate-memory-to-omega.py', 'rules/memory-capture.md', 'hooks/omega-memory-guard.sh'],
|
|
453
454
|
},
|
|
455
|
+
'verify': {
|
|
456
|
+
name: 'Verification Harness (Cucumber + Playwright)',
|
|
457
|
+
description: 'Walkthrough verification with human-in-the-loop verdict pauses. Replaces flat AC lists with re-runnable user-journey scenarios. Includes /verify skeleton skill + cabinet-verify npm runtime + opt-in integration phases for /plan, /execute, /debrief.',
|
|
458
|
+
mandatory: false,
|
|
459
|
+
default: false,
|
|
460
|
+
lean: false,
|
|
461
|
+
templates: [
|
|
462
|
+
'skills/verify',
|
|
463
|
+
'skills/plan/phases/verify-plan.md',
|
|
464
|
+
'skills/execute/phases/verify-emit.md',
|
|
465
|
+
'skills/debrief/phases/verify-coverage.md',
|
|
466
|
+
],
|
|
467
|
+
postInstall: 'verify-setup',
|
|
468
|
+
},
|
|
454
469
|
};
|
|
455
470
|
|
|
456
471
|
/** Recursively collect all relative file paths under a directory. */
|
|
@@ -504,7 +519,8 @@ function parseArgs(argv) {
|
|
|
504
519
|
targetDir: '.',
|
|
505
520
|
};
|
|
506
521
|
|
|
507
|
-
for (
|
|
522
|
+
for (let i = 0; i < args.length; i++) {
|
|
523
|
+
const arg = args[i];
|
|
508
524
|
if (arg === '--yes' || arg === '-y') flags.yes = true;
|
|
509
525
|
else if (arg === '--lean') flags.lean = true;
|
|
510
526
|
else if (arg === '--no-db') flags.noDb = true;
|
|
@@ -512,6 +528,9 @@ function parseArgs(argv) {
|
|
|
512
528
|
else if (arg === '--help' || arg === '-h') flags.help = true;
|
|
513
529
|
else if (arg === '--reset') flags.reset = true;
|
|
514
530
|
else if (arg === '--force') flags.force = true;
|
|
531
|
+
else if (arg === '--modules' && i + 1 < args.length) {
|
|
532
|
+
flags.modules = args[++i].split(',').map(s => s.trim()).filter(Boolean);
|
|
533
|
+
}
|
|
515
534
|
else if (!arg.startsWith('-')) flags.targetDir = arg;
|
|
516
535
|
}
|
|
517
536
|
|
|
@@ -526,6 +545,8 @@ function printHelp() {
|
|
|
526
545
|
--yes, -y Accept all defaults, no prompts
|
|
527
546
|
--lean Install core modules only (no work-tracking, compliance, validate)
|
|
528
547
|
--no-db Skip work tracking database setup
|
|
548
|
+
--modules <keys> Comma-separated module keys to install (e.g., 'verify,memory').
|
|
549
|
+
Mandatory modules are always included.
|
|
529
550
|
--dry-run Show what would be copied without writing
|
|
530
551
|
--reset Remove Claude Cabinet files (uses manifest for safety)
|
|
531
552
|
--force With --reset: remove even customized files
|
|
@@ -665,7 +686,45 @@ async function run() {
|
|
|
665
686
|
let skippedModules = {};
|
|
666
687
|
let includeDb = !flags.noDb;
|
|
667
688
|
|
|
668
|
-
if (flags.
|
|
689
|
+
if (flags.modules) {
|
|
690
|
+
// Explicit module selection via --modules <key1,key2,...>. Mandatory
|
|
691
|
+
// modules are always included regardless of the flag value, so the
|
|
692
|
+
// installer always has session-loop etc. available.
|
|
693
|
+
//
|
|
694
|
+
// On an upgrade (existing .ccrc.json present), --modules is treated
|
|
695
|
+
// ADDITIVELY: the requested keys are merged with whatever the
|
|
696
|
+
// existing installation already had enabled. Otherwise an `--modules
|
|
697
|
+
// verify` invocation on a project with 9 enabled modules would
|
|
698
|
+
// silently deregister 8 of them. Replacing the existing set on
|
|
699
|
+
// upgrade is almost never what the operator wants. (Fresh installs
|
|
700
|
+
// unchanged — there's no prior set to merge with.)
|
|
701
|
+
const mandatoryKeys = Object.entries(MODULES)
|
|
702
|
+
.filter(([, mod]) => mod.mandatory)
|
|
703
|
+
.map(([key]) => key);
|
|
704
|
+
const requested = flags.modules.filter(k => MODULES[k]);
|
|
705
|
+
const unknown = flags.modules.filter(k => !MODULES[k]);
|
|
706
|
+
if (unknown.length > 0) {
|
|
707
|
+
console.log(` ⚠ Unknown modules ignored: ${unknown.join(', ')}`);
|
|
708
|
+
console.log(` Known modules: ${Object.keys(MODULES).join(', ')}`);
|
|
709
|
+
}
|
|
710
|
+
let existingEnabled = [];
|
|
711
|
+
if (dirState === 'existing-install') {
|
|
712
|
+
const existing = readMetadata(projectDir);
|
|
713
|
+
existingEnabled = Object.entries(existing.modules || {})
|
|
714
|
+
.filter(([k, enabled]) => enabled && MODULES[k])
|
|
715
|
+
.map(([k]) => k);
|
|
716
|
+
if (existingEnabled.length > 0) {
|
|
717
|
+
console.log(` Existing modules carried forward: ${existingEnabled.join(', ')}`);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
selectedModules = [...new Set([...mandatoryKeys, ...existingEnabled, ...requested])];
|
|
721
|
+
const skippedKeys = Object.keys(MODULES).filter(k => !selectedModules.includes(k));
|
|
722
|
+
for (const k of skippedKeys) {
|
|
723
|
+
skippedModules[k] = `Skipped by --modules flag`;
|
|
724
|
+
}
|
|
725
|
+
if (!selectedModules.includes('work-tracking')) includeDb = false;
|
|
726
|
+
console.log(` Installing modules: ${selectedModules.join(', ')}\n`);
|
|
727
|
+
} else if (flags.lean) {
|
|
669
728
|
selectedModules = Object.entries(MODULES)
|
|
670
729
|
.filter(([, mod]) => mod.mandatory || mod.lean)
|
|
671
730
|
.map(([key]) => key);
|
|
@@ -955,6 +1014,26 @@ async function run() {
|
|
|
955
1014
|
}
|
|
956
1015
|
}
|
|
957
1016
|
|
|
1017
|
+
// --- Run module postInstall hooks ---
|
|
1018
|
+
// Modules with a `postInstall` field dispatch to a matching setup
|
|
1019
|
+
// function after templates are copied. Currently only 'verify-setup'
|
|
1020
|
+
// (the cabinet-verify tarball builder) is wired.
|
|
1021
|
+
for (const moduleKey of selectedModules) {
|
|
1022
|
+
const mod = MODULES[moduleKey];
|
|
1023
|
+
if (!mod.postInstall) continue;
|
|
1024
|
+
if (mod.postInstall === 'verify-setup') {
|
|
1025
|
+
try {
|
|
1026
|
+
console.log('');
|
|
1027
|
+
const verifyResult = setupVerifyRuntime({ dryRun: !!flags.dryRun });
|
|
1028
|
+
for (const r of verifyResult.results || []) console.log(` 📋 ${r}`);
|
|
1029
|
+
} catch (err) {
|
|
1030
|
+
console.log(` ⚠ cabinet-verify runtime setup failed: ${err.message}`);
|
|
1031
|
+
console.log(' /verify install.sh will fail until the runtime is installed.');
|
|
1032
|
+
console.log(' Re-run the installer to retry.');
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
958
1037
|
// --- Manifest key migration (act:d1f16bee) ---
|
|
959
1038
|
// When CC renames directories (e.g., perspectives/ → cabinet-*/), old manifest
|
|
960
1039
|
// keys no longer match new template paths. Migrate keys BEFORE cleanup so the
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verify-setup.js — install the cabinet-verify runtime tarball at
|
|
3
|
+
* ~/.claude-cabinet/verify/<version>/dist/.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the omega-setup.js pattern: dispatched from cli.js's install
|
|
6
|
+
* pipeline when the `verify` module is selected. Idempotent: skips if
|
|
7
|
+
* the matching-version tarball is already present.
|
|
8
|
+
*
|
|
9
|
+
* See templates/verify-runtime/CONVENTIONS.md §Install Dir and
|
|
10
|
+
* §Tarball Install Pattern for the frozen contract this implements.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { execSync } = require('child_process');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
|
|
18
|
+
const CC_HOME = path.join(os.homedir(), '.claude-cabinet');
|
|
19
|
+
const VERIFY_BASE = path.join(CC_HOME, 'verify');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Set up the cabinet-verify runtime.
|
|
23
|
+
*
|
|
24
|
+
* Steps:
|
|
25
|
+
* 1. Read the version from templates/verify-runtime/package.json
|
|
26
|
+
* 2. Compute installDir = ~/.claude-cabinet/verify/<version>/dist/
|
|
27
|
+
* 3. If a tarball already exists at that path with the same version,
|
|
28
|
+
* log "already installed" and skip
|
|
29
|
+
* 4. Otherwise: mkdir -p installDir; npm pack inside templates/verify-runtime/;
|
|
30
|
+
* move the .tgz to installDir
|
|
31
|
+
* 5. Write ~/.claude-cabinet/verify/current/VERSION (single-line pointer
|
|
32
|
+
* used by /verify install.sh per CONVENTIONS.md Version Resolution)
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} opts
|
|
35
|
+
* @param {boolean} [opts.dryRun] — print planned actions, don't execute
|
|
36
|
+
* @param {string} [opts.runtimeSourceDir] — override the templates/verify-runtime/
|
|
37
|
+
* location. Defaults to <repo>/templates/verify-runtime/ resolved from __dirname.
|
|
38
|
+
* @returns {Object} { installPath, version, status: 'installed'|'skipped'|'dry-run' }
|
|
39
|
+
*/
|
|
40
|
+
function setupVerifyRuntime(opts = {}) {
|
|
41
|
+
const dryRun = !!opts.dryRun;
|
|
42
|
+
const runtimeSourceDir =
|
|
43
|
+
opts.runtimeSourceDir || path.resolve(__dirname, '..', 'templates', 'verify-runtime');
|
|
44
|
+
|
|
45
|
+
// 1. Read version
|
|
46
|
+
const packageJsonPath = path.join(runtimeSourceDir, 'package.json');
|
|
47
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`verify-setup: ${packageJsonPath} not found. Cannot resolve cabinet-verify version.`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
53
|
+
const version = pkg.version;
|
|
54
|
+
if (typeof version !== 'string' || version.length === 0) {
|
|
55
|
+
throw new Error(`verify-setup: ${packageJsonPath} has no version field`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 2. Compute installDir
|
|
59
|
+
const installDir = path.join(VERIFY_BASE, version, 'dist');
|
|
60
|
+
const tarballName = `cabinet-verify-${version}.tgz`;
|
|
61
|
+
const tarballPath = path.join(installDir, tarballName);
|
|
62
|
+
const versionPointer = path.join(VERIFY_BASE, 'current', 'VERSION');
|
|
63
|
+
|
|
64
|
+
const results = [];
|
|
65
|
+
|
|
66
|
+
if (dryRun) {
|
|
67
|
+
results.push(`Would install cabinet-verify@${version}`);
|
|
68
|
+
results.push(` source: ${runtimeSourceDir}`);
|
|
69
|
+
results.push(` target: ${tarballPath}`);
|
|
70
|
+
results.push(` pointer: ${versionPointer}`);
|
|
71
|
+
return { installPath: installDir, version, status: 'dry-run', results };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 3. Idempotency check. Existence alone is not enough — an earlier
|
|
75
|
+
// stub-touch (e.g., a test fixture) can leave a 0-byte file at the
|
|
76
|
+
// tarball path. npm install on the consumer side then fails with
|
|
77
|
+
// ENODATA / TAR_BAD_ARCHIVE. Validate the file has non-trivial size
|
|
78
|
+
// before treating it as installed.
|
|
79
|
+
if (fs.existsSync(tarballPath) && fs.statSync(tarballPath).size > 1024) {
|
|
80
|
+
results.push(`cabinet-verify@${version} already installed (${tarballPath})`);
|
|
81
|
+
// Even on skip, ensure the VERSION pointer is up-to-date so a later
|
|
82
|
+
// version downgrade doesn't leave a stale pointer behind.
|
|
83
|
+
writeVersionPointer(versionPointer, version);
|
|
84
|
+
results.push(`Updated VERSION pointer: ${versionPointer}`);
|
|
85
|
+
return { installPath: installDir, version, status: 'skipped', results };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Remove a 0-byte stub before re-packing so the move below doesn't
|
|
89
|
+
// hit a "file exists" surprise.
|
|
90
|
+
if (fs.existsSync(tarballPath)) {
|
|
91
|
+
fs.unlinkSync(tarballPath);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 4. mkdir + npm pack + move
|
|
95
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
96
|
+
// Run npm pack in the runtime source dir. --pack-destination writes
|
|
97
|
+
// the tarball directly to installDir without an intermediate cwd move.
|
|
98
|
+
const packStdout = execSync(`npm pack --silent --pack-destination "${installDir}"`, {
|
|
99
|
+
cwd: runtimeSourceDir,
|
|
100
|
+
encoding: 'utf8',
|
|
101
|
+
}).trim();
|
|
102
|
+
|
|
103
|
+
// npm pack prints the tarball filename to stdout on the last non-empty line.
|
|
104
|
+
// Normalise to the expected name so consuming projects can rely on the
|
|
105
|
+
// CONVENTIONS.md-documented path.
|
|
106
|
+
const lastLine = packStdout.split('\n').filter(Boolean).pop() || '';
|
|
107
|
+
const producedName = path.basename(lastLine);
|
|
108
|
+
if (producedName && producedName !== tarballName) {
|
|
109
|
+
// npm pack may produce a name like 'cabinet-verify-0.1.0.tgz' that already
|
|
110
|
+
// matches; if it doesn't (e.g., npm prefixes with @scope/), rename to match.
|
|
111
|
+
const producedPath = path.join(installDir, producedName);
|
|
112
|
+
if (fs.existsSync(producedPath)) {
|
|
113
|
+
fs.renameSync(producedPath, tarballPath);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!fs.existsSync(tarballPath)) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`verify-setup: npm pack completed but ${tarballPath} not found. ` +
|
|
120
|
+
`stdout was: ${packStdout.slice(0, 500)}`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
results.push(`Installed cabinet-verify@${version} to ${tarballPath}`);
|
|
125
|
+
|
|
126
|
+
// 5. Write VERSION pointer
|
|
127
|
+
writeVersionPointer(versionPointer, version);
|
|
128
|
+
results.push(`Wrote VERSION pointer: ${versionPointer}`);
|
|
129
|
+
|
|
130
|
+
return { installPath: installDir, version, status: 'installed', results };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function writeVersionPointer(pointerPath, version) {
|
|
134
|
+
fs.mkdirSync(path.dirname(pointerPath), { recursive: true });
|
|
135
|
+
// No trailing newline — CONVENTIONS.md frozen contract requires the
|
|
136
|
+
// file to equal the version string exactly under `cat`.
|
|
137
|
+
fs.writeFileSync(pointerPath, version, 'utf8');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = { setupVerifyRuntime };
|
package/package.json
CHANGED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# /debrief integration with cabinet-verify — verify-coverage phase
|
|
2
|
+
|
|
3
|
+
**Contract: v0.x soft — may change before v1.0.** This phase enables
|
|
4
|
+
the `/verify` integration with `/debrief`. It is a customization phase
|
|
5
|
+
(opt-in), copied into your project only when the `verify` module is
|
|
6
|
+
selected during `npx create-claude-cabinet`.
|
|
7
|
+
|
|
8
|
+
## What this phase does
|
|
9
|
+
|
|
10
|
+
At session close, scan the acts shipped during the session window.
|
|
11
|
+
For each act that touched UI code, check whether a feature-file edit
|
|
12
|
+
landed in the same git commit window. If not, warn — drift risk:
|
|
13
|
+
the product changed but the scenarios didn't.
|
|
14
|
+
|
|
15
|
+
This is the safety net for the `/plan` + `/execute` integration. The
|
|
16
|
+
upstream phases TRY to keep features in sync during the session;
|
|
17
|
+
this phase catches the cases where they failed or weren't invoked.
|
|
18
|
+
|
|
19
|
+
## No-op guard
|
|
20
|
+
|
|
21
|
+
The phase should exit silently if the project has no `e2e/features/`
|
|
22
|
+
directory.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
test -d e2e/features
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Without the runtime installed, there's nothing to be out of sync with.
|
|
29
|
+
|
|
30
|
+
## When this phase runs
|
|
31
|
+
|
|
32
|
+
Position: during `/debrief`'s inventory phase, after acts have been
|
|
33
|
+
enumerated, before the briefing is presented to the user. The warning
|
|
34
|
+
appears in the **Attention Items** section of the debrief output.
|
|
35
|
+
|
|
36
|
+
## Detection algorithm
|
|
37
|
+
|
|
38
|
+
1. **Establish the session window.** The session-start git sha is
|
|
39
|
+
captured at orient (or, lacking that, the most recent commit
|
|
40
|
+
before the first session action). HEAD is the end of the window.
|
|
41
|
+
2. **List feature-file edits in the window.**
|
|
42
|
+
```bash
|
|
43
|
+
git diff --name-only <session-start-sha>..HEAD | grep '\.feature$'
|
|
44
|
+
```
|
|
45
|
+
3. **List shipped acts.** Query pib-db for actions completed during
|
|
46
|
+
the session:
|
|
47
|
+
```bash
|
|
48
|
+
node scripts/pib-db.mjs query "SELECT fid, text, notes FROM actions WHERE completed = 1 AND completed_at >= '<session-start-iso>'"
|
|
49
|
+
```
|
|
50
|
+
4. **For each shipped act, decide whether it was UI-touching.** Look
|
|
51
|
+
at the act's notes' Surface Area section. If the surface includes
|
|
52
|
+
any of:
|
|
53
|
+
- `webapp/frontend/`, `app/`, `pages/`, `components/`
|
|
54
|
+
- paths matching project-specific UI conventions (read
|
|
55
|
+
`phases/ui-paths.md` if defined; otherwise use the default
|
|
56
|
+
heuristic above)
|
|
57
|
+
|
|
58
|
+
then it's UI-touching.
|
|
59
|
+
5. **For each UI-touching act, check if any feature file in the
|
|
60
|
+
diff overlaps with the act's surface area or description.** If
|
|
61
|
+
not, the act is "uncovered."
|
|
62
|
+
|
|
63
|
+
## Warning format
|
|
64
|
+
|
|
65
|
+
For each uncovered UI act, emit one Attention Items entry:
|
|
66
|
+
|
|
67
|
+
> **Act <fid> shipped without a feature-file update — drift risk.**
|
|
68
|
+
> The act touched [paths] but no `.feature` file changed in the same
|
|
69
|
+
> session window. Consider:
|
|
70
|
+
> - `/verify update <fid>` to propose the matching scenario edits
|
|
71
|
+
> - Or accept the drift if the change isn't user-visible enough to
|
|
72
|
+
> warrant a scenario update.
|
|
73
|
+
|
|
74
|
+
Advisory only — debrief still completes. The user decides whether to
|
|
75
|
+
run `/verify update` immediately or defer.
|
|
76
|
+
|
|
77
|
+
## Tuning to reduce false positives
|
|
78
|
+
|
|
79
|
+
The default heuristic over-warns. Two common refinements:
|
|
80
|
+
|
|
81
|
+
1. **Path filter.** Project-specific UI paths in `phases/ui-paths.md`
|
|
82
|
+
(if defined) override the default heuristic. For example, a project
|
|
83
|
+
where `app/` is the framework's app dir (server-side rendering)
|
|
84
|
+
but `webapp/frontend/` is the SPA might only count the latter.
|
|
85
|
+
2. **Per-act opt-out.** An act can declare in its notes that it's a
|
|
86
|
+
"no-feature-edit-needed" act:
|
|
87
|
+
```
|
|
88
|
+
## Verify Coverage
|
|
89
|
+
Skip: this change is internal — no UI behavior changed.
|
|
90
|
+
```
|
|
91
|
+
The phase reads this and skips the act.
|
|
92
|
+
|
|
93
|
+
## What this phase does NOT do
|
|
94
|
+
|
|
95
|
+
- It does not file an action for the uncovered act. The user runs
|
|
96
|
+
`/verify update` (or chooses to ignore) at their discretion.
|
|
97
|
+
- It does not block debrief. Even with 10 uncovered acts, debrief
|
|
98
|
+
completes — the warnings just accumulate in the Attention Items
|
|
99
|
+
section.
|
|
100
|
+
- It does not run the verification suite (`npm run verify`). That's
|
|
101
|
+
the user's call after they decide whether to update scenarios.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# /execute integration with cabinet-verify — verify-emit phase
|
|
2
|
+
|
|
3
|
+
**Contract: v0.x soft — may change before v1.0.** This phase enables
|
|
4
|
+
the `/verify` integration with `/execute`. It is a customization phase
|
|
5
|
+
(opt-in), copied into your project only when the `verify` module is
|
|
6
|
+
selected during `npx create-claude-cabinet`.
|
|
7
|
+
|
|
8
|
+
## What this phase does
|
|
9
|
+
|
|
10
|
+
When `/execute` runs a plan that contains a `## Verify Plan` section,
|
|
11
|
+
this phase writes the proposed feature-file edits alongside the
|
|
12
|
+
code change in the same execution pass. The goal: feature files
|
|
13
|
+
stay in sync with the product because the edit lands in the same
|
|
14
|
+
commit as the code that motivated it.
|
|
15
|
+
|
|
16
|
+
## No-op guards
|
|
17
|
+
|
|
18
|
+
This phase will exit silently in two cases — checked in order:
|
|
19
|
+
|
|
20
|
+
1. **The loaded plan has no `## Verify Plan` section.** Most plans
|
|
21
|
+
(backend-only, refactors, deploy configs) won't have one. No warning,
|
|
22
|
+
no log line.
|
|
23
|
+
2. **The project has no `e2e/features/` directory.** Same as the
|
|
24
|
+
`/plan` integration phase — without the runtime installed, there
|
|
25
|
+
are no feature files to edit. Skip entirely.
|
|
26
|
+
|
|
27
|
+
Detection:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
test -d e2e/features
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Both guards must pass before this phase emits any output or writes
|
|
34
|
+
any files.
|
|
35
|
+
|
|
36
|
+
## When this phase runs
|
|
37
|
+
|
|
38
|
+
Position: after the file-group implementation loop, before the
|
|
39
|
+
pre-commit cabinet sweep. The order matters — feature-file edits
|
|
40
|
+
should be in the working tree when cabinet members review the full
|
|
41
|
+
diff, so a security or QA cabinet member sees that the scenarios were
|
|
42
|
+
updated alongside the code.
|
|
43
|
+
|
|
44
|
+
## How to read the Verify Plan section
|
|
45
|
+
|
|
46
|
+
Parse the plan notes for `## Verify Plan`. Each entry under the
|
|
47
|
+
heading begins with `- features/<file>.feature:` followed by a verb
|
|
48
|
+
phrase. Verbs the parser recognizes:
|
|
49
|
+
|
|
50
|
+
- `ADD step after <anchor>` — insert a new step at a specific position
|
|
51
|
+
- `MODIFY step <checkId>` — change an existing step's text
|
|
52
|
+
- `NEW scenario` — create a whole new `.feature` file
|
|
53
|
+
- `REMOVE step <checkId>` — delete a step
|
|
54
|
+
- `(deferred) <anything>` — record but don't write
|
|
55
|
+
|
|
56
|
+
For each non-deferred entry:
|
|
57
|
+
|
|
58
|
+
1. Resolve the target file. If it's `NEW scenario`, the file is the
|
|
59
|
+
one named in the entry (must not exist yet).
|
|
60
|
+
2. Apply the edit. For ADD/MODIFY/REMOVE, parse the surrounding step
|
|
61
|
+
structure to find the right insertion point. For NEW, write the
|
|
62
|
+
file using the skeleton from `templates/skills/verify/phases/scenario-template.md`.
|
|
63
|
+
3. Verify the result by re-reading the file. The pathHash of any
|
|
64
|
+
modified step changes — that's expected (per CONVENTIONS.md the
|
|
65
|
+
cache will invalidate downstream verdicts).
|
|
66
|
+
|
|
67
|
+
## AC enforcement
|
|
68
|
+
|
|
69
|
+
Each Verify Plan entry maps to an implicit acceptance criterion:
|
|
70
|
+
"the feature-file edit was written." If `/execute` finishes its
|
|
71
|
+
implementation loop but a Verify Plan edit didn't land, mark that
|
|
72
|
+
AC unmet in the verification breadcrumb.
|
|
73
|
+
|
|
74
|
+
The code change itself can still ship — Verify Plan failures are
|
|
75
|
+
acceptance failures, not blockers — but the user sees the unmet AC
|
|
76
|
+
when they review the breadcrumb. The `/debrief` integration's
|
|
77
|
+
`verify-coverage` phase catches this even if the user misses it.
|
|
78
|
+
|
|
79
|
+
## Failure handling
|
|
80
|
+
|
|
81
|
+
If a feature-file edit can't be applied (e.g., the anchor step
|
|
82
|
+
described in `ADD step after <anchor>` doesn't exist in the file):
|
|
83
|
+
|
|
84
|
+
1. Print a warning naming the file, the edit, and the reason
|
|
85
|
+
2. Mark the corresponding AC unmet in the breadcrumb's `deviations`
|
|
86
|
+
array
|
|
87
|
+
3. Continue with the next entry — don't fail the whole execute pass
|
|
88
|
+
|
|
89
|
+
The user resolves these in a follow-up `/verify update <fid>` invocation
|
|
90
|
+
after the code change lands.
|
|
91
|
+
|
|
92
|
+
## NEW scenario handling
|
|
93
|
+
|
|
94
|
+
When the entry is `NEW scenario`, the feature file must not exist
|
|
95
|
+
yet. If it does, escalate:
|
|
96
|
+
|
|
97
|
+
> Verify Plan proposes a NEW scenario at features/13-first-time-user.feature
|
|
98
|
+
> but that file already exists. Did you mean ADD step or MODIFY?
|
|
99
|
+
> Skipping this entry — fix the plan and re-run.
|
|
100
|
+
|
|
101
|
+
NEW scenarios use the scaffolding shape from `phases/scenario-template.md`
|
|
102
|
+
of `/verify`. Pull the template content and substitute the scenario
|
|
103
|
+
name, persona tag, cost tag, and a starter journey from the entry's
|
|
104
|
+
prose.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# /plan integration with cabinet-verify — verify-plan phase
|
|
2
|
+
|
|
3
|
+
**Contract: v0.x soft — may change before v1.0.** This phase enables
|
|
4
|
+
the `/verify` integration with `/plan`. It is a customization phase
|
|
5
|
+
(opt-in), copied into your project only when the `verify` module is
|
|
6
|
+
selected during `npx create-claude-cabinet`.
|
|
7
|
+
|
|
8
|
+
## What this phase does
|
|
9
|
+
|
|
10
|
+
When `/plan` produces a plan involving UI changes, emit a
|
|
11
|
+
`## Verify Plan` section that lists feature-file paths plus proposed
|
|
12
|
+
edits. `/execute` reads this section and writes the feature-file
|
|
13
|
+
edits alongside the code change, so scenarios stay in sync with the
|
|
14
|
+
product.
|
|
15
|
+
|
|
16
|
+
## No-op guard
|
|
17
|
+
|
|
18
|
+
Before doing anything, this phase checks for `e2e/features/` in the
|
|
19
|
+
project root. **If the directory is absent, exit silently** — the
|
|
20
|
+
project hasn't installed the `/verify` runtime, and emitting a
|
|
21
|
+
Verify Plan section against scenarios that don't exist would be
|
|
22
|
+
noise.
|
|
23
|
+
|
|
24
|
+
Detection:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
test -d e2e/features
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If the test fails, skip this phase entirely. No warning, no log line.
|
|
31
|
+
The user installs `/verify` when they're ready; until then, `/plan`
|
|
32
|
+
behaves as if this phase isn't here.
|
|
33
|
+
|
|
34
|
+
## When to emit a Verify Plan section
|
|
35
|
+
|
|
36
|
+
Emit the section when the plan's surface area touches UI code. The
|
|
37
|
+
specific signals depend on project conventions; common patterns:
|
|
38
|
+
|
|
39
|
+
- Modified file path matches `webapp/frontend/src/`, `app/`, `pages/`,
|
|
40
|
+
or `components/`
|
|
41
|
+
- Plan description mentions a route, a page, a modal, a UI flow
|
|
42
|
+
- Plan changes user-visible behavior (vs. internal refactor, schema
|
|
43
|
+
migration, deploy config)
|
|
44
|
+
|
|
45
|
+
If unsure, ask the user during plan drafting: "Does this plan need a
|
|
46
|
+
Verify Plan section? (y/n)". Don't auto-emit on every plan — that
|
|
47
|
+
generates noise for backend-only changes.
|
|
48
|
+
|
|
49
|
+
## Section format
|
|
50
|
+
|
|
51
|
+
The `## Verify Plan` section sits alongside the existing
|
|
52
|
+
`## Acceptance Criteria` and `## Surface Area` sections. It lists
|
|
53
|
+
feature-file paths plus proposed edits:
|
|
54
|
+
|
|
55
|
+
```markdown
|
|
56
|
+
## Verify Plan
|
|
57
|
+
|
|
58
|
+
- features/01-desktop-rewrite.feature: ADD step after the existing
|
|
59
|
+
"settings-bar-appears" check — verify the model picker is absent
|
|
60
|
+
(1.10b model-picker-absent).
|
|
61
|
+
- features/03-multi-tab.feature: MODIFY the "active-run-banner-text"
|
|
62
|
+
step to assert the new banner copy after Phase B.
|
|
63
|
+
- features/13-first-time-user.feature: NEW scenario — invite roundtrip
|
|
64
|
+
+ empty states for a freshly-signed-up user.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Edit verbs:
|
|
68
|
+
- **ADD step after `<anchor>`** — a new step inserted at a specific
|
|
69
|
+
position
|
|
70
|
+
- **MODIFY step `<checkId>`** — change an existing step's assertion
|
|
71
|
+
- **NEW scenario** — a whole new `.feature` file
|
|
72
|
+
- **REMOVE step `<checkId>`** — for deprecations
|
|
73
|
+
|
|
74
|
+
Each entry begins with `- features/<file>.feature:` so the line is
|
|
75
|
+
machine-parseable for `/execute`'s `verify-emit` phase.
|
|
76
|
+
|
|
77
|
+
## Integration with acceptance criteria
|
|
78
|
+
|
|
79
|
+
The Verify Plan section is **treated like an AC**: if `/execute`
|
|
80
|
+
fails to write the feature-file edit, the corresponding AC is marked
|
|
81
|
+
unmet. This is enforced by the `verify-emit` phase in `/execute`.
|
|
82
|
+
|
|
83
|
+
You may explicitly tag a Verify Plan entry as deferred:
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
- features/05-framework-smoke.feature: (deferred) ADD step for the
|
|
87
|
+
new framework migration banner — requires the migration to land
|
|
88
|
+
in webapp first.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Deferred entries are recorded but don't block execution.
|
|
92
|
+
|
|
93
|
+
## When the plan has no UI surface
|
|
94
|
+
|
|
95
|
+
Backend-only plans, schema migrations, and infrastructure changes
|
|
96
|
+
don't need a Verify Plan section. Emitting one for them generates
|
|
97
|
+
noise during `/execute`. Use judgment — when in doubt, ask the user.
|