@printpractical/cruze 0.0.1 → 0.0.3
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 +41 -17
- package/dist/adapters/inbound/cli/cli_context.js +1 -0
- package/dist/adapters/inbound/cli/commands/code.js +2 -1
- package/dist/adapters/inbound/cli/commands/install.js +4 -0
- package/dist/adapters/inbound/cli/commands/realign.js +28 -0
- package/dist/adapters/inbound/cli/commands/review.js +1 -1
- package/dist/adapters/inbound/cli/commands.js +3 -1
- package/dist/adapters/inbound/cli/parse_command.js +2 -0
- package/dist/adapters/inbound/cli/run_cli.js +9 -0
- package/dist/adapters/outbound/node_project_files.js +2 -1
- package/dist/adapters/outbound/process_agent_runner.js +8 -3
- package/dist/app/ports/agent_runner.js +5 -6
- package/dist/app/project_context.js +4 -2
- package/dist/app/use_cases/check_code.js +8 -3
- package/dist/app/use_cases/init_project.js +31 -3
- package/dist/app/use_cases/install_skills.js +8 -1
- package/dist/app/use_cases/journal_events.js +4 -3
- package/dist/app/use_cases/land_change.js +27 -6
- package/dist/app/use_cases/realign_done.js +45 -0
- package/dist/app/use_cases/realign_status.js +106 -0
- package/dist/app/use_cases/record_version.js +56 -0
- package/dist/app/use_cases/run_review.js +26 -12
- package/dist/app/use_cases/validate_project.js +10 -4
- package/dist/domain/check/check_source.js +23 -2
- package/dist/domain/config.js +18 -8
- package/dist/domain/journal.js +29 -5
- package/dist/domain/project/layout.js +1 -0
- package/dist/domain/scaffold.js +15 -1
- package/dist/domain/status/next_step.js +19 -2
- package/dist/domain/validation/plan_rules.js +18 -1
- package/dist/domain/validation/project_rules.js +17 -1
- package/dist/domain/validation/validate_project.js +2 -1
- package/dist/domain/validation/work_item_rules.js +7 -0
- package/dist/domain/versions/ci_pin.js +40 -0
- package/dist/domain/versions/cruze_version.js +51 -0
- package/dist/domain/versions/realign_notes.js +72 -0
- package/dist/domain/versions/rule_versions.js +22 -0
- package/dist/domain/versions/scheduled_exceptions.js +41 -0
- package/package.json +1 -1
- package/skills/architect/feature.md +4 -2
- package/skills/behavioural-testing/SKILL.md +6 -0
- package/skills/build/SKILL.md +1 -1
- package/skills/envision/project.md +4 -2
- package/skills/formats/reference/config.md +7 -3
- package/skills/formats/reference/work-items.md +1 -1
- package/skills/hexagonal-design/SKILL.md +7 -1
- package/skills/hexagonal-design/languages/rust.md +7 -2
- package/skills/land/SKILL.md +1 -1
- package/skills/next/SKILL.md +1 -0
- package/skills/plan/tasks.md +7 -3
- package/skills/plan/test-plan.md +1 -1
- package/skills/realign/SKILL.md +35 -0
- package/skills/realign/notes/0.0.2.md +69 -0
- package/skills/realign/notes/0.0.3.md +11 -0
- package/skills/realign/notes.md +30 -0
- package/skills/research/SKILL.md +2 -1
- package/skills/rethink/SKILL.md +3 -1
- package/skills/rethink/levels.md +1 -1
- package/skills/roles/SKILL.md +5 -2
- package/skills/roles/auditor.md +35 -0
- package/skills/roles/code-reviewer.md +4 -3
- package/skills/roles/design-reviewer.md +9 -6
- package/skills/roles/researcher.md +1 -0
- package/src/adapters/inbound/cli/cli_context.ts +1 -0
- package/src/adapters/inbound/cli/commands/code.ts +2 -1
- package/src/adapters/inbound/cli/commands/install.ts +4 -0
- package/src/adapters/inbound/cli/commands/realign.ts +28 -0
- package/src/adapters/inbound/cli/commands/review.ts +1 -1
- package/src/adapters/inbound/cli/commands.ts +3 -1
- package/src/adapters/inbound/cli/parse_command.ts +2 -0
- package/src/adapters/inbound/cli/run_cli.ts +9 -0
- package/src/adapters/outbound/node_project_files.ts +2 -1
- package/src/adapters/outbound/process_agent_runner.ts +8 -3
- package/src/app/ports/agent_runner.ts +5 -6
- package/src/app/project_context.ts +4 -2
- package/src/app/use_cases/check_code.ts +8 -3
- package/src/app/use_cases/init_project.ts +31 -3
- package/src/app/use_cases/install_skills.ts +8 -1
- package/src/app/use_cases/journal_events.ts +4 -3
- package/src/app/use_cases/land_change.ts +27 -6
- package/src/app/use_cases/realign_done.ts +45 -0
- package/src/app/use_cases/realign_status.ts +106 -0
- package/src/app/use_cases/record_version.ts +56 -0
- package/src/app/use_cases/run_review.ts +26 -12
- package/src/app/use_cases/validate_project.ts +10 -4
- package/src/domain/check/check_source.ts +23 -2
- package/src/domain/config.ts +18 -8
- package/src/domain/journal.ts +29 -5
- package/src/domain/project/layout.ts +1 -0
- package/src/domain/scaffold.ts +15 -1
- package/src/domain/status/next_step.ts +19 -2
- package/src/domain/validation/plan_rules.ts +18 -1
- package/src/domain/validation/project_rules.ts +17 -1
- package/src/domain/validation/validate_project.ts +2 -1
- package/src/domain/validation/work_item_rules.ts +7 -0
- package/src/domain/versions/ci_pin.ts +40 -0
- package/src/domain/versions/cruze_version.ts +51 -0
- package/src/domain/versions/realign_notes.ts +72 -0
- package/src/domain/versions/rule_versions.ts +22 -0
- package/src/domain/versions/scheduled_exceptions.ts +41 -0
- package/templates/init/config.yaml +5 -6
- package/templates/init/review/claude.yaml +7 -0
- package/templates/init/review/other.yaml +7 -0
- package/templates/init/CLAUDE.md +0 -1
|
@@ -56,6 +56,9 @@ function itemProblems(view , item ) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/** A feature's Changes table covers its deltas, and each change folder agrees with its row. */
|
|
59
|
+
/** More changes than this, and one design review can't hold the whole feature: contradictions slip through to plan. */
|
|
60
|
+
const MAX_CHANGES = 6;
|
|
61
|
+
|
|
59
62
|
function featureScopeProblems(view , feature , delta ) {
|
|
60
63
|
const rows = readChangesTable(feature.doc);
|
|
61
64
|
if (rows.length === 0) return [warning(feature.path, undefined, "not-designed", "the feature has no changes yet; architect designs and splits it")];
|
|
@@ -64,6 +67,10 @@ function featureScopeProblems(view , feature , delta
|
|
|
64
67
|
[...readProgress(feature.doc).changes].filter(([, state]) => state === "landed").map(([change]) => change),
|
|
65
68
|
);
|
|
66
69
|
const names = rows.map((row) => row.change);
|
|
70
|
+
const extra = rows[MAX_CHANGES];
|
|
71
|
+
if (extra !== undefined) {
|
|
72
|
+
problems.push(warning(feature.path, extra.line, "feature-size", `the feature has ${rows.length} changes, over ${MAX_CHANGES}; split it into features a single design review can hold`));
|
|
73
|
+
}
|
|
67
74
|
for (const row of rows) {
|
|
68
75
|
if (!/^\d\d-[a-z0-9]+(?:-[a-z0-9]+)*$/.test(row.change)) problems.push(error(feature.path, row.line, "change-name", `change "${row.change}" must be named NN-slug`));
|
|
69
76
|
if (names.indexOf(row.change) !== names.lastIndexOf(row.change)) problems.push(error(feature.path, row.line, "change-name", `change ${row.change} is listed twice`));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** The Cruze package CI runs through `npx --package=<spec>`, kept at the version the project installed. */
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const FORMS = [
|
|
12
|
+
// The npm package: @printpractical/cruze@0.0.1
|
|
13
|
+
(spec, version) => (/^@printpractical\/cruze@[^/\s]+$/.test(spec) ? `@printpractical/cruze@${version}` : null),
|
|
14
|
+
// The release tarball: .../releases/download/v0.0.1/printpractical-cruze-0.0.1.tgz
|
|
15
|
+
(spec, version) => {
|
|
16
|
+
const m = /^(.*\/releases\/download\/)v[^/]+\/printpractical-cruze-[^/]+\.tgz$/.exec(spec);
|
|
17
|
+
return m === null ? null : `${m[1]}v${version}/printpractical-cruze-${version}.tgz`;
|
|
18
|
+
},
|
|
19
|
+
// The git repository at a release tag: github:PrintPractical/cruze#v0.0.1
|
|
20
|
+
(spec, version) => {
|
|
21
|
+
const m = /^(.*cruze(?:\.git)?)#v\d[^\s]*$/.exec(spec);
|
|
22
|
+
return m === null ? null : `${m[1]}#v${version}`;
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/** Moves every `--package=<spec>` that runs Cruze in a CI workflow to the version. */
|
|
27
|
+
export function repinCruze(ciText , version ) {
|
|
28
|
+
const repinned = [];
|
|
29
|
+
const unrecognised = [];
|
|
30
|
+
const text = ciText.replace(/--package=(\S+)(?=\s+cruze\b)/g, (whole, spec ) => {
|
|
31
|
+
const moved = FORMS.map((form) => form(spec, version)).find((result) => result !== null);
|
|
32
|
+
if (moved === undefined || moved === null) {
|
|
33
|
+
if (!unrecognised.includes(spec)) unrecognised.push(spec);
|
|
34
|
+
return whole;
|
|
35
|
+
}
|
|
36
|
+
if (!repinned.includes(moved)) repinned.push(moved);
|
|
37
|
+
return `--package=${moved}`;
|
|
38
|
+
});
|
|
39
|
+
return { text, repinned, unrecognised };
|
|
40
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Which Cruze a project runs: recorded in `.cruze/config.yaml` by `cruze install`, compared with the CLI. */
|
|
2
|
+
|
|
3
|
+
/** Orders two versions such as `0.0.1` and `0.1.0` by their numeric parts; a pre-release tag is ignored. */
|
|
4
|
+
export function compareVersions(a , b ) {
|
|
5
|
+
const parts = (v ) => (v.split("-")[0] ?? "").split(".").map((p) => Number.parseInt(p, 10) || 0);
|
|
6
|
+
const [x, y] = [parts(a), parts(b)];
|
|
7
|
+
for (let i = 0; i < Math.max(x.length, y.length); i++) {
|
|
8
|
+
const diff = (x[i] ?? 0) - (y[i] ?? 0);
|
|
9
|
+
if (diff !== 0) return diff;
|
|
10
|
+
}
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/** How the project's recorded Cruze differs from the CLI running now, or undefined when they match. */
|
|
20
|
+
export function versionSkew(cli , recorded ) {
|
|
21
|
+
if (recorded === undefined) {
|
|
22
|
+
return { kind: "unrecorded", message: `the project doesn't record which Cruze its skills came from; run \`cruze install\` to install the skills of this CLI (${cli}) and record it` };
|
|
23
|
+
}
|
|
24
|
+
const order = compareVersions(recorded, cli);
|
|
25
|
+
if (order < 0) {
|
|
26
|
+
return { kind: "skills-older", recorded, message: `the project's skills are from Cruze ${recorded}, older than this CLI (${cli}); run \`cruze install\` to update them and the CI pin` };
|
|
27
|
+
}
|
|
28
|
+
if (order > 0) {
|
|
29
|
+
return { kind: "cli-older", recorded, message: `the project uses Cruze ${recorded}, newer than this CLI (${cli}); upgrade the CLI as the README's "Upgrading" section says` };
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The config text with `cruze:` set to the version. The line is replaced in place, or added
|
|
36
|
+
* after `version:`, so the file's comments and layout survive.
|
|
37
|
+
*/
|
|
38
|
+
export function withRecordedVersion(configText , version ) {
|
|
39
|
+
return withVersionLine(configText, "cruze", version);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The config text with a top-level version key, such as `cruze:` or `standards:`, set in place. */
|
|
43
|
+
export function withVersionLine(configText , key , version ) {
|
|
44
|
+
const line = `${key}: ${JSON.stringify(version)}`;
|
|
45
|
+
const existing = new RegExp(`^${key}:.*$`, "m");
|
|
46
|
+
if (existing.test(configText)) return configText.replace(existing, line);
|
|
47
|
+
const anchor = key === "standards" ? /^cruze:.*$/m.exec(configText) ?? /^version:.*$/m.exec(configText) : /^version:.*$/m.exec(configText);
|
|
48
|
+
if (anchor === null) return `${line}\n${configText}`;
|
|
49
|
+
const end = anchor.index + anchor[0].length;
|
|
50
|
+
return `${configText.slice(0, end)}\n${line}${configText.slice(end)}`;
|
|
51
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { compareVersions } from "./cruze_version.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A realign note: one change in what Cruze expects of a project, shipped in
|
|
5
|
+
* `skills/realign/notes/<version>.md` so `realign` can bring existing code up to it.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const APPLIES = { "existing code": "existing", "new work only": "new" };
|
|
28
|
+
|
|
29
|
+
/** Parses one version's notes file. Each note is a `### <id>: <title>` heading with facts under it. */
|
|
30
|
+
export function parseRealignNotes(version , text ) {
|
|
31
|
+
const notes = [];
|
|
32
|
+
const problems = [];
|
|
33
|
+
const sections = text.split(/^### /m).slice(1);
|
|
34
|
+
for (const section of sections) {
|
|
35
|
+
const [heading = "", ...body] = section.split("\n");
|
|
36
|
+
const match = /^([a-z0-9]+(?:-[a-z0-9]+)*): (.+)$/.exec(heading.trim());
|
|
37
|
+
if (match === null) {
|
|
38
|
+
problems.push(`${version}: "### ${heading.trim()}" must read "### <id>: <title>"`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const [, id = "", title = ""] = match;
|
|
42
|
+
const fact = (key ) => body.map((line) => new RegExp(`^- ${key}: (.+)$`).exec(line)?.[1]?.trim()).find((v) => v !== undefined);
|
|
43
|
+
const applies = APPLIES[fact("Applies to") ?? ""];
|
|
44
|
+
const rule = fact("Rule");
|
|
45
|
+
const detect = fact("Detect")?.replace(/`/g, "");
|
|
46
|
+
const ask = fact("Ask");
|
|
47
|
+
const migrate = fact("Migrate");
|
|
48
|
+
if (applies === undefined) problems.push(`${version} ${id}: "- Applies to:" must be "existing code" or "new work only"`);
|
|
49
|
+
if (rule === undefined) problems.push(`${version} ${id}: needs "- Rule:"`);
|
|
50
|
+
if (detect !== undefined && !/^(check|validate):[a-z-]+$/.test(detect)) problems.push(`${version} ${id}: "- Detect:" names a rule as check:<rule> or validate:<rule>`);
|
|
51
|
+
if (applies === "existing" && detect === undefined && ask === undefined) problems.push(`${version} ${id}: a note for existing code needs "- Detect:" or "- Ask:"`);
|
|
52
|
+
if (applies === "existing" && migrate === undefined) problems.push(`${version} ${id}: a note for existing code needs "- Migrate:"`);
|
|
53
|
+
notes.push({
|
|
54
|
+
id,
|
|
55
|
+
title,
|
|
56
|
+
version,
|
|
57
|
+
appliesTo: applies ?? "new",
|
|
58
|
+
rule: rule ?? "",
|
|
59
|
+
...(detect === undefined ? {} : { detect }),
|
|
60
|
+
...(ask === undefined ? {} : { ask }),
|
|
61
|
+
...(migrate === undefined ? {} : { migrate }),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const ids = notes.map((n) => n.id);
|
|
65
|
+
ids.filter((id, i) => ids.indexOf(id) !== i).forEach((id) => problems.push(`${version}: note ${id} appears twice`));
|
|
66
|
+
return { notes, problems };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Notes after the version the code meets, up to and including the version installed. */
|
|
70
|
+
export function notesBetween(notes , standards , target ) {
|
|
71
|
+
return notes.filter((n) => compareVersions(n.version, standards) > 0 && compareVersions(n.version, target) <= 0);
|
|
72
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { compareVersions } from "./cruze_version.js";
|
|
2
|
+
|
|
3
|
+
/** The first release of Cruze. A project that records no `standards:` meets its expectations. */
|
|
4
|
+
export const FIRST_RELEASE = "0.0.1";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The release that introduced each rule reporting on existing code, keyed as `<command>:<rule>`.
|
|
8
|
+
* A rule newer than the project's `standards:` still reports, but can't fail CI until the project realigns.
|
|
9
|
+
* Every entry needs a realign note in `skills/realign/notes/<version>.md`; the bundle lint checks it.
|
|
10
|
+
*/
|
|
11
|
+
export const RULE_SINCE = {
|
|
12
|
+
"check:test-placement": "0.0.2",
|
|
13
|
+
"validate:outside-module-map": "0.0.2",
|
|
14
|
+
"validate:readme-overview": "0.0.2",
|
|
15
|
+
"validate:feature-size": "0.0.2",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** Whether a rule arrived after the version the project's code meets, so it waits for `realign`. */
|
|
19
|
+
export function isPending(command , rule , standards ) {
|
|
20
|
+
const since = RULE_SINCE[`${command}:${rule}`];
|
|
21
|
+
return since !== undefined && compareVersions(since, standards) > 0;
|
|
22
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { parseDocument, } from "yaml";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `check.exceptions` entries that `realign` adds for findings a prefactor change will fix,
|
|
5
|
+
* and that landing that change removes. Edited through the YAML document, so comments survive.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const scheduledReason = (version , note , ref ) => `realign ${version} (${note}): scheduled in ${ref}`;
|
|
14
|
+
|
|
15
|
+
/** The config text with an exception for each finding, naming the change that will fix it. */
|
|
16
|
+
export function withScheduledExceptions(configText , version , ref , findings ) {
|
|
17
|
+
if (findings.length === 0) return configText;
|
|
18
|
+
const doc = parseDocument(configText);
|
|
19
|
+
const listed = new Set(((doc.getIn(["check", "exceptions"]) )?.toJSON() ?? []).map((e) => e.path));
|
|
20
|
+
for (const finding of findings.filter((f, i) => !listed.has(f.path) && findings.findIndex((o) => o.path === f.path) === i)) {
|
|
21
|
+
doc.addIn(["check", "exceptions"], doc.createNode({ path: finding.path, reason: scheduledReason(version, finding.note, ref) }));
|
|
22
|
+
}
|
|
23
|
+
return render(doc);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The config text without the exceptions scheduled in a change, once it lands; unchanged when it had none. */
|
|
27
|
+
export function withoutScheduledExceptions(configText , ref ) {
|
|
28
|
+
const doc = parseDocument(configText);
|
|
29
|
+
const exceptions = doc.getIn(["check", "exceptions"]) ;
|
|
30
|
+
if (exceptions === undefined || !Array.isArray(exceptions.items)) return { text: configText, removed: [] };
|
|
31
|
+
const suffix = `: scheduled in ${ref}`;
|
|
32
|
+
const removed = exceptions.items.map((item) => item.toJSON()).filter((e) => e.reason?.endsWith(suffix)).map((e) => e.path ?? "");
|
|
33
|
+
if (removed.length === 0) return { text: configText, removed: [] };
|
|
34
|
+
exceptions.items = exceptions.items.filter((item) => !(item.toJSON().reason ?? "").endsWith(suffix));
|
|
35
|
+
return { text: render(doc), removed };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Renders without wrapping long lines or padding flow lists, so an edit changes only what it touches. */
|
|
39
|
+
function render(doc ) {
|
|
40
|
+
return doc.toString({ lineWidth: 0, flowCollectionPadding: false });
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ The result is a `feature.md` with a complete architecture delta and an ordered l
|
|
|
15
15
|
- `MODIFIED` for an existing element, with its full new body. Copy the current body from `docs/architecture.md` and edit it, so nothing is lost by accident.
|
|
16
16
|
- `REMOVED` with a `Reason`, for an element the feature retires.
|
|
17
17
|
5. **Link behaviour to design.** Each use case that runs a requirement lists it under `Serves`. Add or modify a `FLOW` for each key scenario, with `Serves` naming its scenarios and the failure paths they need.
|
|
18
|
-
6. **Research and decide.** For each new component that isn't domain logic, run the researcher role and record a row in `## Adopt or build`. Take every new dependency to the user.
|
|
18
|
+
6. **Research and decide.** For each new component that isn't domain logic, run the researcher role and record a row in `## Adopt or build`. Take every new dependency to the user. Then verify every claim the design relies on, following step 7 of adopt or build in `.agents/skills/cruze-research/SKILL.md`. Done when no claim in the design is unverified.
|
|
19
19
|
7. **Keep later seams open.** When the feature map shows a later feature that will extend this area, record the seam in a `Future` fact, and don't build it.
|
|
20
20
|
8. Done when `cruze validate` reports no errors in the delta itself, and every cited ID exists in the living docs or this delta.
|
|
21
21
|
|
|
@@ -23,7 +23,9 @@ The result is a `feature.md` with a complete architecture delta and an ordered l
|
|
|
23
23
|
|
|
24
24
|
9. **Slice vertically.** Each change delivers one or more scenarios end to end, through every layer they need, and can land on its own. The first change is the thinnest slice that proves the design, a tracer bullet. Later changes widen it.
|
|
25
25
|
10. **Fill the Changes table.** Give each row a number and a slug, such as `01-local-serial`. List the scenario and requirement IDs it `Delivers`, the architecture IDs it `Builds`, any IDs it `Removes`, and the changes it `Depends on`.
|
|
26
|
+
- A change builds an element only when its scenarios prove the whole element. Each delta element is built by exactly one change, so when an element's duties arrive in different changes, split it into elements that each arrive whole, such as frame limits split out of a concurrency rule.
|
|
27
|
+
- `Depends on` names every earlier change that builds something this change's scenarios need.
|
|
26
28
|
11. **Cover everything exactly once.** Every delta ID appears in exactly one change. A module the delta adds, or one still `planned` in the living docs, is built by the first change that writes a file in it. A module already `built` isn't listed. Done when `cruze validate` reports no errors for the feature, and no `not-designed` warning.
|
|
27
|
-
12. **Size each change.** A change that would need more than about 12 tasks, or touches more than one context's domain, splits in two.
|
|
29
|
+
12. **Size each change, and the feature.** A change that would need more than about 12 tasks, or touches more than one context's domain, splits in two. A feature of more than 6 changes is more than one design review can hold: split it into features that each serve part of its goals, and run `cruze features add` for the later ones. `cruze validate` warns `feature-size` until it is split.
|
|
28
30
|
|
|
29
31
|
Then continue with the review and walkthrough steps of the skill. When the user approves, run `cruze approve <feature>` and quote its result. The command takes the feature's full ID, such as `2026-09-25-open-console`, or its slug when no other active item shares it.
|
|
@@ -36,6 +36,12 @@ A behaviour test drives a use case, not a single domain type, so it keeps passin
|
|
|
36
36
|
- Time, randomness and the environment are ports too. Inject a clock instead of reading the system time.
|
|
37
37
|
- A fake earns trust from the contract tests it shares with the real adapter. Read [fakes.md](fakes.md) before writing one.
|
|
38
38
|
|
|
39
|
+
## Test support
|
|
40
|
+
|
|
41
|
+
- Share fixtures and harnesses the way you share fakes. Keep one builder or constant for each domain value tests keep needing, such as a valid configuration or an ID from a string, and one harness per seam, such as an in-process service or the real binary started on a temporary directory. They live in the test support module the language file names.
|
|
42
|
+
- Before writing a helper in a test file, look in the test support module. Use or extend what is there, and never redefine it.
|
|
43
|
+
- Split a test file by the behaviour it covers, one use case, port or flow per file. File budgets apply to source, not to tests, so never split a test file to meet one.
|
|
44
|
+
|
|
39
45
|
## Expected values
|
|
40
46
|
|
|
41
47
|
- Take expected values from an independent source: the scenario's worked example, a spec, or a known-good literal. Never compute the expected value the way the code does.
|
package/skills/build/SKILL.md
CHANGED
|
@@ -30,7 +30,7 @@ For task `T<n>`:
|
|
|
30
30
|
|
|
31
31
|
1. **Read it.** Note its owner, its files, the IDs it proves, and the test plan rows for those IDs.
|
|
32
32
|
2. **Red.** Write the tests for the IDs it proves, at the seams the test plan names, carrying the IDs. Run them, and see them fail for the reason you expect.
|
|
33
|
-
3. **Green.** Write the least code that makes them pass, in the task's files. Code that belongs to another task waits for
|
|
33
|
+
3. **Green.** Write the least code that makes them pass, in the task's files. Code that belongs to another task, or another change, waits for it, even when the next change will need it.
|
|
34
34
|
4. **Check.** Run `cruze check <the task's files>`, the formatter and the linter, and fix what they report. Run the tests the task touched, and the rest of the suite when they are quick.
|
|
35
35
|
5. **Commit** with a Conventional Commit message naming the task, such as `feat(access): console session state machine (T2)`.
|
|
36
36
|
6. **Tick it.** Run `cruze task done T<n>`, which records the commit. Its progress edit rides along in the next commit.
|
|
@@ -15,6 +15,8 @@ The result is an approved `docs/vision.md` and a `docs/glossary.md` holding the
|
|
|
15
15
|
5. **Write the vision.** Fill each section, and remove every template guide.
|
|
16
16
|
6. **Fill the feature map.** For each capability, run `cruze features add <slug> --summary "<summary>" --goals <GOAL IDs>`. Put command syntax in backticks, such as `` `consolectl console <device>` ``, so it isn't read as a template guide. Running `add` again for the same slug replaces its entry in place. Done when every goal is served by at least one feature on the map.
|
|
17
17
|
7. **Confirm.** Walk the user through the vision in one short summary: the problem, the goals with their measures, the non-goals, the constraints, and the feature map. Ask whether it matches their understanding, and apply any corrections.
|
|
18
|
-
8. **Approve.** When the user approves, run `cruze approve vision` and quote its result.
|
|
18
|
+
8. **Approve.** When the user approves, run `cruze approve vision` and quote its result.
|
|
19
|
+
9. **Introduce the project in the README.** Under the title of `README.md`, write one paragraph drawn from the vision's Problem, Users and Goals: what the product is, who it is for, and why it exists, ending with a link to `docs/vision.md`. Keep anything already there that is still true. Done when `cruze validate` reports no `readme-overview` warning.
|
|
20
|
+
10. **Commit,** with a message such as `docs: envision the project`.
|
|
19
21
|
|
|
20
|
-
Done when `cruze status` shows `docs/vision.md` approved and the glossary holds every domain term the vision uses.
|
|
22
|
+
Done when `cruze status` shows `docs/vision.md` approved, the README says what the project is, and the glossary holds every domain term the vision uses.
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
```yaml
|
|
6
6
|
version: 1
|
|
7
|
+
cruze: "0.0.2"
|
|
8
|
+
standards: "0.0.2"
|
|
7
9
|
project: "Console Access"
|
|
8
10
|
tracker: markdown
|
|
9
11
|
|
|
@@ -38,16 +40,18 @@ layers:
|
|
|
38
40
|
| Key | Meaning |
|
|
39
41
|
| --- | --- |
|
|
40
42
|
| `version` | Format version. Always `1` for now. |
|
|
43
|
+
| `cruze` | The Cruze version whose skills the project installed. `cruze install` writes it; don't edit it, except to go back to an older version on purpose. |
|
|
44
|
+
| `standards` | The Cruze version whose expectations the code meets. `cruze realign done` moves it up. A rule a later release added reports but fails no CI until then. Without it, a project meets `0.0.1`. |
|
|
41
45
|
| `project` | The project name, quoted. |
|
|
42
46
|
| `tracker` | Where work items live. `markdown` is the only value in V1. |
|
|
43
47
|
| `source` | Globs of the source files `cruze check` inspects. |
|
|
44
48
|
| `tests` | Globs of the files `cruze trace` searches for scenario IDs. |
|
|
45
|
-
| `check.max_lines` | Line budget per source file. |
|
|
49
|
+
| `check.max_lines` | Line budget per source file. Test files outside `source` have no budget. |
|
|
46
50
|
| `check.max_types` | Budget of top-level types per source file. |
|
|
47
|
-
| `check.exceptions` | Files allowed past a budget, each with a `path` and a `reason`. |
|
|
51
|
+
| `check.exceptions` | Files allowed past a budget, or Rust test files allowed under `src/` (`test-placement`), each with a `path` and a `reason`. `realign` adds entries whose reason ends `scheduled in <ref>`, and landing that change removes them. |
|
|
48
52
|
| `layers` | Each layer has a `name`, the `paths` it covers, and `may_import`, the layers it may depend on. |
|
|
49
53
|
| `commands` | The project's commands by name, such as `test` or `run`. The walking-skeleton change fills them in, and `cruze land` copies them into the Commands section of `AGENTS.md`. |
|
|
50
|
-
| `review.command` | The program and arguments `cruze review` runs to start an agent in a fresh context, with the prompt on standard input.
|
|
54
|
+
| `review.command` | The program and arguments `cruze review` runs to start an agent in a fresh context, with the prompt on standard input. Optional. `cruze init` sets it for Claude Code to run in print mode, allowed to read the project and run `git diff`, `git log`, `git show` and `cruze`. The verifier runs the system, so add the project's build and run commands. When it is unset, or its program isn't installed, `cruze review` hands the role's prompt back to the calling agent to run in a helper. |
|
|
51
55
|
|
|
52
56
|
Rules for layers:
|
|
53
57
|
|
|
@@ -35,7 +35,7 @@ Templates: [../templates/feature.md](../templates/feature.md), [../templates/cha
|
|
|
35
35
|
|
|
36
36
|
A standalone change adds `## Intent`, `## Adopt or build`, `## Spec delta` and `## Architecture delta` before its `## Scope`, in the same format as a feature's. Its scope covers every ID in its own deltas, plus any `planned` elements from the living docs that it builds.
|
|
37
37
|
|
|
38
|
-
A feature is designed in two steps. Feature-scope `envision` writes the intent, settled decisions and spec delta, and leaves `## Architecture delta` as `None.` and the Changes table empty. `architect` writes the architecture delta and the changes. Until the Changes table has a row, `cruze validate` reports the feature as `not-designed` (a warning), skips the coverage rules, and `cruze approve` refuses it.
|
|
38
|
+
A feature is designed in two steps. Feature-scope `envision` writes the intent, settled decisions and spec delta, and leaves `## Architecture delta` as `None.` and the Changes table empty. `architect` writes the architecture delta and the changes. Until the Changes table has a row, `cruze validate` reports the feature as `not-designed` (a warning), skips the coverage rules, and `cruze approve` refuses it. A feature of more than 6 changes gets a `feature-size` warning: split it, because one design review can't hold it.
|
|
39
39
|
|
|
40
40
|
`architect` writes a standalone change's design sections and its scope, and leaves the test plan table empty and the tasks section blank. Until `plan` fills them, `cruze validate` reports the change as `not-planned` (a warning), skips the task and test plan rules, and `cruze approve` refuses it.
|
|
41
41
|
|
|
@@ -94,7 +94,12 @@ Layers are dependency boundaries, not runtime hops. A port can be a plain functi
|
|
|
94
94
|
## Representations and errors
|
|
95
95
|
|
|
96
96
|
- Keep transport, application, domain and persistence representations separate when their meaning differs. Map them explicitly at the boundary, with one owner per mapping. Don't copy a type only to have one per layer.
|
|
97
|
-
-
|
|
97
|
+
- Expected failures are values the caller handles, not crashes. An error type exists where a caller handles its cases differently, and nowhere else.
|
|
98
|
+
- Domain errors describe domain failures and live with the concept that raises them.
|
|
99
|
+
- A use case returns the domain error unchanged when nothing else can fail. When it adds failures of its own, such as a port's, its error wraps the domain error in one case and never copies its variants.
|
|
100
|
+
- Adapter errors describe infrastructure failures. The adapter translates them at the port, so an SDK's error type never crosses it.
|
|
101
|
+
- Similar failures share one type, with what differs as a field: one `too large` failure naming what was too large, not one type per operation.
|
|
102
|
+
- A function returns only the failures its callers can meet. When every caller has already ruled a case out, narrow the return type rather than handling the case as unreachable.
|
|
98
103
|
|
|
99
104
|
## Warning signs
|
|
100
105
|
|
|
@@ -107,6 +112,7 @@ Reconsider ownership when a design or a diff shows any of these:
|
|
|
107
112
|
- Application code constructs an adapter.
|
|
108
113
|
- Logic that already exists is implemented again, or a change keeps a private copy of shared behaviour.
|
|
109
114
|
- An interface mirrors its only implementation, or a chain of components only forwards calls.
|
|
115
|
+
- An error type copies another's cases, or two error types differ only in their names.
|
|
110
116
|
- Commodity infrastructure is being hand-written although a mature library does it. Follow `.agents/skills/cruze-research/SKILL.md`.
|
|
111
117
|
|
|
112
118
|
These are review signals, not automatic failures. When one could be checked mechanically, propose a `cruze check` rule or a linter setting instead of repeating the finding.
|
|
@@ -21,7 +21,9 @@ These add to the hexagonal design rules for Rust projects. The module map decide
|
|
|
21
21
|
|
|
22
22
|
## Errors
|
|
23
23
|
|
|
24
|
-
- Define
|
|
24
|
+
- Define error enums with `thiserror` where the hexagonal-design error rules call for a type, not one per layer by default. A use case whose only failure is a domain error returns that error. One that adds failures wraps it in a single `#[from]` variant.
|
|
25
|
+
- Put what differs between similar failures in fields, such as `TooLarge { subject: Subject, size: usize, limit: usize }`, rather than `BatchTooLarge`, `MutationTooLarge` and `SetTooLarge`.
|
|
26
|
+
- A match arm that can only be `unreachable!`, or an `expect` on an error the caller has ruled out, means the callee returns too wide a type: narrow it.
|
|
25
27
|
- `anyhow` belongs only in the composition root and binaries, where no caller inspects the error. Never return it from a port or a domain function.
|
|
26
28
|
- No `unwrap`, `expect` or `panic!` for conditions that can happen in production. Tests may use them.
|
|
27
29
|
|
|
@@ -37,4 +39,7 @@ These add to the hexagonal design rules for Rust projects. The module map decide
|
|
|
37
39
|
- Add dependencies with `cargo add`, so the version comes from the registry.
|
|
38
40
|
- No `unsafe` unless the user approves it or an unavoidable low-level boundary needs it, with a `// SAFETY:` comment giving the reason.
|
|
39
41
|
- Format with `cargo fmt`, lint with `cargo clippy -- -D warnings`, and test with `cargo test`.
|
|
40
|
-
- Behaviour, contract and smoke tests live in `tests/` and reach the code through the library's public API.
|
|
42
|
+
- Behaviour, contract and smoke tests live in the crate's `tests/` directory and reach the code through the library's public API. Domain tests sit in a `#[cfg(test)] mod tests` beside the code and need no fakes.
|
|
43
|
+
- When a module's inline tests would take its file past the budget, move them to the crate's `tests/`, named for the module: `tests/<module>.rs`, or `tests/<module>/main.rs` declaring one file per topic, such as `tests/generation/add_generation.rs`. Cargo builds each `tests/*.rs` and each `tests/*/main.rs` as a test binary, and nothing deeper. Never move them to `src/<module>/tests.rs` or `src/<module>/tests/`: `cruze check` reports those as `test-placement`. A test that needs a private item is testing structure, so drive the public API instead. When a private seam really is the contract, such as a filesystem trait a crash test injects, list the file under `check.exceptions` with that reason.
|
|
44
|
+
- Group integration tests into a few binaries by area, `tests/<area>/main.rs` with one module per topic, since every binary links the crate again.
|
|
45
|
+
- Share fakes, fixtures and harnesses within a crate through `tests/support/mod.rs`, which each test binary declares with `mod support;`. In a workspace, put what several crates' tests share in one dev-only crate, such as `<project>-test-support`, listed under `[dev-dependencies]`. Never share them with `#[path]` includes.
|
package/skills/land/SKILL.md
CHANGED
|
@@ -20,7 +20,7 @@ Land makes finished work part of the living model. `cruze land` merges the chang
|
|
|
20
20
|
- When they don't hold, stop and offer `rethink`.
|
|
21
21
|
4. **Run `cruze land`** and quote its report: what it merged, what is now built, and whether the work finished and was archived.
|
|
22
22
|
- A `merge-conflict` means someone changed an element this feature merged earlier. Stop and run `rethink`, which reconciles it.
|
|
23
|
-
- A `merge-invalid` means the merged docs wouldn't validate. Nothing was written. Stop and run `rethink`.
|
|
23
|
+
- A `merge-invalid` means the merged docs, or the feature and changes being landed, wouldn't validate, such as a decision citing an ID the change removes. Nothing was written. Stop and run `rethink`.
|
|
24
24
|
5. **Update the changelog.** Under `## [Unreleased]` in `CHANGELOG.md`, add one line per user-visible behaviour the change delivers, in the user's words, under `### Added`, `### Changed` or `### Removed`. Name the behaviour, not the code, including any rule a user can now run into that no scenario covers yet.
|
|
25
25
|
6. **Update the README** when the change altered how someone installs, runs or uses the product. Run every command you add, to check it works.
|
|
26
26
|
7. **Check the pitfalls.** Run `cruze journal list --event disposition`, `cruze journal list --event rethink` and `cruze journal list --event bug`. When findings under the same rubric item with the same root cause, or two defects with the same cause, have now happened twice, add one line under `## Known pitfalls` in `AGENTS.md` saying what to do instead. Keep `AGENTS.md` under one page. When the pitfalls outgrow it, propose to the user a `cruze check` rule or a knowledge-skill change for the oldest ones.
|
package/skills/next/SKILL.md
CHANGED
|
@@ -25,6 +25,7 @@ Next reads the project's state and says what to do now. The CLI works it out fro
|
|
|
25
25
|
| `verify` | `verify`, on this branch |
|
|
26
26
|
| `land` | `land`, on this branch |
|
|
27
27
|
| `rethink` | `rethink`: something approved changed, and the work citing it must be reviewed |
|
|
28
|
+
| `realign` | `realign`: the installed Cruze expects more of existing code than it meets |
|
|
28
29
|
| `switch-branch` | Switch to the named branch, where that change is built |
|
|
29
30
|
|
|
30
31
|
When the user asks about something `cruze next` didn't name, such as a bug or an idea, point them to `triage` or `explore`.
|
package/skills/plan/tasks.md
CHANGED
|
@@ -9,6 +9,7 @@ A task is one owner, the files it writes, and the IDs it proves. Build does them
|
|
|
9
9
|
- The composition root comes last.
|
|
10
10
|
- Put fakes just before the first task whose test needs them.
|
|
11
11
|
- Each task's test can fail first and then pass, using only what earlier tasks built.
|
|
12
|
+
- When the project's lint rejects unused code, such as `cargo clippy -- -D warnings`, put each new item in the task of its first user, or in a task whose own test uses it. Each task then commits green on its own.
|
|
12
13
|
3. **Write one line per task:**
|
|
13
14
|
|
|
14
15
|
```markdown
|
|
@@ -19,8 +20,11 @@ A task is one owner, the files it writes, and the IDs it proves. Build does them
|
|
|
19
20
|
- Owner and paths in backticks. Every path is a file the architecture assigns to that owner, or a test or support file.
|
|
20
21
|
- A task proves the elements it builds, and each scenario whose test goes green in it.
|
|
21
22
|
- A task that only sets up tooling proves the flow or scenario its checks run.
|
|
22
|
-
4. **
|
|
23
|
-
5. **
|
|
23
|
+
4. **Find the callers.** For each signature, default or setting a task changes, search the code for every use of it, including tests that start the real binary or read the setting. Add each file that must change to the task. Done when no task will need a file it doesn't list.
|
|
24
|
+
5. **Size each task.** A task writes one owner, with its tests, in one sitting. When an owner would take several steps, such as a use case with many scenarios, split it into tasks that each prove a subset of the scenarios.
|
|
25
|
+
- Run `cruze check` on each existing file a task extends. When the task would take the file past `check.max_lines` or `check.max_types`, name the new file in the task, split along a responsibility the owner already has.
|
|
26
|
+
- The budgets apply to source files, not tests. Split a test file by the behaviour it covers, one use case or port per file, never to meet a budget. Tests that leave a source file go where the hexagonal-design language file you loaded says.
|
|
27
|
+
6. **Check coverage.**
|
|
24
28
|
- Every `Builds` ID is proved by a task, except a module, which is proved by any task that writes inside its `Path`.
|
|
25
29
|
- Every delivered scenario is proved by at least one task.
|
|
26
|
-
- Done when `cruze validate` reports no `unproved-scope` or `
|
|
30
|
+
- Done when `cruze validate` reports no `unproved-scope`, `task-format` or `outside-module-map` problems. An `outside-module-map` warning means a task writes a file no module's `Path` covers: add the file to the owning module's `Path` through `rethink`, or move it.
|
package/skills/plan/test-plan.md
CHANGED
|
@@ -9,6 +9,6 @@ The test plan decides, before any code, which test proves each scenario and at w
|
|
|
9
9
|
2. **One `contract` row per port that a built adapter implements.** The seam names the fake and each real adapter, and what stands in for the outside world: a temporary directory, a pseudo-terminal, a local test server.
|
|
10
10
|
3. **A `domain` row only for real logic.** Add one for a state machine, a calculation, or an invariant with many edge cases, when reaching every case through use cases would take many tests.
|
|
11
11
|
4. **A `smoke` row for each flow the change completes,** when that flow is one of the system's top 1 to 3. It runs the real inbound adapter wired by the real composition root.
|
|
12
|
-
5. **Test file paths follow the language's conventions.** Put behaviour, contract and smoke tests where the language keeps tests that use the public API, such as `tests/` in Rust. Put domain tests where it keeps unit tests.
|
|
12
|
+
5. **Test file paths follow the language's conventions.** Put behaviour, contract and smoke tests where the language keeps tests that use the public API, such as `tests/` in Rust. Put domain tests where it keeps unit tests. When the language file says where tests go once they outgrow their source file, follow it. Add each test to the file for its seam in the test support module the language file names, rather than a new file per task.
|
|
13
13
|
|
|
14
14
|
Done when every delivered scenario has a `behaviour` row, every port a built adapter implements has a `contract` row, and every test file path is a real path the project's test runner will find.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cruze-realign
|
|
3
|
+
description: Brings an existing codebase up to what the installed Cruze expects, by auditing it against each release's realign notes, deciding every finding with you, and scheduling the fixes as prefactor changes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Realign
|
|
7
|
+
|
|
8
|
+
Each Cruze release can expect more of a project's code and documents than the last, such as where tests live or how error types are shaped. `cruze install` updates the skills; realign brings the existing work up to them. The code's version is `standards:` in `.cruze/config.yaml`, and the installed one is `cruze:`. Rules newer than `standards:` report but fail no CI until realign moves it.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. **Find the gap.** Run `cruze realign status` and quote its first line: the version the code meets and the one installed. Add `--full` when the user asks for a full audit, or the project adopted Cruze partway and has never been realigned; it takes every release's notes. On `install-first`, the skills are older than the CLI: run `cruze install` first. Read [notes.md](notes.md) for what a note holds. Done when you can name every note in the report.
|
|
13
|
+
2. **See what is in flight.** Run `cruze status`. Realign doesn't wait for active features and changes; it schedules around them in step 6.
|
|
14
|
+
3. **Load the standards.** Read these, and each skill file a note's `Rule` names:
|
|
15
|
+
- `.agents/skills/cruze-hexagonal-design/SKILL.md`, and its language file when one exists for the project's language
|
|
16
|
+
- `.agents/skills/cruze-behavioural-testing/SKILL.md`
|
|
17
|
+
- `.agents/skills/cruze-formats/reference/architecture.md`
|
|
18
|
+
4. **Audit.** Run the auditor role from `.agents/skills/cruze-roles/SKILL.md` on every note with an `Ask`. In a full audit, give it the standards instead, and run one auditor per module in the module map. Check its evidence against the files. Done when every note with an `Ask` has an answer with evidence, and every note with a `Detect` has its findings from the status report.
|
|
19
|
+
5. **Decide each finding** with the user, a group at a time, with your recommendation:
|
|
20
|
+
- `fixed`: a prefactor change will fix it.
|
|
21
|
+
- `waived`: the project keeps its own convention, with the reason. For a `check:` finding, list the file under `check.exceptions` with that reason, which keeps CI green. For the rest, the journal holds the waiver.
|
|
22
|
+
- `deferred`: it waits for later work, recorded with `cruze features add` or on the roadmap.
|
|
23
|
+
|
|
24
|
+
Record each with `cruze journal add disposition --set review=realign --set finding="<note id>: <path or summary>" --set disposition=<fixed|waived|deferred> --set reason="<reason>"`. For a finding from a `Detect` rule, write the finding as exactly `<note id>: <path>`, so `cruze realign status` knows it next time. A recorded waiver is never raised again.
|
|
25
|
+
6. **Schedule the fixes.** Group the `fixed` findings into prefactor changes, each small enough to plan (about 12 tasks), one module or concern per change.
|
|
26
|
+
- When a fix changes what `docs/architecture.md` says, such as an error element, a use case's `Errors` or a port's `Operations`, run `rethink` at architecture level first. It replans the built elements the prefactor rebuilds.
|
|
27
|
+
- Create each prefactor as "A prefactor" in `.agents/skills/cruze-architect/tweak.md` describes. The behaviour tests are its safety net: wire formats, messages and exit codes stay as they are unless the user decides otherwise.
|
|
28
|
+
- Put each on the roadmap, following `.agents/skills/cruze-roadmap/SKILL.md`. Run `cruze status --overlap --change <ref>`, and block it on every in-flight item it overlaps.
|
|
29
|
+
7. **Record it.** Run `cruze realign done`, adding `--change <ref>` for the prefactor that fixes the `Detect` findings still open. It moves `standards:` up, and lists those files under `check.exceptions` until that change lands, when `cruze land` removes them. Quote its result, and commit with a message such as `chore: realign to Cruze <version>`.
|
|
30
|
+
|
|
31
|
+
Done when `cruze realign status` reports the code meeting the installed version, and every finding has a journaled disposition.
|
|
32
|
+
|
|
33
|
+
## Next step
|
|
34
|
+
|
|
35
|
+
`plan` for the first prefactor change. When nothing needed fixing, `next`.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Realign notes: 0.0.2
|
|
2
|
+
|
|
3
|
+
## Existing code
|
|
4
|
+
|
|
5
|
+
### test-placement: Rust tests that outgrow their file live in tests/
|
|
6
|
+
- Applies to: existing code
|
|
7
|
+
- Rule: `.agents/skills/cruze-hexagonal-design/languages/rust.md`, "Dependencies and tooling"
|
|
8
|
+
- Detect: check:test-placement
|
|
9
|
+
- Migrate: move `src/<module>/tests.rs` and `src/<module>/tests/*.rs` to the crate's `tests/<module>.rs`, or `tests/<module>/main.rs` with one file per topic, driving the public API. A test whose private seam is the contract, such as a filesystem trait a crash test injects, stays, listed under `check.exceptions` with that reason.
|
|
10
|
+
|
|
11
|
+
### readme-overview: The README says what the project is
|
|
12
|
+
- Applies to: existing code
|
|
13
|
+
- Rule: `.agents/skills/cruze-envision/project.md`, step 9
|
|
14
|
+
- Detect: validate:readme-overview
|
|
15
|
+
- Migrate: write one paragraph under the README's title from the vision's Problem, Users and Goals, ending with a link to `docs/vision.md`.
|
|
16
|
+
|
|
17
|
+
### feature-size: A feature has at most 6 changes
|
|
18
|
+
- Applies to: existing code
|
|
19
|
+
- Rule: `.agents/skills/cruze-architect/feature.md`, step 12
|
|
20
|
+
- Detect: validate:feature-size
|
|
21
|
+
- Migrate: only for features still in progress. Keep the changes that have landed or started, and move the rest into a new feature with `cruze features add`, through `rethink` at feature level.
|
|
22
|
+
|
|
23
|
+
### module-paths: Every file a task writes is inside a module's Path
|
|
24
|
+
- Applies to: existing code
|
|
25
|
+
- Rule: `.agents/skills/cruze-plan/tasks.md`, step 6
|
|
26
|
+
- Detect: validate:outside-module-map
|
|
27
|
+
- Migrate: only for changes still being planned or built. Add the file to its owner's `Path` through `rethink` at architecture level, or move the file.
|
|
28
|
+
|
|
29
|
+
### error-types: Error types exist only where callers handle their cases differently
|
|
30
|
+
- Applies to: existing code
|
|
31
|
+
- Rule: `.agents/skills/cruze-hexagonal-design/SKILL.md`, "Representations and errors"
|
|
32
|
+
- Ask: Does any error type copy another's variants, differ from another only in its name, or carry a case that every caller rules out, such as with `unreachable!` or `expect`? Does a use case define its own error when it only passes a domain error through?
|
|
33
|
+
- Migrate: return or wrap the domain error in one case, merge similar failures into one type with the difference as a field, and narrow return types. Keep wire codes, messages and exit statuses unchanged. When `docs/architecture.md` names the error types, rethink at architecture level before the prefactor.
|
|
34
|
+
|
|
35
|
+
### shared-test-support: Tests share fixtures and harnesses
|
|
36
|
+
- Applies to: existing code
|
|
37
|
+
- Rule: `.agents/skills/cruze-behavioural-testing/SKILL.md`, "Test support"
|
|
38
|
+
- Ask: Do test files define helpers, fixtures or harnesses that another test file or the test support module already has, or share code across crates with `#[path]` includes?
|
|
39
|
+
- Migrate: move each shared helper into the test support module, and in a Rust workspace into one dev-only test-support crate. Replace the copies with uses of it.
|
|
40
|
+
|
|
41
|
+
## New work only
|
|
42
|
+
|
|
43
|
+
### design-review-rubric: Contradictions are blockers, and slices build whole elements
|
|
44
|
+
- Applies to: new work only
|
|
45
|
+
- Rule: `.agents/skills/cruze-roles/design-reviewer.md`, "Rubric"
|
|
46
|
+
|
|
47
|
+
### verified-claims: Research runs every claim the design relies on
|
|
48
|
+
- Applies to: new work only
|
|
49
|
+
- Rule: `.agents/skills/cruze-research/SKILL.md`, "Adopt or build", step 7
|
|
50
|
+
|
|
51
|
+
### design-change-findings: A finding that needs a design change goes to rethink
|
|
52
|
+
- Applies to: new work only
|
|
53
|
+
- Rule: `.agents/skills/cruze-roles/SKILL.md`, "Round 1", step 3
|
|
54
|
+
|
|
55
|
+
### scope-now: Code for a later change waits for that change
|
|
56
|
+
- Applies to: new work only
|
|
57
|
+
- Rule: `.agents/skills/cruze-roles/code-reviewer.md`, rubric item 3
|
|
58
|
+
|
|
59
|
+
### plan-foresight: Plans find callers, respect budgets and lints, and split tests by behaviour
|
|
60
|
+
- Applies to: new work only
|
|
61
|
+
- Rule: `.agents/skills/cruze-plan/tasks.md`
|
|
62
|
+
|
|
63
|
+
### rethink-attribution: Rethinks name the step that found and missed them
|
|
64
|
+
- Applies to: new work only
|
|
65
|
+
- Rule: `.agents/skills/cruze-rethink/SKILL.md`, step 7
|
|
66
|
+
|
|
67
|
+
### recorded-version: Install records the Cruze version and keeps CI on it
|
|
68
|
+
- Applies to: new work only
|
|
69
|
+
- Rule: `cruze install`, which writes `cruze:` in `.cruze/config.yaml` and moves the CI pin
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Realign notes: 0.0.3
|
|
2
|
+
|
|
3
|
+
## New work only
|
|
4
|
+
|
|
5
|
+
### review-helper-fallback: A review runs in a helper when no review agent is configured or installed
|
|
6
|
+
- Applies to: new work only
|
|
7
|
+
- Rule: `.agents/skills/cruze-roles/SKILL.md`, "Running a role", step 3
|
|
8
|
+
|
|
9
|
+
### optional-review-command: review.command is optional, and set only for Claude Code
|
|
10
|
+
- Applies to: new work only
|
|
11
|
+
- Rule: `.agents/skills/cruze-formats/reference/config.md`, "Configuration format"
|