continuous-improvement 3.0.0 → 3.8.0
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/.claude-plugin/marketplace.json +78 -0
- package/CHANGELOG.md +210 -0
- package/LICENSE +21 -21
- package/QUICKSTART.md +101 -81
- package/README.md +224 -198
- package/SKILL.md +87 -9
- package/action.yml +33 -0
- package/bin/analyze.sh +161 -153
- package/bin/backfill.mjs +172 -0
- package/bin/check-docs-substrings.mjs +333 -0
- package/bin/check-everything-mirror.mjs +145 -0
- package/bin/check-routing-targets.mjs +151 -0
- package/bin/check-skill-law-tag.mjs +128 -0
- package/bin/check-skill-mirror.mjs +119 -0
- package/bin/check-skill-tiers.mjs +116 -0
- package/bin/check-third-party-shape.mjs +202 -0
- package/bin/generate-plugin-manifests.mjs +169 -0
- package/bin/harvest-friction.mjs +279 -0
- package/bin/hook-stats.mjs +258 -0
- package/bin/install.mjs +418 -456
- package/bin/lint-transcript.mjs +239 -0
- package/bin/mcp-server.mjs +842 -499
- package/bin/observe.mjs +148 -0
- package/bin/pre-commit-block-strays.sh +49 -0
- package/bin/refresh-third-party.mjs +416 -0
- package/bin/unified-cli.mjs +533 -0
- package/commands/continuous-improvement.md +115 -74
- package/commands/dashboard.md +56 -0
- package/commands/discipline.md +51 -0
- package/commands/harvest.md +76 -0
- package/commands/learn-eval.md +117 -0
- package/commands/planning-with-files.md +66 -0
- package/commands/proceed-with-the-recommendation.md +62 -0
- package/commands/ralph.md +103 -0
- package/commands/release-train.md +81 -0
- package/commands/seven-laws.md +16 -0
- package/commands/superpowers.md +153 -0
- package/commands/swarm.md +101 -0
- package/commands/workspace-surface-audit.md +77 -0
- package/hooks/observe.sh +172 -134
- package/hooks/session.sh +106 -106
- package/hooks/three-section-close.mjs +181 -0
- package/instinct-packs/go.json +58 -0
- package/instinct-packs/meta.json +16 -0
- package/instinct-packs/python.json +58 -0
- package/instinct-packs/react.json +58 -0
- package/lib/cli-anything.mjs +401 -0
- package/lib/compound-engineering.mjs +831 -0
- package/lib/observe-event.mjs +128 -0
- package/lib/plugin-metadata.mjs +432 -0
- package/lib/pm-marketplace.mjs +61 -0
- package/lib/pm-skills.mjs +1274 -0
- package/lib/resolve-home-dir.mjs +43 -0
- package/lib/skill-tiers.mjs +137 -0
- package/lib/unified-plugin.mjs +924 -0
- package/llms.txt +68 -0
- package/package.json +38 -15
- package/plugins/beginner.json +17 -6
- package/plugins/continuous-improvement/.claude-plugin/marketplace.json +20 -0
- package/plugins/continuous-improvement/.claude-plugin/plugin.json +26 -0
- package/plugins/continuous-improvement/LICENSE +21 -0
- package/plugins/continuous-improvement/README.md +56 -0
- package/plugins/continuous-improvement/bin/backfill.mjs +172 -0
- package/plugins/continuous-improvement/bin/mcp-server.mjs +886 -0
- package/plugins/continuous-improvement/bin/observe.mjs +148 -0
- package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -0
- package/plugins/continuous-improvement/commands/dashboard.md +56 -0
- package/plugins/continuous-improvement/commands/discipline.md +51 -0
- package/plugins/continuous-improvement/commands/harvest.md +76 -0
- package/plugins/continuous-improvement/commands/learn-eval.md +117 -0
- package/plugins/continuous-improvement/commands/planning-with-files.md +66 -0
- package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +62 -0
- package/plugins/continuous-improvement/commands/ralph.md +103 -0
- package/plugins/continuous-improvement/commands/release-train.md +81 -0
- package/plugins/continuous-improvement/commands/seven-laws.md +16 -0
- package/plugins/continuous-improvement/commands/superpowers.md +153 -0
- package/plugins/continuous-improvement/commands/swarm.md +101 -0
- package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -0
- package/plugins/continuous-improvement/hooks/hooks.json +60 -0
- package/plugins/continuous-improvement/hooks/observe.sh +172 -0
- package/plugins/continuous-improvement/hooks/session.sh +106 -0
- package/plugins/continuous-improvement/hooks/three-section-close.mjs +181 -0
- package/plugins/continuous-improvement/instinct-packs/go.json +58 -0
- package/plugins/continuous-improvement/instinct-packs/meta.json +16 -0
- package/plugins/continuous-improvement/instinct-packs/python.json +58 -0
- package/plugins/continuous-improvement/instinct-packs/react.json +58 -0
- package/plugins/continuous-improvement/lib/observe-event.mjs +128 -0
- package/plugins/continuous-improvement/lib/plugin-metadata.mjs +432 -0
- package/plugins/continuous-improvement/lib/resolve-home-dir.mjs +43 -0
- package/plugins/continuous-improvement/skills/README.md +34 -0
- package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +249 -0
- package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +131 -0
- package/plugins/continuous-improvement/skills/gateguard/SKILL.md +155 -0
- package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +108 -0
- package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +454 -0
- package/plugins/continuous-improvement/skills/ralph/SKILL.md +221 -0
- package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +76 -0
- package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +104 -0
- package/plugins/continuous-improvement/skills/superpowers/SKILL.md +212 -0
- package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -0
- package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +136 -0
- package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +192 -0
- package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +191 -0
- package/plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md +147 -0
- package/plugins/continuous-improvement/templates/planning-with-files/findings.md +8 -0
- package/plugins/continuous-improvement/templates/planning-with-files/progress.md +7 -0
- package/plugins/continuous-improvement/templates/planning-with-files/task_plan.md +23 -0
- package/plugins/expert.json +34 -5
- package/skills/README.md +79 -0
- package/skills/deploy-receipt.md +131 -0
- package/skills/gateguard.md +155 -0
- package/skills/para-memory-files.md +108 -0
- package/skills/proceed-with-the-recommendation.md +454 -0
- package/skills/ralph.md +221 -0
- package/skills/safety-guard.md +76 -0
- package/skills/strategic-compact.md +104 -0
- package/skills/superpowers.md +212 -0
- package/skills/tdd-workflow.md +411 -0
- package/skills/token-budget-advisor.md +136 -0
- package/skills/verification-loop.md +192 -0
- package/skills/wild-risa-balance.md +191 -0
- package/skills/workspace-surface-audit.md +147 -0
- package/templates/planning-with-files/findings.md +8 -0
- package/templates/planning-with-files/progress.md +7 -0
- package/templates/planning-with-files/task_plan.md +23 -0
- package/templates/verify-ladder.example.json +47 -0
package/bin/backfill.mjs
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// backfill.mts — Tag legacy thin-schema observation rows for skip-clean
|
|
3
|
+
// consumption by the analysis pass.
|
|
4
|
+
//
|
|
5
|
+
// Walks ~/.claude/instincts/<hash>/observations.jsonl files and writes a
|
|
6
|
+
// `schema: "thin" | "rich"` field on every row that doesn't already have one.
|
|
7
|
+
// Per the plan doc: this is a flag-pass, not a content-recovery — the original
|
|
8
|
+
// thin rows lack the input we'd need to fabricate richer fields. Tagging lets
|
|
9
|
+
// the analysis pass cleanly skip thin rows and surface a "X% of observations
|
|
10
|
+
// were thin" stat to operators so they understand why their auto-instinct
|
|
11
|
+
// pipeline historically produced nothing.
|
|
12
|
+
//
|
|
13
|
+
// Output:
|
|
14
|
+
// - <home>/.claude/instincts/<hash>/observations.jsonl (rewritten in place
|
|
15
|
+
// with schema field appended; original preserved as .bak)
|
|
16
|
+
// - <home>/.claude/instincts/backfill-summary.json (per-project digest)
|
|
17
|
+
//
|
|
18
|
+
// Flags:
|
|
19
|
+
// --dry-run Read everything, write nothing; print counts to stdout.
|
|
20
|
+
//
|
|
21
|
+
// Idempotent: re-running on already-tagged rows is a no-op.
|
|
22
|
+
// Exit code: always 0. Failures land on stderr only.
|
|
23
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
24
|
+
import { homedir } from "node:os";
|
|
25
|
+
import { basename, join } from "node:path";
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
const DRY_RUN = args.includes("--dry-run");
|
|
28
|
+
const HELP = args.includes("--help") || args.includes("-h");
|
|
29
|
+
if (HELP) {
|
|
30
|
+
console.log(`
|
|
31
|
+
backfill — Tag legacy thin-schema observation rows.
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
npx continuous-improvement backfill Tag rows in place
|
|
35
|
+
npx continuous-improvement backfill --dry-run Report counts, write nothing
|
|
36
|
+
|
|
37
|
+
What it does:
|
|
38
|
+
Walks ~/.claude/instincts/<hash>/observations.jsonl files and adds a
|
|
39
|
+
schema field ("thin" or "rich") to every row that lacks one. Thin rows
|
|
40
|
+
came from the legacy bash fallback (jq missing) and have no input_summary;
|
|
41
|
+
rich rows came from the Node observer and have full tool_input.command /
|
|
42
|
+
Edit.file_path / etc.
|
|
43
|
+
|
|
44
|
+
Output:
|
|
45
|
+
- observations.jsonl rewritten in place (original kept as .bak)
|
|
46
|
+
- backfill-summary.json with per-project counts
|
|
47
|
+
|
|
48
|
+
Idempotent. Always exits 0 — failures go to stderr only.
|
|
49
|
+
`);
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
main();
|
|
53
|
+
function main() {
|
|
54
|
+
try {
|
|
55
|
+
runBackfill();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
process.stderr.write(`[backfill] ${error instanceof Error ? error.message : String(error)}\n`);
|
|
59
|
+
}
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
function runBackfill() {
|
|
63
|
+
const home = process.env.HOME || process.env.USERPROFILE || homedir();
|
|
64
|
+
const instinctsDir = join(home, ".claude", "instincts");
|
|
65
|
+
if (!existsSync(instinctsDir)) {
|
|
66
|
+
if (!DRY_RUN)
|
|
67
|
+
mkdirSync(instinctsDir, { recursive: true });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const projectDirs = listProjectDirs(instinctsDir);
|
|
71
|
+
const summary = {
|
|
72
|
+
total: 0,
|
|
73
|
+
thin: 0,
|
|
74
|
+
rich: 0,
|
|
75
|
+
projects: {},
|
|
76
|
+
generated_at: new Date().toISOString(),
|
|
77
|
+
};
|
|
78
|
+
for (const dir of projectDirs) {
|
|
79
|
+
const obsFile = join(dir, "observations.jsonl");
|
|
80
|
+
if (!existsSync(obsFile))
|
|
81
|
+
continue;
|
|
82
|
+
const projectId = basename(dir);
|
|
83
|
+
const stat = { total: 0, thin: 0, rich: 0 };
|
|
84
|
+
const newLines = [];
|
|
85
|
+
const corruptLines = [];
|
|
86
|
+
let mutated = false;
|
|
87
|
+
const raw = readFileSync(obsFile, "utf8");
|
|
88
|
+
for (const line of raw.split("\n")) {
|
|
89
|
+
const trimmed = line.trim();
|
|
90
|
+
if (trimmed.length === 0)
|
|
91
|
+
continue;
|
|
92
|
+
let row;
|
|
93
|
+
try {
|
|
94
|
+
row = JSON.parse(trimmed);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
process.stderr.write(`[backfill] skipped corrupt row in ${projectId}: ${trimmed.slice(0, 80)}\n`);
|
|
98
|
+
// Drop from main file but preserve in observations.corrupt.jsonl
|
|
99
|
+
// so the operator never silently loses data.
|
|
100
|
+
corruptLines.push(trimmed);
|
|
101
|
+
mutated = true;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
stat.total++;
|
|
105
|
+
summary.total++;
|
|
106
|
+
const previousSchema = row.schema;
|
|
107
|
+
const isRich = typeof row.input_summary === "string" && row.input_summary.length > 0;
|
|
108
|
+
const newSchema = isRich ? "rich" : "thin";
|
|
109
|
+
if (previousSchema !== newSchema) {
|
|
110
|
+
row.schema = newSchema;
|
|
111
|
+
mutated = true;
|
|
112
|
+
}
|
|
113
|
+
if (newSchema === "thin") {
|
|
114
|
+
stat.thin++;
|
|
115
|
+
summary.thin++;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
stat.rich++;
|
|
119
|
+
summary.rich++;
|
|
120
|
+
}
|
|
121
|
+
newLines.push(JSON.stringify(row));
|
|
122
|
+
}
|
|
123
|
+
summary.projects[projectId] = stat;
|
|
124
|
+
if (mutated && !DRY_RUN) {
|
|
125
|
+
// Atomic-ish write: backup → write → keep .bak for one cycle.
|
|
126
|
+
const backup = obsFile + ".bak";
|
|
127
|
+
renameSync(obsFile, backup);
|
|
128
|
+
writeFileSync(obsFile, newLines.join("\n") + "\n", "utf8");
|
|
129
|
+
if (corruptLines.length > 0) {
|
|
130
|
+
// Quarantine corrupt rows so operator data is never silently lost.
|
|
131
|
+
const corruptFile = join(dir, "observations.corrupt.jsonl");
|
|
132
|
+
const existing = existsSync(corruptFile) ? readFileSync(corruptFile, "utf8") : "";
|
|
133
|
+
writeFileSync(corruptFile, existing + corruptLines.join("\n") + "\n", "utf8");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (DRY_RUN) {
|
|
138
|
+
process.stdout.write(formatReport(summary, true));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const summaryPath = join(instinctsDir, "backfill-summary.json");
|
|
142
|
+
writeFileSync(summaryPath, JSON.stringify(summary, null, 2) + "\n", "utf8");
|
|
143
|
+
process.stdout.write(formatReport(summary, false));
|
|
144
|
+
}
|
|
145
|
+
function listProjectDirs(instinctsDir) {
|
|
146
|
+
// Real project-hash dirs are sha256[:12] (hex). Test fixtures use 12-char
|
|
147
|
+
// alpha labels (g/h/i are not hex but make tests readable). Both are
|
|
148
|
+
// matched here; the broader pattern is harmless because real instincts/
|
|
149
|
+
// sub-dirs only ever contain hex hashes plus 'global' / loose dotfiles.
|
|
150
|
+
return readdirSync(instinctsDir)
|
|
151
|
+
.filter((name) => /^[0-9a-z]{12}$/.test(name))
|
|
152
|
+
.map((name) => join(instinctsDir, name))
|
|
153
|
+
.filter((dir) => {
|
|
154
|
+
try {
|
|
155
|
+
return statSync(dir).isDirectory();
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function formatReport(summary, isDryRun) {
|
|
163
|
+
const projects = Object.keys(summary.projects);
|
|
164
|
+
const lines = [
|
|
165
|
+
isDryRun ? "[backfill --dry-run] would tag the following:" : "[backfill] tagged:",
|
|
166
|
+
` total rows: ${summary.total}`,
|
|
167
|
+
` thin rows: ${summary.thin}`,
|
|
168
|
+
` rich rows: ${summary.rich}`,
|
|
169
|
+
` projects: ${projects.length}`,
|
|
170
|
+
];
|
|
171
|
+
return lines.join("\n") + "\n";
|
|
172
|
+
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Docs Substring Check
|
|
4
|
+
*
|
|
5
|
+
* Verifies that every substring this repo's tests assert on inside a real
|
|
6
|
+
* `*.md` file is currently present in that file. Mechanical enforcement of
|
|
7
|
+
* the "Test/docs sync rule" in CONTRIBUTING.md: a wholesale docs rewrite
|
|
8
|
+
* (README.md, CHANGELOG.md, skill markdown) must preserve the substrings
|
|
9
|
+
* the test suite expects, or update the tests in the same PR.
|
|
10
|
+
*
|
|
11
|
+
* The full test suite (`npm test`) already runs each `assert.match` and
|
|
12
|
+
* fails on drift. This lint adds three things on top:
|
|
13
|
+
* 1. A focused, fast (<500ms) check that only verifies prose substrings.
|
|
14
|
+
* 2. A clean failure surface — it names (target file, expected substring,
|
|
15
|
+
* originating test) instead of dumping the full doc content into stderr.
|
|
16
|
+
* 3. A standalone CI step that fails before the broader test job has a
|
|
17
|
+
* chance to bury the drift in unrelated output.
|
|
18
|
+
*
|
|
19
|
+
* The manifest below is the spec. When you add or change a prose-substring
|
|
20
|
+
* assertion in `src/test/*.mts`, add or update the corresponding entry here
|
|
21
|
+
* in the same PR (per the Test/docs sync rule).
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* node bin/check-docs-substrings.mjs # Check the current repo
|
|
25
|
+
* node bin/check-docs-substrings.mjs <repo-root> # Check a specific repo root
|
|
26
|
+
* node bin/check-docs-substrings.mjs --list # Print the inventory and exit
|
|
27
|
+
*
|
|
28
|
+
* Exit codes:
|
|
29
|
+
* 0 — every substring matches
|
|
30
|
+
* 1 — at least one assertion failed (target file is missing or doesn't
|
|
31
|
+
* contain the expected substring)
|
|
32
|
+
*/
|
|
33
|
+
import { readFileSync } from "node:fs";
|
|
34
|
+
import { join } from "node:path";
|
|
35
|
+
import { argv, cwd, exit } from "node:process";
|
|
36
|
+
export const DOCS_ASSERTIONS = [
|
|
37
|
+
// README.md (src/test/community.test.mts)
|
|
38
|
+
{ file: "README.md", pattern: /planning-with-files/i, source: "community.test.mts:88" },
|
|
39
|
+
{ file: "README.md", pattern: /task_plan\.md/, source: "community.test.mts:89" },
|
|
40
|
+
{ file: "README.md", pattern: /ci_plan_init/, source: "community.test.mts:90" },
|
|
41
|
+
// README.md install hero — locked 2026-05-05 to prevent silent rewording of
|
|
42
|
+
// the install decision rule. The whole install section was restructured to
|
|
43
|
+
// lead with this one line because the previous "pick one path" framing left
|
|
44
|
+
// first-time installers comparison-shopping. Drop or rewrite this and
|
|
45
|
+
// beginner-vs-expert ambiguity returns immediately.
|
|
46
|
+
{ file: "README.md", pattern: "If you don't know which to pick, use Beginner.", source: "docs-substrings-manifest:readme-install-decision-rule" },
|
|
47
|
+
// CONTRIBUTING.md (src/test/community.test.mts)
|
|
48
|
+
{ file: "CONTRIBUTING.md", pattern: /Contributing/, source: "community.test.mts:16" },
|
|
49
|
+
{ file: "CONTRIBUTING.md", pattern: /npm test/, source: "community.test.mts:17" },
|
|
50
|
+
// CONTRIBUTING.md Law Coverage Matrix anchor — locked 2026-05-05. The README
|
|
51
|
+
// points to this section via #law-coverage-matrix; renaming the heading
|
|
52
|
+
// creates a silent 404 in the README link. Lint catches it.
|
|
53
|
+
{ file: "CONTRIBUTING.md", pattern: "## Law Coverage Matrix", source: "docs-substrings-manifest:contributing-law-coverage-anchor" },
|
|
54
|
+
// CODE_OF_CONDUCT.md (src/test/community.test.mts)
|
|
55
|
+
{ file: "CODE_OF_CONDUCT.md", pattern: /Code of Conduct/, source: "community.test.mts:24" },
|
|
56
|
+
{ file: "CODE_OF_CONDUCT.md", pattern: /Contributor Covenant/, source: "community.test.mts:25" },
|
|
57
|
+
// SECURITY.md (src/test/community.test.mts)
|
|
58
|
+
{ file: "SECURITY.md", pattern: /Security/, source: "community.test.mts:32" },
|
|
59
|
+
{ file: "SECURITY.md", pattern: /Reporting/i, source: "community.test.mts:33" },
|
|
60
|
+
{ file: "SECURITY.md", pattern: /Vulnerabilit/i, source: "community.test.mts:34" },
|
|
61
|
+
// .github/ISSUE_TEMPLATE/bug_report.md (src/test/community.test.mts)
|
|
62
|
+
{ file: ".github/ISSUE_TEMPLATE/bug_report.md", pattern: /Bug/, source: "community.test.mts:99" },
|
|
63
|
+
{ file: ".github/ISSUE_TEMPLATE/bug_report.md", pattern: /Steps to reproduce/, source: "community.test.mts:100" },
|
|
64
|
+
// .github/ISSUE_TEMPLATE/feature_request.md (src/test/community.test.mts)
|
|
65
|
+
{ file: ".github/ISSUE_TEMPLATE/feature_request.md", pattern: /Feature/, source: "community.test.mts:107" },
|
|
66
|
+
{ file: ".github/ISSUE_TEMPLATE/feature_request.md", pattern: /law/i, source: "community.test.mts:108" },
|
|
67
|
+
// SKILL.md (src/test/skill.test.mts)
|
|
68
|
+
{ file: "SKILL.md", pattern: /^---\r?\n/, source: "skill.test.mts:19" },
|
|
69
|
+
{ file: "SKILL.md", pattern: /name: continuous-improvement/, source: "skill.test.mts:20" },
|
|
70
|
+
{ file: "SKILL.md", pattern: /description:/, source: "skill.test.mts:21" },
|
|
71
|
+
{ file: "SKILL.md", pattern: /Law 1.*Research Before Executing/s, source: "skill.test.mts:25" },
|
|
72
|
+
{ file: "SKILL.md", pattern: /Law 2.*Plan Is Sacred/s, source: "skill.test.mts:26" },
|
|
73
|
+
{ file: "SKILL.md", pattern: /Law 3.*One Thing at a Time/s, source: "skill.test.mts:27" },
|
|
74
|
+
{ file: "SKILL.md", pattern: /Law 4.*Verify Before Reporting/s, source: "skill.test.mts:28" },
|
|
75
|
+
{ file: "SKILL.md", pattern: /Law 5.*Reflect After/s, source: "skill.test.mts:29" },
|
|
76
|
+
{ file: "SKILL.md", pattern: /Law 6.*Iterate/s, source: "skill.test.mts:30" },
|
|
77
|
+
{ file: "SKILL.md", pattern: /Law 7.*Learn From Every Session/s, source: "skill.test.mts:31" },
|
|
78
|
+
{ file: "SKILL.md", pattern: /Research.*Plan.*Execute.*Verify.*Reflect.*Learn.*Iterate/s, source: "skill.test.mts:36" },
|
|
79
|
+
{ file: "SKILL.md", pattern: /Mulahazah/i, source: "skill.test.mts:42" },
|
|
80
|
+
{ file: "SKILL.md", pattern: /confidence/i, source: "skill.test.mts:43" },
|
|
81
|
+
{ file: "SKILL.md", pattern: /Auto-Level/i, source: "skill.test.mts:44" },
|
|
82
|
+
{ file: "SKILL.md", pattern: /id:/, source: "skill.test.mts:48" },
|
|
83
|
+
{ file: "SKILL.md", pattern: /trigger:/, source: "skill.test.mts:49" },
|
|
84
|
+
{ file: "SKILL.md", pattern: /confidence:/, source: "skill.test.mts:50" },
|
|
85
|
+
{ file: "SKILL.md", pattern: /Planning-With-Files/i, source: "skill.test.mts:54" },
|
|
86
|
+
{ file: "SKILL.md", pattern: /opt-in/i, source: "skill.test.mts:55" },
|
|
87
|
+
{ file: "SKILL.md", pattern: /task_plan\.md/, source: "skill.test.mts:56" },
|
|
88
|
+
// commands/discipline.md (src/test/commands.test.mts)
|
|
89
|
+
{ file: "commands/discipline.md", pattern: /^---\r?\n/, source: "commands.test.mts:20" },
|
|
90
|
+
{ file: "commands/discipline.md", pattern: /name: discipline/, source: "commands.test.mts:21" },
|
|
91
|
+
{ file: "commands/discipline.md", pattern: /description:/, source: "commands.test.mts:22" },
|
|
92
|
+
{ file: "commands/discipline.md", pattern: /Research Before Executing/, source: "commands.test.mts:26" },
|
|
93
|
+
{ file: "commands/discipline.md", pattern: /Plan Is Sacred/, source: "commands.test.mts:27" },
|
|
94
|
+
{ file: "commands/discipline.md", pattern: /One Thing at a Time/, source: "commands.test.mts:28" },
|
|
95
|
+
{ file: "commands/discipline.md", pattern: /Verify Before Reporting/, source: "commands.test.mts:29" },
|
|
96
|
+
{ file: "commands/discipline.md", pattern: /Reflect After Sessions/, source: "commands.test.mts:30" },
|
|
97
|
+
{ file: "commands/discipline.md", pattern: /Iterate One Change/, source: "commands.test.mts:31" },
|
|
98
|
+
{ file: "commands/discipline.md", pattern: /Learn From Every Session/, source: "commands.test.mts:32" },
|
|
99
|
+
{ file: "commands/discipline.md", pattern: /I'll just quickly/, source: "commands.test.mts:36" },
|
|
100
|
+
{ file: "commands/discipline.md", pattern: /This should work/, source: "commands.test.mts:37" },
|
|
101
|
+
{ file: "commands/discipline.md", pattern: /Code runs without errors/, source: "commands.test.mts:41" },
|
|
102
|
+
{ file: "commands/discipline.md", pattern: /Build passes/, source: "commands.test.mts:42" },
|
|
103
|
+
// commands/dashboard.md (src/test/commands.test.mts)
|
|
104
|
+
{ file: "commands/dashboard.md", pattern: /^---\r?\n/, source: "commands.test.mts:56" },
|
|
105
|
+
{ file: "commands/dashboard.md", pattern: /name: dashboard/, source: "commands.test.mts:57" },
|
|
106
|
+
{ file: "commands/dashboard.md", pattern: /Dashboard/, source: "commands.test.mts:61" },
|
|
107
|
+
{ file: "commands/dashboard.md", pattern: /Observations/, source: "commands.test.mts:62" },
|
|
108
|
+
{ file: "commands/dashboard.md", pattern: /Instincts/, source: "commands.test.mts:63" },
|
|
109
|
+
{ file: "commands/dashboard.md", pattern: /Health/, source: "commands.test.mts:64" },
|
|
110
|
+
{ file: "commands/dashboard.md", pattern: /CAPTURE/, source: "commands.test.mts:68" },
|
|
111
|
+
{ file: "commands/dashboard.md", pattern: /ANALYZE/, source: "commands.test.mts:69" },
|
|
112
|
+
{ file: "commands/dashboard.md", pattern: /beginner|expert/, source: "commands.test.mts:70" },
|
|
113
|
+
// commands/planning-with-files.md (src/test/commands.test.mts)
|
|
114
|
+
{ file: "commands/planning-with-files.md", pattern: /^---\r?\n/, source: "commands.test.mts:91" },
|
|
115
|
+
{ file: "commands/planning-with-files.md", pattern: /name: planning-with-files/, source: "commands.test.mts:92" },
|
|
116
|
+
{ file: "commands/planning-with-files.md", pattern: /description:/, source: "commands.test.mts:93" },
|
|
117
|
+
{ file: "commands/planning-with-files.md", pattern: /task_plan\.md/, source: "commands.test.mts:97" },
|
|
118
|
+
{ file: "commands/planning-with-files.md", pattern: /findings\.md/, source: "commands.test.mts:98" },
|
|
119
|
+
{ file: "commands/planning-with-files.md", pattern: /progress\.md/, source: "commands.test.mts:99" },
|
|
120
|
+
{ file: "commands/planning-with-files.md", pattern: /init/i, source: "commands.test.mts:100" },
|
|
121
|
+
{ file: "commands/planning-with-files.md", pattern: /status/i, source: "commands.test.mts:101" },
|
|
122
|
+
{ file: "commands/planning-with-files.md", pattern: /checkpoint/i, source: "commands.test.mts:102" },
|
|
123
|
+
{ file: "commands/planning-with-files.md", pattern: /recover/i, source: "commands.test.mts:103" },
|
|
124
|
+
// Reflection-block mirror files (src/test/reflection-iteration-field.test.mts)
|
|
125
|
+
// Each must contain the literal "Iteration — Next best recommendations (ranked, top 3)" string.
|
|
126
|
+
{ file: "SKILL.md", pattern: "Iteration — Next best recommendations (ranked, top 3)", source: "reflection-iteration-field.test.mts:43" },
|
|
127
|
+
{ file: "commands/continuous-improvement.md", pattern: "Iteration — Next best recommendations (ranked, top 3)", source: "reflection-iteration-field.test.mts:43" },
|
|
128
|
+
{ file: "plugins/continuous-improvement/skills/continuous-improvement/SKILL.md", pattern: "Iteration — Next best recommendations (ranked, top 3)", source: "reflection-iteration-field.test.mts:43" },
|
|
129
|
+
{ file: "plugins/continuous-improvement/commands/continuous-improvement.md", pattern: "Iteration — Next best recommendations (ranked, top 3)", source: "reflection-iteration-field.test.mts:43" },
|
|
130
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "Iteration — Next best recommendations (ranked, top 3)", source: "reflection-iteration-field.test.mts:43" },
|
|
131
|
+
// Past Mistake Acknowledgment Gate / P-MAG (src/test/past-mistake-gate.test.mts)
|
|
132
|
+
// Source skill + plugin mirror must both contain the Phase 0 heading, the negative-prompt field marker,
|
|
133
|
+
// and the Stop Conditions clearance bullet. Dropping any of the three silently removes part of the gate.
|
|
134
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "Phase 0: Acknowledge (Past Mistake Acknowledgment Gate / P-MAG)", source: "past-mistake-gate.test.mts" },
|
|
135
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "Phase 0: Acknowledge (Past Mistake Acknowledgment Gate / P-MAG)", source: "past-mistake-gate.test.mts" },
|
|
136
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "Will NOT repeat:", source: "past-mistake-gate.test.mts" },
|
|
137
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "Will NOT repeat:", source: "past-mistake-gate.test.mts" },
|
|
138
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "Prior-mistake residue still present", source: "past-mistake-gate.test.mts" },
|
|
139
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "Prior-mistake residue still present", source: "past-mistake-gate.test.mts" },
|
|
140
|
+
// P-MAG third surface (auto-memory feedback_*.md) — locked 2026-05-07 after PR #83.
|
|
141
|
+
// Rule 1 of Phase 0 was upgraded from scanning two surfaces to scanning three so
|
|
142
|
+
// the operator's named past-mistake corrections (which live in
|
|
143
|
+
// ~/.claude/projects/<hash>/memory/feedback_*.md) cannot be silently skipped.
|
|
144
|
+
// Each assertion below catches a specific class of regression:
|
|
145
|
+
// - "Scan three surfaces" → reverting the surface count back to two
|
|
146
|
+
// - "memory/feedback_*.md" → dropping the glob pattern entirely
|
|
147
|
+
// - "feedback_past_mistake_gate.md" → generic rewording that loses the concrete anchor
|
|
148
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "Scan three surfaces", source: "past-mistake-gate.test.mts" },
|
|
149
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "Scan three surfaces", source: "past-mistake-gate.test.mts" },
|
|
150
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "memory/feedback_*.md", source: "past-mistake-gate.test.mts" },
|
|
151
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "memory/feedback_*.md", source: "past-mistake-gate.test.mts" },
|
|
152
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "feedback_past_mistake_gate.md", source: "past-mistake-gate.test.mts" },
|
|
153
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "feedback_past_mistake_gate.md", source: "past-mistake-gate.test.mts" },
|
|
154
|
+
// workspace-surface-audit Environment Grain — locked 2026-05-07 (PR A of second-release train).
|
|
155
|
+
// Phase 1 of the audit gained an Environment Grain subsection that records shell flavor,
|
|
156
|
+
// autocrlf state, jq availability, case-sensitive filesystem flag, CWD baseline, and a
|
|
157
|
+
// parallel-actor expectation flag — the per-host facts that root the report's
|
|
158
|
+
// "command failed / wrong approach" friction class. Each assertion catches a specific
|
|
159
|
+
// class of regression:
|
|
160
|
+
// - "#### Environment Grain" → removing the whole subsection
|
|
161
|
+
// - "core.autocrlf" → dropping the Windows-line-endings probe
|
|
162
|
+
// - "Parallel-actor expectation" → losing the cross-skill integration with gateguard PR #83
|
|
163
|
+
{ file: "skills/workspace-surface-audit.md", pattern: "#### Environment Grain", source: "docs-substrings-manifest:workspace-surface-audit-environment-grain" },
|
|
164
|
+
{ file: "plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md", pattern: "#### Environment Grain", source: "docs-substrings-manifest:workspace-surface-audit-environment-grain" },
|
|
165
|
+
{ file: "skills/workspace-surface-audit.md", pattern: "core.autocrlf", source: "docs-substrings-manifest:workspace-surface-audit-environment-grain" },
|
|
166
|
+
{ file: "plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md", pattern: "core.autocrlf", source: "docs-substrings-manifest:workspace-surface-audit-environment-grain" },
|
|
167
|
+
{ file: "skills/workspace-surface-audit.md", pattern: "Parallel-actor expectation", source: "docs-substrings-manifest:workspace-surface-audit-environment-grain" },
|
|
168
|
+
{ file: "plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md", pattern: "Parallel-actor expectation", source: "docs-substrings-manifest:workspace-surface-audit-environment-grain" },
|
|
169
|
+
// superpowers Stacked-PR Plan Precondition — locked 2026-05-07 (PR B of second-release train).
|
|
170
|
+
// The dispatcher gained a non-negotiable rule for ≥3-file changes: produce a stacked-PR plan
|
|
171
|
+
// (per-PR table, dependency graph, worktree-per-PR, out-of-scope) before the first edit. The
|
|
172
|
+
// rule excludes markdown-only / lockfile-only / generated-only / vendor-refresh / skill-mirror
|
|
173
|
+
// changes. Each assertion below catches a specific class of regression:
|
|
174
|
+
// - "## Stacked-PR Plan Precondition (≥3 files)" → removing the whole rule heading
|
|
175
|
+
// - "Per-PR table" → losing the required-output enumeration
|
|
176
|
+
{ file: "skills/superpowers.md", pattern: "## Stacked-PR Plan Precondition (≥3 files)", source: "docs-substrings-manifest:superpowers-stacked-pr-precondition" },
|
|
177
|
+
{ file: "plugins/continuous-improvement/skills/superpowers/SKILL.md", pattern: "## Stacked-PR Plan Precondition (≥3 files)", source: "docs-substrings-manifest:superpowers-stacked-pr-precondition" },
|
|
178
|
+
{ file: "skills/superpowers.md", pattern: "Per-PR table", source: "docs-substrings-manifest:superpowers-stacked-pr-precondition" },
|
|
179
|
+
{ file: "plugins/continuous-improvement/skills/superpowers/SKILL.md", pattern: "Per-PR table", source: "docs-substrings-manifest:superpowers-stacked-pr-precondition" },
|
|
180
|
+
// verification-loop per-project ladder — locked 2026-05-07 (PR C of second-release train).
|
|
181
|
+
// Phase 0 (Ladder Resolution) was added so Phases 1–6 read the project's actual build/typecheck/
|
|
182
|
+
// lint/test/security/deploy_receipt invocations from .claude/verify-ladder.json (or sniff /
|
|
183
|
+
// ask fallback) instead of hardcoded npm run X. Phase 8 wires deploy-receipt (PR #83) for
|
|
184
|
+
// auto-deploy projects. Each assertion below catches a specific class of regression:
|
|
185
|
+
// - "### Phase 0: Resolve the Ladder" → removing the whole resolution phase
|
|
186
|
+
// - ".claude/verify-ladder.json" → renaming or moving the manifest path
|
|
187
|
+
// - "verify-ladder (resolved):" → losing the resolved-ladder output contract
|
|
188
|
+
// - "### Phase 8: Deploy Receipt" → losing the cross-skill integration with PR #83
|
|
189
|
+
{ file: "skills/verification-loop.md", pattern: "### Phase 0: Resolve the Ladder", source: "docs-substrings-manifest:verification-loop-per-project-ladder" },
|
|
190
|
+
{ file: "plugins/continuous-improvement/skills/verification-loop/SKILL.md", pattern: "### Phase 0: Resolve the Ladder", source: "docs-substrings-manifest:verification-loop-per-project-ladder" },
|
|
191
|
+
{ file: "skills/verification-loop.md", pattern: ".claude/verify-ladder.json", source: "docs-substrings-manifest:verification-loop-per-project-ladder" },
|
|
192
|
+
{ file: "plugins/continuous-improvement/skills/verification-loop/SKILL.md", pattern: ".claude/verify-ladder.json", source: "docs-substrings-manifest:verification-loop-per-project-ladder" },
|
|
193
|
+
{ file: "skills/verification-loop.md", pattern: "verify-ladder (resolved):", source: "docs-substrings-manifest:verification-loop-per-project-ladder" },
|
|
194
|
+
{ file: "plugins/continuous-improvement/skills/verification-loop/SKILL.md", pattern: "verify-ladder (resolved):", source: "docs-substrings-manifest:verification-loop-per-project-ladder" },
|
|
195
|
+
{ file: "skills/verification-loop.md", pattern: "### Phase 8: Deploy Receipt", source: "docs-substrings-manifest:verification-loop-per-project-ladder" },
|
|
196
|
+
{ file: "plugins/continuous-improvement/skills/verification-loop/SKILL.md", pattern: "### Phase 8: Deploy Receipt", source: "docs-substrings-manifest:verification-loop-per-project-ladder" },
|
|
197
|
+
// /harvest slash command + Law-7 prose — locked 2026-05-07 (PR E, follow-up to PR D #88).
|
|
198
|
+
// The deferred follow-up landed: commands/harvest.md (+ plugin mirror) and a Friction Harvest
|
|
199
|
+
// Pipeline subsection inside SKILL.md Law 7 (+ plugin mirror). Each assertion below catches
|
|
200
|
+
// a specific class of regression:
|
|
201
|
+
// - "name: harvest" frontmatter → renaming the slash command
|
|
202
|
+
// - "Friction Harvest Pipeline" → losing the SKILL.md Law-7 subsection title
|
|
203
|
+
// - "dedup_key = sha1(type + tool" → losing the idempotency contract documentation
|
|
204
|
+
{ file: "commands/harvest.md", pattern: "name: harvest", source: "docs-substrings-manifest:harvest-slash-command-and-law7-prose" },
|
|
205
|
+
{ file: "plugins/continuous-improvement/commands/harvest.md", pattern: "name: harvest", source: "docs-substrings-manifest:harvest-slash-command-and-law7-prose" },
|
|
206
|
+
{ file: "SKILL.md", pattern: "Friction Harvest Pipeline", source: "docs-substrings-manifest:harvest-slash-command-and-law7-prose" },
|
|
207
|
+
{ file: "plugins/continuous-improvement/skills/continuous-improvement/SKILL.md", pattern: "Friction Harvest Pipeline", source: "docs-substrings-manifest:harvest-slash-command-and-law7-prose" },
|
|
208
|
+
{ file: "SKILL.md", pattern: "dedup_key = sha1(type + tool", source: "docs-substrings-manifest:harvest-slash-command-and-law7-prose" },
|
|
209
|
+
{ file: "plugins/continuous-improvement/skills/continuous-improvement/SKILL.md", pattern: "dedup_key = sha1(type + tool", source: "docs-substrings-manifest:harvest-slash-command-and-law7-prose" },
|
|
210
|
+
// wild-risa-balance recommendation floor (src/test/wild-risa-floor.test.mts)
|
|
211
|
+
// Source skill + plugin mirror must both contain the literal "2 WILD + 5 RISA = 7 items minimum".
|
|
212
|
+
{ file: "skills/wild-risa-balance.md", pattern: "2 WILD + 5 RISA = 7 items minimum", source: "wild-risa-floor.test.mts:38" },
|
|
213
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "2 WILD + 5 RISA = 7 items minimum", source: "wild-risa-floor.test.mts:38" },
|
|
214
|
+
// wild-risa-balance audience tiers (src/test/wild-risa-tiers.test.mts)
|
|
215
|
+
// Source + plugin mirror must contain the tier headings, item-count rule, and model-version lock.
|
|
216
|
+
// Dropping any one downgrades the tier contract back to a flat expert-only block.
|
|
217
|
+
{ file: "skills/wild-risa-balance.md", pattern: "## Audience Tiers (beginner vs expert)", source: "wild-risa-tiers.test.mts" },
|
|
218
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "## Audience Tiers (beginner vs expert)", source: "wild-risa-tiers.test.mts" },
|
|
219
|
+
{ file: "skills/wild-risa-balance.md", pattern: "### Beginner tier (lite shape)", source: "wild-risa-tiers.test.mts" },
|
|
220
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "### Beginner tier (lite shape)", source: "wild-risa-tiers.test.mts" },
|
|
221
|
+
{ file: "skills/wild-risa-balance.md", pattern: "### Expert tier", source: "wild-risa-tiers.test.mts" },
|
|
222
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "### Expert tier", source: "wild-risa-tiers.test.mts" },
|
|
223
|
+
{ file: "skills/wild-risa-balance.md", pattern: "### Tier signal in the 3-section close", source: "wild-risa-tiers.test.mts" },
|
|
224
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "### Tier signal in the 3-section close", source: "wild-risa-tiers.test.mts" },
|
|
225
|
+
{ file: "skills/wild-risa-balance.md", pattern: "3 minimum, 5 maximum", source: "wild-risa-tiers.test.mts" },
|
|
226
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "3 minimum, 5 maximum", source: "wild-risa-tiers.test.mts" },
|
|
227
|
+
{ file: "skills/wild-risa-balance.md", pattern: "Opus 4.7", source: "wild-risa-tiers.test.mts" },
|
|
228
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "Opus 4.7", source: "wild-risa-tiers.test.mts" },
|
|
229
|
+
// wild-risa-balance "no" escape valve (src/test/wild-risa-tiers.test.mts)
|
|
230
|
+
// Both tiers must allow `Recommendation: no` when no real recommendation exists; padding to hit
|
|
231
|
+
// the floor is the failure mode. Heading + literal phrase + handoff-action clause are locked.
|
|
232
|
+
{ file: "skills/wild-risa-balance.md", pattern: `### The "no" escape valve (both tiers)`, source: "wild-risa-tiers.test.mts" },
|
|
233
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: `### The "no" escape valve (both tiers)`, source: "wild-risa-tiers.test.mts" },
|
|
234
|
+
{ file: "skills/wild-risa-balance.md", pattern: "Recommendation: no", source: "wild-risa-tiers.test.mts" },
|
|
235
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "Recommendation: no", source: "wild-risa-tiers.test.mts" },
|
|
236
|
+
{ file: "skills/wild-risa-balance.md", pattern: "switch context", source: "wild-risa-tiers.test.mts" },
|
|
237
|
+
{ file: "plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md", pattern: "switch context", source: "wild-risa-tiers.test.mts" },
|
|
238
|
+
// proceed-with-the-recommendation tier-aware contract (src/test/wild-risa-tiers.test.mts)
|
|
239
|
+
// Phase 1 must accept beginner blocks (3..5 unlabeled); Phase 7 close must render the tier suffix.
|
|
240
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "Beginner tier:**", source: "wild-risa-tiers.test.mts" },
|
|
241
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "Beginner tier:**", source: "wild-risa-tiers.test.mts" },
|
|
242
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "3 ≤ n ≤ 5", source: "wild-risa-tiers.test.mts" },
|
|
243
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "3 ≤ n ≤ 5", source: "wild-risa-tiers.test.mts" },
|
|
244
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "Tier signal in the heading", source: "wild-risa-tiers.test.mts" },
|
|
245
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "Tier signal in the heading", source: "wild-risa-tiers.test.mts" },
|
|
246
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "## Recommendation (expert)", source: "wild-risa-tiers.test.mts" },
|
|
247
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "## Recommendation (expert)", source: "wild-risa-tiers.test.mts" },
|
|
248
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "## Recommendation (beginner)", source: "wild-risa-tiers.test.mts" },
|
|
249
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "## Recommendation (beginner)", source: "wild-risa-tiers.test.mts" },
|
|
250
|
+
// proceed-with-the-recommendation "no" escape valve in Phase 7 close (src/test/wild-risa-tiers.test.mts)
|
|
251
|
+
// Phase 7 must instruct renderer to ship `no` + the tier-suffixed heading when the surface is exhausted.
|
|
252
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: `The "no" escape valve (both tiers)`, source: "wild-risa-tiers.test.mts" },
|
|
253
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: `The "no" escape valve (both tiers)`, source: "wild-risa-tiers.test.mts" },
|
|
254
|
+
{ file: "skills/proceed-with-the-recommendation.md", pattern: "explicit handoff signal", source: "wild-risa-tiers.test.mts" },
|
|
255
|
+
{ file: "plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md", pattern: "explicit handoff signal", source: "wild-risa-tiers.test.mts" },
|
|
256
|
+
];
|
|
257
|
+
export function checkAssertions(repoRoot, assertions = DOCS_ASSERTIONS) {
|
|
258
|
+
const fileCache = new Map();
|
|
259
|
+
const failures = [];
|
|
260
|
+
for (const a of assertions) {
|
|
261
|
+
const fullPath = join(repoRoot, a.file);
|
|
262
|
+
let content = fileCache.get(fullPath);
|
|
263
|
+
if (content === undefined) {
|
|
264
|
+
try {
|
|
265
|
+
content = readFileSync(fullPath, "utf8");
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
content = null;
|
|
269
|
+
}
|
|
270
|
+
fileCache.set(fullPath, content);
|
|
271
|
+
}
|
|
272
|
+
if (content === null) {
|
|
273
|
+
failures.push({ assertion: a, reason: "target-missing" });
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const matched = typeof a.pattern === "string"
|
|
277
|
+
? content.includes(a.pattern)
|
|
278
|
+
: a.pattern.test(content);
|
|
279
|
+
if (!matched) {
|
|
280
|
+
failures.push({ assertion: a, reason: "pattern-not-found" });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return failures;
|
|
284
|
+
}
|
|
285
|
+
function describePattern(p) {
|
|
286
|
+
return typeof p === "string" ? `"${p}"` : p.toString();
|
|
287
|
+
}
|
|
288
|
+
function printList() {
|
|
289
|
+
const grouped = new Map();
|
|
290
|
+
for (const a of DOCS_ASSERTIONS) {
|
|
291
|
+
const list = grouped.get(a.file) ?? [];
|
|
292
|
+
list.push(a);
|
|
293
|
+
grouped.set(a.file, list);
|
|
294
|
+
}
|
|
295
|
+
console.log(`docs-substrings inventory (${DOCS_ASSERTIONS.length} assertions across ${grouped.size} files):\n`);
|
|
296
|
+
const files = [...grouped.keys()].sort();
|
|
297
|
+
for (const f of files) {
|
|
298
|
+
const items = grouped.get(f);
|
|
299
|
+
console.log(` ${f} (${items.length})`);
|
|
300
|
+
for (const a of items) {
|
|
301
|
+
console.log(` - ${describePattern(a.pattern)} [${a.source}]`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function main() {
|
|
306
|
+
const args = argv.slice(2);
|
|
307
|
+
if (args.includes("--list")) {
|
|
308
|
+
printList();
|
|
309
|
+
exit(0);
|
|
310
|
+
}
|
|
311
|
+
const repoRoot = args[0] ?? cwd();
|
|
312
|
+
const failures = checkAssertions(repoRoot);
|
|
313
|
+
if (failures.length === 0) {
|
|
314
|
+
console.log(`OK docs-substrings: all ${DOCS_ASSERTIONS.length} substring assertion(s) match their target files.`);
|
|
315
|
+
exit(0);
|
|
316
|
+
}
|
|
317
|
+
console.error(`FAIL docs-substrings: ${failures.length} of ${DOCS_ASSERTIONS.length} assertion(s) failed.\n`);
|
|
318
|
+
for (const f of failures) {
|
|
319
|
+
const a = f.assertion;
|
|
320
|
+
if (f.reason === "target-missing") {
|
|
321
|
+
console.error(` - ${a.file}: target file not found (asserted by ${a.source}).`);
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
console.error(` - ${a.file}: missing expected substring ${describePattern(a.pattern)} (asserted by ${a.source}).`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
console.error("\nFix per CONTRIBUTING.md \"Test/docs sync rule\": tests asserting on prose content must ship in the same PR as the docs change adding the asserted substring. A wholesale docs rewrite must preserve every existing substring — or update the test in the same PR.");
|
|
328
|
+
exit(1);
|
|
329
|
+
}
|
|
330
|
+
const invokedDirectly = argv[1]?.endsWith("check-docs-substrings.mjs");
|
|
331
|
+
if (invokedDirectly) {
|
|
332
|
+
main();
|
|
333
|
+
}
|