@esneiderbravo/speclaw 0.3.3 → 0.3.5
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 +54 -1
- package/dist/cli/commands/budget.js +36 -0
- package/dist/cli/commands/doctor.js +11 -1
- package/dist/cli/commands/init.js +3 -1
- package/dist/cli/commands/update.js +30 -3
- package/dist/cli/commands/verify.js +118 -0
- package/dist/cli/index.js +14 -3
- package/dist/modules/compass/indexer.js +9 -0
- package/dist/modules/compass/map.js +114 -0
- package/dist/modules/compass/register.js +30 -64
- package/dist/modules/foundation/assets/docs/compass.template.md +3 -0
- package/dist/modules/foundation/assets/laws/laws-manifest.json +49 -0
- package/dist/modules/foundation/assets/workflows/speclaw.yml +26 -0
- package/dist/modules/foundation/ci.js +41 -0
- package/dist/modules/foundation/context-budget.js +45 -0
- package/dist/modules/foundation/deps.js +1 -1
- package/dist/modules/foundation/doctor.js +9 -0
- package/dist/modules/foundation/graph.js +1 -1
- package/dist/modules/foundation/laws.js +28 -0
- package/dist/modules/foundation/register.js +71 -120
- package/dist/modules/foundation/report-md.js +33 -0
- package/dist/modules/foundation/sarif.js +96 -0
- package/dist/modules/foundation/scaffold.js +32 -12
- package/dist/modules/foundation/verify-model.js +14 -0
- package/dist/modules/foundation/verify.js +16 -17
- package/dist/modules/lawbook/assets/skills/archive/SKILL.md +1 -31
- package/dist/modules/lawbook/assets/skills/archive/steps/01-confirm-done.md +7 -0
- package/dist/modules/lawbook/assets/skills/archive/steps/02-reconcile.md +15 -0
- package/dist/modules/lawbook/assets/skills/archive/steps/03-validate-and-sync.md +7 -0
- package/dist/modules/lawbook/assets/skills/archive/steps/04-archive.md +9 -0
- package/dist/modules/lawbook/assets/skills/archive/steps/05-report.md +7 -0
- package/dist/modules/lawbook/assets/skills/build/SKILL.md +2 -100
- package/dist/modules/lawbook/assets/skills/build/steps/01-load-change.md +7 -0
- package/dist/modules/lawbook/assets/skills/build/steps/02-branch.md +6 -0
- package/dist/modules/lawbook/assets/skills/build/steps/03-implement.md +11 -0
- package/dist/modules/lawbook/assets/skills/build/steps/04-quality-gates.md +10 -0
- package/dist/modules/lawbook/assets/skills/build/steps/05-manual-verification.md +22 -0
- package/dist/modules/lawbook/assets/skills/build/steps/06-discipline-reports.md +44 -0
- package/dist/modules/lawbook/assets/skills/build/steps/07-hand-off.md +9 -0
- package/dist/modules/lawbook/assets/skills/draft/SKILL.md +3 -80
- package/dist/modules/lawbook/assets/skills/draft/steps/01-ensure-workspace.md +5 -0
- package/dist/modules/lawbook/assets/skills/draft/steps/02-understand.md +12 -0
- package/dist/modules/lawbook/assets/skills/draft/steps/03-name-capabilities.md +14 -0
- package/dist/modules/lawbook/assets/skills/draft/steps/04-write-artifacts.md +41 -0
- package/dist/modules/lawbook/assets/skills/draft/steps/05-validate.md +11 -0
- package/dist/modules/lawbook/assets/skills/draft/steps/06-hand-off.md +5 -0
- package/dist/modules/lawbook/assets/skills/explore/SKILL.md +6 -22
- package/dist/modules/lawbook/assets/skills/explore/steps/01-investigate.md +16 -0
- package/dist/modules/lawbook/assets/skills/explore/steps/02-summarize.md +7 -0
- package/dist/modules/lawbook/assets/skills/sync/SKILL.md +1 -30
- package/dist/modules/lawbook/assets/skills/sync/steps/01-confirm.md +5 -0
- package/dist/modules/lawbook/assets/skills/sync/steps/02-reconcile.md +16 -0
- package/dist/modules/lawbook/assets/skills/sync/steps/03-validate.md +6 -0
- package/dist/modules/lawbook/assets/skills/sync/steps/04-promote.md +10 -0
- package/dist/modules/lawbook/assets/skills/sync/steps/05-report.md +7 -0
- package/dist/modules/lawbook/register.js +17 -36
- package/dist/modules/tools/register.js +15 -15
- package/dist/server.js +13 -7
- package/dist/shared/budget.js +159 -0
- package/dist/shared/exposure.js +110 -0
- package/dist/shared/git.js +49 -0
- package/dist/shared/manifest.js +11 -2
- package/dist/shared/mcp.js +33 -0
- package/dist/shared/schema-tokens.js +86 -0
- package/dist/shared/tokens.js +41 -0
- package/package.json +2 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { fingerprint } from "./ci.js";
|
|
2
|
+
/** GitHub Code Scanning rejects a run with more than this many results. */
|
|
3
|
+
export const SARIF_RESULT_CAP = 5000;
|
|
4
|
+
function toSarifLevel(s) {
|
|
5
|
+
if (s === "error")
|
|
6
|
+
return "error";
|
|
7
|
+
if (s === "warn")
|
|
8
|
+
return "warning";
|
|
9
|
+
return "note";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A project-relative POSIX URI. Absolute paths (Unix `/…` or Windows `C:\…`)
|
|
13
|
+
* make GitHub drop the annotation; never emit them.
|
|
14
|
+
*
|
|
15
|
+
* @param file - A finding's `file` field (already project-relative POSIX).
|
|
16
|
+
*/
|
|
17
|
+
export function toRepoRelativeUri(file) {
|
|
18
|
+
return file
|
|
19
|
+
.replace(/\\/g, "/")
|
|
20
|
+
.replace(/^[A-Za-z]:/, "")
|
|
21
|
+
.replace(/^\/+/, "");
|
|
22
|
+
}
|
|
23
|
+
const SEVERITY_ORDER = { error: 0, warn: 1, info: 2 };
|
|
24
|
+
/**
|
|
25
|
+
* Project a {@link VerifyReport} to SARIF 2.1.0. One `rule` per loaded law
|
|
26
|
+
* (so GitHub groups alerts by law id); results truncated to
|
|
27
|
+
* {@link SARIF_RESULT_CAP} by severity; skipped laws become
|
|
28
|
+
* `toolExecutionNotifications`.
|
|
29
|
+
*
|
|
30
|
+
* @param report - The batch report.
|
|
31
|
+
* @param ctx - Package version and the laws that were loaded.
|
|
32
|
+
* @returns A JSON-serialisable SARIF log.
|
|
33
|
+
*/
|
|
34
|
+
export function toSarif(report, ctx) {
|
|
35
|
+
const sorted = [...report.findings].sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]);
|
|
36
|
+
const dropped = Math.max(0, sorted.length - SARIF_RESULT_CAP);
|
|
37
|
+
const kept = dropped > 0 ? sorted.slice(0, SARIF_RESULT_CAP) : sorted;
|
|
38
|
+
const notifications = report.skipped.map((s) => ({
|
|
39
|
+
level: "warning",
|
|
40
|
+
message: {
|
|
41
|
+
text: `Law ${s.lawId} not evaluated: ${s.reason}${s.detail ? ` (${s.detail})` : ""}`,
|
|
42
|
+
},
|
|
43
|
+
}));
|
|
44
|
+
if (dropped > 0) {
|
|
45
|
+
notifications.push({
|
|
46
|
+
level: "warning",
|
|
47
|
+
message: { text: `Truncated ${dropped} findings (SARIF cap ${SARIF_RESULT_CAP})` },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
$schema: "https://json.schemastore.org/sarif-2.1.0.json",
|
|
52
|
+
version: "2.1.0",
|
|
53
|
+
runs: [
|
|
54
|
+
{
|
|
55
|
+
tool: {
|
|
56
|
+
driver: {
|
|
57
|
+
name: "speclaw",
|
|
58
|
+
informationUri: "https://github.com/esneiderbravo/speclaw",
|
|
59
|
+
semanticVersion: ctx.speclawVersion,
|
|
60
|
+
rules: ctx.laws.map((law) => ({
|
|
61
|
+
id: law.id,
|
|
62
|
+
name: law.id.replace(/~/g, "_"),
|
|
63
|
+
shortDescription: { text: law.title },
|
|
64
|
+
fullDescription: { text: law.prose },
|
|
65
|
+
help: {
|
|
66
|
+
text: law.rationale ?? law.prose,
|
|
67
|
+
markdown: `**${law.title}**\n\n${law.prose}`,
|
|
68
|
+
},
|
|
69
|
+
properties: { tags: ["speclaw", law.verification.kind] },
|
|
70
|
+
})),
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
results: kept.map((f) => ({
|
|
74
|
+
ruleId: f.lawId,
|
|
75
|
+
level: toSarifLevel(f.severity),
|
|
76
|
+
message: { text: f.detail ? `${f.message} ${f.detail}` : f.message },
|
|
77
|
+
locations: [
|
|
78
|
+
{
|
|
79
|
+
physicalLocation: {
|
|
80
|
+
artifactLocation: { uri: toRepoRelativeUri(f.file) },
|
|
81
|
+
region: { startLine: f.line ?? 1 },
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
partialFingerprints: { "speclaw/v1": fingerprint(f) },
|
|
86
|
+
})),
|
|
87
|
+
invocations: [
|
|
88
|
+
{
|
|
89
|
+
executionSuccessful: report.summary.failed === 0,
|
|
90
|
+
toolExecutionNotifications: notifications,
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -8,7 +8,7 @@ import { installWorkflow } from "../lawbook/register.js";
|
|
|
8
8
|
import { installPack, loadPacks } from "../tools/packs.js";
|
|
9
9
|
import { readManifest, writeManifest } from "../../shared/manifest.js";
|
|
10
10
|
import { pkgVersion } from "../../shared/version.js";
|
|
11
|
-
import { readLawManifest, seedManifest, writeLawManifest } from "./laws.js";
|
|
11
|
+
import { mergeSeedLaws, readLawManifest, seedManifest, writeLawManifest, } from "./laws.js";
|
|
12
12
|
import { installHooks } from "./hooks.js";
|
|
13
13
|
const ASSETS = assetsDir(import.meta.url);
|
|
14
14
|
// Every {{var}} the foundation templates may reference. Ones the agent didn't
|
|
@@ -25,19 +25,38 @@ const FOUNDATION_DEFAULTS = {
|
|
|
25
25
|
documentation_extra: "",
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
|
-
* Ensure the project has a law manifest
|
|
29
|
-
*
|
|
30
|
-
* `.speclaw/`; seeding only when missing keeps a curated manifest (the MVP's
|
|
31
|
-
* authoring surface until executable-laws) from being overwritten on update.
|
|
28
|
+
* Ensure the project has a law manifest. Missing → seed. Present → append any
|
|
29
|
+
* shipped seed law whose `id` is absent (never overwrite a curated entry).
|
|
32
30
|
*/
|
|
33
31
|
function ensureLawManifest(projectPath, report) {
|
|
34
32
|
const existing = readLawManifest(projectPath);
|
|
35
|
-
if (existing)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
if (!existing) {
|
|
34
|
+
const seed = seedManifest();
|
|
35
|
+
writeLawManifest(projectPath, seed);
|
|
36
|
+
report.written.push(path.join(projectPath, ".speclaw", "laws-manifest.json"));
|
|
37
|
+
return seed;
|
|
38
|
+
}
|
|
39
|
+
const { manifest, added } = mergeSeedLaws(existing);
|
|
40
|
+
if (added.length > 0) {
|
|
41
|
+
writeLawManifest(projectPath, manifest);
|
|
42
|
+
report.written.push(path.join(projectPath, ".speclaw", "laws-manifest.json"));
|
|
43
|
+
}
|
|
44
|
+
return manifest;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Write `.github/workflows/speclaw.yml` from the shipped template when the
|
|
48
|
+
* path does not exist. Never overwrite — the user's CI is theirs.
|
|
49
|
+
*/
|
|
50
|
+
function ensureVerifyWorkflow(projectPath, report) {
|
|
51
|
+
const dest = path.join(projectPath, ".github", "workflows", "speclaw.yml");
|
|
52
|
+
if (fs.existsSync(dest)) {
|
|
53
|
+
report.skipped.push(dest);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const src = path.join(ASSETS, "workflows", "speclaw.yml");
|
|
57
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
58
|
+
fs.copyFileSync(src, dest);
|
|
59
|
+
report.written.push(dest);
|
|
41
60
|
}
|
|
42
61
|
/**
|
|
43
62
|
* Render the foundation: walk the module's assets/, mirror its structure into
|
|
@@ -131,6 +150,7 @@ export function scaffold(projectPath, profile, packNames, agents = [], opts = {}
|
|
|
131
150
|
// configured. The seam is the manifest: check-dispatcher enforces `path` laws;
|
|
132
151
|
// executable-laws will extend the same manifest with more backends.
|
|
133
152
|
const lawManifest = ensureLawManifest(projectPath, report);
|
|
153
|
+
ensureVerifyWorkflow(projectPath, report);
|
|
134
154
|
report.hooks = installHooks(projectPath, agents, lawManifest, report, {
|
|
135
155
|
baselines: managedOpts.baselines,
|
|
136
156
|
backup: managedOpts.backup,
|
|
@@ -139,7 +159,7 @@ export function scaffold(projectPath, profile, packNames, agents = [], opts = {}
|
|
|
139
159
|
// Record what was installed so `speclaw update` can re-apply these packs and
|
|
140
160
|
// gate feature migrations by version, plus the managed-file baselines that let
|
|
141
161
|
// a later update tell user edits from stale files.
|
|
142
|
-
writeManifest(projectPath, pkgVersion(), packNames, record);
|
|
162
|
+
writeManifest(projectPath, pkgVersion(), packNames, record, opts.minimal !== undefined ? { minimal: opts.minimal } : {});
|
|
143
163
|
report.nextSteps = [
|
|
144
164
|
"Run the `lawbook_init` tool to set up the spec-driven workflow (creates lawbook/). No external CLI needed — it's built into speclaw.",
|
|
145
165
|
"Run the `compass_index` tool to build the local code graph (.speclaw/). No install, no LLM — it's built into speclaw. Re-run it after significant edits.",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True when `file` (POSIX, project-relative) is at or under one of `paths`.
|
|
3
|
+
*
|
|
4
|
+
* @param file - A project-relative POSIX path.
|
|
5
|
+
* @param paths - Optional path prefixes; omitted or empty matches everything.
|
|
6
|
+
*/
|
|
7
|
+
export function underPaths(file, paths) {
|
|
8
|
+
if (!paths || paths.length === 0)
|
|
9
|
+
return true;
|
|
10
|
+
return paths.some((p) => {
|
|
11
|
+
const norm = p.replace(/\/+$/, "");
|
|
12
|
+
return file === norm || file.startsWith(norm + "/");
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import { performance } from "node:perf_hooks";
|
|
2
2
|
import { openDb, indexExists } from "../compass/db.js";
|
|
3
|
-
import { hasBatchBackend,
|
|
3
|
+
import { hasBatchBackend, loadManifestForVerify } from "./laws.js";
|
|
4
4
|
import { runDepsLaw } from "./deps.js";
|
|
5
5
|
import { runGraphLaw } from "./graph.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
6
|
+
export { underPaths } from "./verify-model.js";
|
|
7
|
+
// The batch verifier behind the `law_verify` tool and the `speclaw laws verify`
|
|
8
|
+
// CLI. It evaluates every law whose backend reads the Compass graph (`deps`,
|
|
9
|
+
// `graph`) without a language model, and reports a result honest enough to
|
|
10
|
+
// trust: it distinguishes passed / failed / skipped / unknown and never counts a
|
|
11
|
+
// skip or an unknown as a pass. It is the single home of graph evaluation; the
|
|
12
|
+
// action-time evaluator (`check.ts`) shares this module's model and scope matcher
|
|
13
|
+
// but never runs these engines, so no index query lands on the keystroke budget.
|
|
15
14
|
/**
|
|
16
15
|
* Verify the project's deterministic `deps`/`graph` laws against the Compass
|
|
17
16
|
* index and return a four-state report.
|
|
18
17
|
*
|
|
19
18
|
* When the project has no index, every selected batch law is reported as
|
|
20
|
-
* `skipped` with reason `no-index` (never silently passed).
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* `skipped` with reason `no-index` (never silently passed). When the gitignored
|
|
20
|
+
* manifest file is missing, the shipped seed is used so a clean clone does not
|
|
21
|
+
* report an empty pass. Each evaluated law lands in exactly one of `passed` /
|
|
22
|
+
* `failed` / `unknown`: it fails when the engine produced a finding, is
|
|
23
|
+
* `unknown` when it produced none but rests on unresolved edges (which could
|
|
24
|
+
* hide a violation), and passes otherwise.
|
|
24
25
|
*
|
|
25
26
|
* @param args - The project, and optional `paths` / `engines` / `lawIds` filters.
|
|
26
27
|
* @returns The {@link VerifyReport}.
|
|
@@ -46,9 +47,7 @@ export function verifyLaws(args) {
|
|
|
46
47
|
unknown,
|
|
47
48
|
elapsedMs: performance.now() - start,
|
|
48
49
|
});
|
|
49
|
-
const manifest =
|
|
50
|
-
if (!manifest)
|
|
51
|
-
return done();
|
|
50
|
+
const manifest = loadManifestForVerify(args.projectPath);
|
|
52
51
|
const engines = args.engines;
|
|
53
52
|
const selected = manifest.laws.filter((law) => {
|
|
54
53
|
if (!hasBatchBackend(law))
|
|
@@ -14,34 +14,4 @@ reason) while any task is unchecked, while `reports/` holds no discipline report
|
|
|
14
14
|
or while the delta specs are not yet synced into the canonical specs. So archive
|
|
15
15
|
is the last step of a completed change: reconcile, sync, then archive.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
1. Confirm the change is truly done: every task in `tasks.md` checked, quality
|
|
20
|
-
gates green, behavior verified, and the discipline reports written under
|
|
21
|
-
`reports/`.
|
|
22
|
-
|
|
23
|
-
2. **Reconciliation review (agent-executed).** Run the reconciliation from the
|
|
24
|
-
`sync` skill: reconstruct what was built (branch diff since draft +
|
|
25
|
-
`compass_explore` / `compass_impact`) and compare it to the change's delta
|
|
26
|
-
specs.
|
|
27
|
-
- **If the code drifted past the contracts:** show short insights — a tight
|
|
28
|
-
bullet list of what was built outside the delta specs and why it matters
|
|
29
|
-
(e.g. "DB path renamed to `data/app.db` + auto-migration — infra behavior
|
|
30
|
-
absent from the spec") — and reconcile the delta specs (write the drift
|
|
31
|
-
in). Drift left unreconciled cannot be archived: the specs-synced gate will
|
|
32
|
-
block it.
|
|
33
|
-
- **If nothing drifted:** say so and continue.
|
|
34
|
-
|
|
35
|
-
3. Run `lawbook_validate`, then `lawbook_sync` to promote the delta specs into
|
|
36
|
-
`lawbook/specs/`. This is required, not optional: `lawbook_archive` refuses
|
|
37
|
-
unless the canonical specs already match the delta specs.
|
|
38
|
-
|
|
39
|
-
4. Run the `lawbook_archive` tool with the change name and today's date
|
|
40
|
-
(`YYYY-MM-DD`). It re-checks the gate deterministically and, if it passes,
|
|
41
|
-
moves `lawbook/changes/<name>/` to `lawbook/changes/archive/<date>-<name>/`.
|
|
42
|
-
If it refuses, resolve the reported blockers (unchecked tasks, missing
|
|
43
|
-
reports, unsynced specs) and retry.
|
|
44
|
-
|
|
45
|
-
5. Report the archive path, what you reconciled (or that nothing drifted), and
|
|
46
|
-
the promoted specs. Never move the folder by hand — a manual `mv` skips the
|
|
47
|
-
gate and hides an incomplete change.
|
|
17
|
+
Read `steps/01-confirm-done.md` and do only what it says.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Reconciliation review (agent-executed)
|
|
2
|
+
|
|
3
|
+
Run the reconciliation from the `sync` skill: reconstruct what was built
|
|
4
|
+
(branch diff since draft + `compass_explore` / `compass_impact`) and compare it
|
|
5
|
+
to the change's delta specs.
|
|
6
|
+
|
|
7
|
+
- **If the code drifted past the contracts:** show short insights — a tight
|
|
8
|
+
bullet list of what was built outside the delta specs and why it matters
|
|
9
|
+
(e.g. "DB path renamed to `data/app.db` + auto-migration — infra behavior
|
|
10
|
+
absent from the spec") — and reconcile the delta specs (write the drift
|
|
11
|
+
in). Drift left unreconciled cannot be archived: the specs-synced gate will
|
|
12
|
+
block it.
|
|
13
|
+
- **If nothing drifted:** say so and continue.
|
|
14
|
+
|
|
15
|
+
Next: read `steps/03-validate-and-sync.md` and do only what it says.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Validate and sync
|
|
2
|
+
|
|
3
|
+
Run `lawbook_validate`, then `lawbook_sync` to promote the delta specs into
|
|
4
|
+
`lawbook/specs/`. This is required, not optional: `lawbook_archive` refuses
|
|
5
|
+
unless the canonical specs already match the delta specs.
|
|
6
|
+
|
|
7
|
+
Next: read `steps/04-archive.md` and do only what it says.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Archive
|
|
2
|
+
|
|
3
|
+
Run the `lawbook_archive` tool with the change name and today's date
|
|
4
|
+
(`YYYY-MM-DD`). It re-checks the gate deterministically and, if it passes,
|
|
5
|
+
moves `lawbook/changes/<name>/` to `lawbook/changes/archive/<date>-<name>/`.
|
|
6
|
+
If it refuses, resolve the reported blockers (unchecked tasks, missing
|
|
7
|
+
reports, unsynced specs) and retry.
|
|
8
|
+
|
|
9
|
+
Next: read `steps/05-report.md` and do only what it says.
|
|
@@ -8,104 +8,6 @@ description: Implement the tasks of a drafted change, following its spec and the
|
|
|
8
8
|
Work through a change's `tasks.md` in order, keeping code, spec, and standards
|
|
9
9
|
in lockstep.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Use when the user wants to start or continue implementing a drafted change.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
`specs/`. If unsure which change, run `lawbook_list`.
|
|
15
|
-
- Read the governing standards in `docs/standards/` for the areas you'll touch.
|
|
16
|
-
|
|
17
|
-
## Step 1 — Branch first
|
|
18
|
-
|
|
19
|
-
Create the feature branch (the mandatory Step 0 in `tasks.md`), following the
|
|
20
|
-
repo's branch pattern `{{branch_pattern}}`.
|
|
21
|
-
|
|
22
|
-
## Step 2 — Implement task by task
|
|
23
|
-
|
|
24
|
-
- Use `compass_explore` before editing to see a symbol's callers/callees and
|
|
25
|
-
blast radius; re-run `compass_index` after significant edits to keep the
|
|
26
|
-
graph fresh.
|
|
27
|
-
- Make the smallest correct change; match the surrounding code.
|
|
28
|
-
- The code must satisfy the delta spec exactly. If reality diverges from the
|
|
29
|
-
spec, update the spec in the change (not silently) — the two must agree.
|
|
30
|
-
- Check off each task in `tasks.md` as you complete it.
|
|
31
|
-
|
|
32
|
-
## Step 3 — Quality gates (mandatory)
|
|
33
|
-
|
|
34
|
-
Run the repo's gates from `docs/standards/testing-standards.md`:
|
|
35
|
-
|
|
36
|
-
- Tests: `{{test_commands}}`
|
|
37
|
-
- Lint / type-check: `{{lint_commands}}`
|
|
38
|
-
|
|
39
|
-
Run them yourself and report real output. A red gate blocks completion.
|
|
40
|
-
|
|
41
|
-
## Step 4 — Manual verification (mandatory, agent executes)
|
|
42
|
-
|
|
43
|
-
Exercise the behavior (endpoint/UI/CLI) yourself where feasible — do not
|
|
44
|
-
delegate manual testing to the user. Record what you verified.
|
|
45
|
-
|
|
46
|
-
**Verification is isolated by construction — it never touches real data.** Run it
|
|
47
|
-
against an ephemeral or throwaway store: a temporary copy, an in-memory database
|
|
48
|
-
(`:memory:`), a dedicated test store, or inside a transaction that is rolled
|
|
49
|
-
back — best of all, verify pure/domain logic with fixtures and no store at all.
|
|
50
|
-
Do **not** create, update, or delete the user's real data (a production or
|
|
51
|
-
development database, or files holding real data) as a side effect of proving a
|
|
52
|
-
change, and do **not** run raw store commands (e.g. direct SQL) against a live
|
|
53
|
-
store. Snapshot-and-restore is not a sanctioned method — a stray write slips past
|
|
54
|
-
the restore.
|
|
55
|
-
|
|
56
|
-
If isolation is genuinely impossible and a real-store write is unavoidable,
|
|
57
|
-
**stop and ask first** — state exactly what you will write and to which store —
|
|
58
|
-
and proceed only after explicit authorization. A backup is not a substitute for
|
|
59
|
-
authorization. Record in the report how verification stayed isolated (or the
|
|
60
|
-
authorization you obtained).
|
|
61
|
-
|
|
62
|
-
## Step 5 — Write the discipline reports (mandatory)
|
|
63
|
-
|
|
64
|
-
Record the evidence of testing under `lawbook/changes/<name>/reports/`, one file
|
|
65
|
-
per discipline the change touched, named for that discipline. The set is **open,
|
|
66
|
-
not a fixed list** — `backend.md`, `frontend.md`, and `api.md` are the common
|
|
67
|
-
ones, but write `database.md`, `infra.md`, `security.md`, `performance.md`,
|
|
68
|
-
`e2e.md`, etc. when the change exercises those concerns, and coin a clear
|
|
69
|
-
`<discipline>.md` for anything none of them fit. Omit disciplines the change did
|
|
70
|
-
not touch; the archive is blocked until at least one discipline report exists.
|
|
71
|
-
|
|
72
|
-
**`api.md` is mandatory whenever the change touches an API surface** — a new or
|
|
73
|
-
modified endpoint, its request/response contract, its status codes, or its
|
|
74
|
-
auth/permission or ordering guarantees. A `backend.md` unit report does not
|
|
75
|
-
substitute for it: the contract is a distinct concern. In `api.md` document the
|
|
76
|
-
method and path, the auth/permissions, the response shape and every status code
|
|
77
|
-
the change governs (e.g. `200`/`401`/`403`/`404`), any ordering guarantee, and
|
|
78
|
-
how the contract was exercised (test client and/or `curl`) — kept isolated from
|
|
79
|
-
any live data store per Step 4.
|
|
80
|
-
|
|
81
|
-
Each report MUST follow this structure, in order — the fixed shape is what makes
|
|
82
|
-
the evidence trustworthy and reproducible, rather than left to improvisation:
|
|
83
|
-
|
|
84
|
-
1. **Title + header** — `# <Discipline> checks — <change> (<date>)`, then a line
|
|
85
|
-
`Date · Branch · Environment/cwd` naming where the commands ran.
|
|
86
|
-
2. **Gates & results** — a `| Check | Command | Result |` table: each gate, the
|
|
87
|
-
exact command, and its real result with pass/fail counts (e.g. "62 files, 434
|
|
88
|
-
passed") and ✅/⚠️/❌. Quote real output — never paraphrase a green you did
|
|
89
|
-
not see.
|
|
90
|
-
3. **Tests added / updated** — each new or changed test and what it asserts; note
|
|
91
|
-
TDD evidence ("failed before the fix, passes after") where it applies.
|
|
92
|
-
4. **Spec-scenario coverage** — a table mapping each `#### Scenario` in this
|
|
93
|
-
change's delta specs to how it was verified (a test id, a gate, or a manual
|
|
94
|
-
step). Every scenario must appear.
|
|
95
|
-
5. **Pre-existing / unrelated failures** — any failing check not caused by this
|
|
96
|
-
change, with proof it is pre-existing (e.g. it reproduces with the change
|
|
97
|
-
stashed) — or state "none".
|
|
98
|
-
6. **Pending manual steps** — anything not automated, stated plainly — or "none".
|
|
99
|
-
7. **Verdict** — one line.
|
|
100
|
-
|
|
101
|
-
If a test kind does not yet apply (e.g. no unit runner), the report says so in
|
|
102
|
-
place of that evidence and records the gates and manual verification that stood
|
|
103
|
-
in.
|
|
104
|
-
|
|
105
|
-
## Step 6 — Hand off
|
|
106
|
-
|
|
107
|
-
When every task is checked and gates are green, tell the user the change is
|
|
108
|
-
ready to `sync` and `archive`. Keep the delta specs current as you build, but
|
|
109
|
-
know that `sync` formally reconciles the delta specs against what was actually
|
|
110
|
-
built — so behavior that drifted past the original spec is caught there, not
|
|
111
|
-
left to chance.
|
|
13
|
+
Read `steps/01-load-change.md` and do only what it says.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Load the change
|
|
2
|
+
|
|
3
|
+
- Read `lawbook/changes/<name>/proposal.md`, `tasks.md`, and the delta specs under
|
|
4
|
+
`specs/`. If unsure which change, run `lawbook_list`.
|
|
5
|
+
- Read the governing standards in `docs/standards/` for the areas you'll touch.
|
|
6
|
+
|
|
7
|
+
Next: read `steps/02-branch.md` and do only what it says.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Implement task by task
|
|
2
|
+
|
|
3
|
+
- Use `compass_explore` before editing to see a symbol's callers/callees and
|
|
4
|
+
blast radius; re-run `compass_index` after significant edits to keep the
|
|
5
|
+
graph fresh.
|
|
6
|
+
- Make the smallest correct change; match the surrounding code.
|
|
7
|
+
- The code must satisfy the delta spec exactly. If reality diverges from the
|
|
8
|
+
spec, update the spec in the change (not silently) — the two must agree.
|
|
9
|
+
- Check off each task in `tasks.md` as you complete it.
|
|
10
|
+
|
|
11
|
+
Next: read `steps/04-quality-gates.md` and do only what it says.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Quality gates (mandatory)
|
|
2
|
+
|
|
3
|
+
Run the repo's gates from `docs/standards/testing-standards.md`:
|
|
4
|
+
|
|
5
|
+
- Tests: `{{test_commands}}`
|
|
6
|
+
- Lint / type-check: `{{lint_commands}}`
|
|
7
|
+
|
|
8
|
+
Run them yourself and report real output. A red gate blocks completion.
|
|
9
|
+
|
|
10
|
+
Next: read `steps/05-manual-verification.md` and do only what it says.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Manual verification (mandatory, agent executes)
|
|
2
|
+
|
|
3
|
+
Exercise the behavior (endpoint/UI/CLI) yourself where feasible — do not
|
|
4
|
+
delegate manual testing to the user. Record what you verified.
|
|
5
|
+
|
|
6
|
+
**Verification is isolated by construction — it never touches real data.** Run it
|
|
7
|
+
against an ephemeral or throwaway store: a temporary copy, an in-memory database
|
|
8
|
+
(`:memory:`), a dedicated test store, or inside a transaction that is rolled
|
|
9
|
+
back — best of all, verify pure/domain logic with fixtures and no store at all.
|
|
10
|
+
Do **not** create, update, or delete the user's real data (a production or
|
|
11
|
+
development database, or files holding real data) as a side effect of proving a
|
|
12
|
+
change, and do **not** run raw store commands (e.g. direct SQL) against a live
|
|
13
|
+
store. Snapshot-and-restore is not a sanctioned method — a stray write slips past
|
|
14
|
+
the restore.
|
|
15
|
+
|
|
16
|
+
If isolation is genuinely impossible and a real-store write is unavoidable,
|
|
17
|
+
**stop and ask first** — state exactly what you will write and to which store —
|
|
18
|
+
and proceed only after explicit authorization. A backup is not a substitute for
|
|
19
|
+
authorization. Record in the report how verification stayed isolated (or the
|
|
20
|
+
authorization you obtained).
|
|
21
|
+
|
|
22
|
+
Next: read `steps/06-discipline-reports.md` and do only what it says.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Write the discipline reports (mandatory)
|
|
2
|
+
|
|
3
|
+
Record the evidence of testing under `lawbook/changes/<name>/reports/`, one file
|
|
4
|
+
per discipline the change touched, named for that discipline. The set is **open,
|
|
5
|
+
not a fixed list** — `backend.md`, `frontend.md`, and `api.md` are the common
|
|
6
|
+
ones, but write `database.md`, `infra.md`, `security.md`, `performance.md`,
|
|
7
|
+
`e2e.md`, etc. when the change exercises those concerns, and coin a clear
|
|
8
|
+
`<discipline>.md` for anything none of them fit. Omit disciplines the change did
|
|
9
|
+
not touch; the archive is blocked until at least one discipline report exists.
|
|
10
|
+
|
|
11
|
+
**`api.md` is mandatory whenever the change touches an API surface** — a new or
|
|
12
|
+
modified endpoint, its request/response contract, its status codes, or its
|
|
13
|
+
auth/permission or ordering guarantees. A `backend.md` unit report does not
|
|
14
|
+
substitute for it: the contract is a distinct concern. In `api.md` document the
|
|
15
|
+
method and path, the auth/permissions, the response shape and every status code
|
|
16
|
+
the change governs (e.g. `200`/`401`/`403`/`404`), any ordering guarantee, and
|
|
17
|
+
how the contract was exercised (test client and/or `curl`) — kept isolated from
|
|
18
|
+
any live data store per the manual-verification step.
|
|
19
|
+
|
|
20
|
+
Each report MUST follow this structure, in order — the fixed shape is what makes
|
|
21
|
+
the evidence trustworthy and reproducible, rather than left to improvisation:
|
|
22
|
+
|
|
23
|
+
1. **Title + header** — `# <Discipline> checks — <change> (<date>)`, then a line
|
|
24
|
+
`Date · Branch · Environment/cwd` naming where the commands ran.
|
|
25
|
+
2. **Gates & results** — a `| Check | Command | Result |` table: each gate, the
|
|
26
|
+
exact command, and its real result with pass/fail counts (e.g. "62 files, 434
|
|
27
|
+
passed") and ✅/⚠️/❌. Quote real output — never paraphrase a green you did
|
|
28
|
+
not see.
|
|
29
|
+
3. **Tests added / updated** — each new or changed test and what it asserts; note
|
|
30
|
+
TDD evidence ("failed before the fix, passes after") where it applies.
|
|
31
|
+
4. **Spec-scenario coverage** — a table mapping each `#### Scenario` in this
|
|
32
|
+
change's delta specs to how it was verified (a test id, a gate, or a manual
|
|
33
|
+
step). Every scenario must appear.
|
|
34
|
+
5. **Pre-existing / unrelated failures** — any failing check not caused by this
|
|
35
|
+
change, with proof it is pre-existing (e.g. it reproduces with the change
|
|
36
|
+
stashed) — or state "none".
|
|
37
|
+
6. **Pending manual steps** — anything not automated, stated plainly — or "none".
|
|
38
|
+
7. **Verdict** — one line.
|
|
39
|
+
|
|
40
|
+
If a test kind does not yet apply (e.g. no unit runner), the report says so in
|
|
41
|
+
place of that evidence and records the gates and manual verification that stood
|
|
42
|
+
in.
|
|
43
|
+
|
|
44
|
+
Next: read `steps/07-hand-off.md` and do only what it says.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Hand off
|
|
2
|
+
|
|
3
|
+
When every task is checked and gates are green, tell the user the change is
|
|
4
|
+
ready to `sync` and `archive`. Keep the delta specs current as you build, but
|
|
5
|
+
know that `sync` formally reconciles the delta specs against what was actually
|
|
6
|
+
built — so behavior that drifted past the original spec is caught there, not
|
|
7
|
+
left to chance.
|
|
8
|
+
|
|
9
|
+
No further steps remain — build workflow complete.
|
|
@@ -9,84 +9,7 @@ Turn a request into a complete, reviewable change under `lawbook/changes/<name>/
|
|
|
9
9
|
before any implementation. This is speclaw's own spec-driven workflow — no
|
|
10
10
|
external CLI; the mechanical steps are speclaw MCP tools.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Use when the user wants to start, plan, or propose a new feature, fix, or
|
|
13
|
+
refactor.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## Step 1 — Understand the request and the code
|
|
17
|
-
|
|
18
|
-
- **Refresh the index first.** Run `compass_index` before reasoning about the
|
|
19
|
-
code — it is incremental (unchanged files are skipped by hash), so this is
|
|
20
|
-
cheap and guarantees your decisions rest on the current graph, not a stale one.
|
|
21
|
-
- Clarify what the user wants (feature / fix / refactor) and confirm scope.
|
|
22
|
-
- Use `compass_explore` and `compass_recall` (speclaw's code index) BEFORE
|
|
23
|
-
grep/read to locate the real code the change touches and its blast radius.
|
|
24
|
-
- Read the governing standards in `docs/standards/` (architecture, backend,
|
|
25
|
-
frontend, testing) so the change complies with the project's law.
|
|
26
|
-
|
|
27
|
-
## Step 2 — Pick a change name and its capabilities
|
|
28
|
-
|
|
29
|
-
- **Change name:** kebab-case, action-oriented (e.g. `add-login`,
|
|
30
|
-
`fix-shift-overlap`). This is the folder under `lawbook/changes/`, and it is
|
|
31
|
-
per-feature — always distinct.
|
|
32
|
-
- **Capabilities:** run `lawbook_list` to see the canonical capabilities. A
|
|
33
|
-
capability is the living contract for an area of behavior — it is *not* the
|
|
34
|
-
change. When your change modifies behavior an existing capability already
|
|
35
|
-
governs, reuse that capability's **exact** name so `sync` updates its spec.
|
|
36
|
-
Introduce a new capability only as a deliberate choice for a genuinely distinct
|
|
37
|
-
area of behavior — never as a near-duplicate (`transfer` next to an existing
|
|
38
|
-
`transfers`) of one that already exists.
|
|
39
|
-
|
|
40
|
-
## Step 3 — Write the artifacts
|
|
41
|
-
|
|
42
|
-
Create under `lawbook/changes/<name>/`:
|
|
43
|
-
|
|
44
|
-
- **proposal.md** — the why, the what, non-goals, and whether migrations are
|
|
45
|
-
needed. Reference the team's tracker ticket if there is one.
|
|
46
|
-
- **specs/<capability>/spec.md** — the delta spec for each affected capability.
|
|
47
|
-
`sync` promotes this by overwriting the whole canonical file, so the delta must
|
|
48
|
-
carry the capability's **full** intended spec. When you are updating an existing
|
|
49
|
-
capability, **start from the current `lawbook/specs/<capability>/spec.md`** and
|
|
50
|
-
edit on top of it, so its existing requirements are carried forward — do not
|
|
51
|
-
author it from scratch, or promotion will silently drop them. Use normative
|
|
52
|
-
language and testable scenarios:
|
|
53
|
-
```markdown
|
|
54
|
-
# <Capability>
|
|
55
|
-
|
|
56
|
-
### Requirement: <name>
|
|
57
|
-
The system SHALL <requirement>.
|
|
58
|
-
|
|
59
|
-
#### Scenario: <name>
|
|
60
|
-
- Given <context>
|
|
61
|
-
- When <action>
|
|
62
|
-
- Then <observable outcome>
|
|
63
|
-
```
|
|
64
|
-
- **design.md** — always: approach, alternatives weighed, and the trade-offs
|
|
65
|
-
behind the decision. For a small change, keep it short — but write it.
|
|
66
|
-
- **tasks.md** — ordered, checkable steps. MUST include the mandatory steps
|
|
67
|
-
from `lawbook/config.yaml` (feature branch first; tests reviewed and run;
|
|
68
|
-
manual verification executed by the agent; discipline reports produced; docs
|
|
69
|
-
updated; archive within the PR).
|
|
70
|
-
- **reports/** — create the folder with a short `reports/README.md` naming the
|
|
71
|
-
discipline reports the change will need — one per discipline it touches, from an
|
|
72
|
-
open set (`backend.md`, `frontend.md`, `api.md`, `database.md`, `infra.md`,
|
|
73
|
-
`security.md`, … — and `api.md` is required when the change touches any API
|
|
74
|
-
surface) that `build` will fill, following the required report structure
|
|
75
|
-
(header · gates table ·
|
|
76
|
-
tests added · spec-scenario coverage · pre-existing failures · pending manual ·
|
|
77
|
-
verdict — see the `build` skill, Step 5). Every change ships this folder;
|
|
78
|
-
archive is blocked until it holds at least one discipline report.
|
|
79
|
-
|
|
80
|
-
## Step 4 — Validate
|
|
81
|
-
|
|
82
|
-
Run the `lawbook_validate` tool for the change and fix every issue it reports
|
|
83
|
-
(missing artifacts, non-normative specs, missing scenarios) before handing off
|
|
84
|
-
to implementation. Read its advisory **warnings** too: a near-duplicate
|
|
85
|
-
capability name usually means you should reuse the existing capability's exact
|
|
86
|
-
name, and a dropped-requirement warning means the delta should start from the
|
|
87
|
-
canonical. Warnings do not block, but resolve them unless the divergence is
|
|
88
|
-
intentional.
|
|
89
|
-
|
|
90
|
-
## Step 5 — Hand off
|
|
91
|
-
|
|
92
|
-
Summarize the change and tell the user it's ready to `build`.
|
|
15
|
+
Read `steps/01-ensure-workspace.md` and do only what it says.
|