@printpractical/cruze 0.0.9 → 0.0.10
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 +17 -13
- package/dist/adapters/inbound/cli/cli_context.js +4 -0
- package/dist/adapters/inbound/cli/commands/diff.js +23 -0
- package/dist/adapters/inbound/cli/commands/documents.js +1 -1
- package/dist/adapters/inbound/cli/commands/show.js +66 -2
- package/dist/adapters/inbound/cli/commands/status.js +7 -3
- package/dist/adapters/inbound/cli/commands.js +9 -3
- package/dist/adapters/inbound/cli/parse_command.js +8 -0
- package/dist/adapters/outbound/git_repository.js +9 -0
- package/dist/app/ports/repository.js +4 -0
- package/dist/app/use_cases/approve_artifact.js +18 -10
- package/dist/app/use_cases/check_code.js +5 -3
- package/dist/app/use_cases/journal_events.js +6 -2
- package/dist/app/use_cases/new_project_doc.js +10 -2
- package/dist/app/use_cases/run_review.js +10 -2
- package/dist/app/use_cases/show_elements.js +18 -0
- package/dist/app/use_cases/show_notes.js +11 -0
- package/dist/app/use_cases/show_scope.js +15 -1
- package/dist/app/use_cases/upstream_diff.js +55 -0
- package/dist/domain/approvals/rebase.js +39 -0
- package/dist/domain/approvals/upstream_text.js +36 -0
- package/dist/domain/check/check_source.js +18 -1
- package/dist/domain/check/decision_comments.js +38 -0
- package/dist/domain/decision_citations.js +62 -0
- package/dist/domain/edits/agents_file.js +9 -0
- package/dist/domain/ids.js +3 -1
- package/dist/domain/journal.js +3 -1
- package/dist/domain/land/merge_plan.js +7 -2
- package/dist/domain/line_diff.js +56 -0
- package/dist/domain/project/element_lookup.js +124 -0
- package/dist/domain/project/living_model.js +2 -1
- package/dist/domain/project/notes.js +74 -0
- package/dist/domain/skill_budget.js +36 -0
- package/dist/domain/status/next_step.js +27 -5
- package/dist/domain/status/pending_rethink.js +22 -0
- package/dist/domain/status/work_status.js +17 -2
- package/dist/domain/validation/decision_rules.js +76 -0
- package/dist/domain/validation/delta_rules.js +2 -0
- package/dist/domain/validation/future_rules.js +40 -0
- package/dist/domain/validation/living_rules.js +2 -0
- package/dist/domain/validation/validate_project.js +4 -0
- package/dist/domain/validation/vision_rules.js +41 -0
- package/dist/domain/versions/rule_versions.js +3 -0
- package/package.json +1 -1
- package/skills/architect/SKILL.md +2 -1
- package/skills/architect/feature.md +6 -4
- package/skills/architect/project.md +2 -2
- package/skills/behavioural-testing/SKILL.md +3 -2
- package/skills/behavioural-testing/fakes.md +3 -3
- package/skills/build/SKILL.md +2 -2
- package/skills/envision/SKILL.md +3 -2
- package/skills/envision/feature.md +3 -1
- package/skills/envision/intake.md +28 -0
- package/skills/envision/possibilities.md +13 -0
- package/skills/envision/project.md +5 -3
- package/skills/explore/SKILL.md +2 -2
- package/skills/formats/SKILL.md +13 -2
- package/skills/formats/reference/architecture.md +7 -3
- package/skills/formats/reference/durable-docs.md +4 -1
- package/skills/formats/reference/work-items.md +1 -1
- package/skills/formats/templates/vision.md +12 -0
- package/skills/grilling/SKILL.md +10 -0
- package/skills/hexagonal-design/languages/rust.md +2 -1
- package/skills/hexagonal-design/runtime.md +1 -0
- package/skills/land/SKILL.md +6 -2
- package/skills/plan/SKILL.md +13 -3
- package/skills/plan/tasks.md +3 -3
- package/skills/realign/SKILL.md +5 -3
- package/skills/realign/notes/0.0.10.md +131 -0
- package/skills/realign/notes/0.0.2.md +1 -1
- package/skills/realign/notes/0.0.6.md +1 -1
- package/skills/realign/notes/0.0.8.md +1 -1
- package/skills/realign/notes/0.0.9.md +2 -2
- package/skills/realign/notes.md +1 -0
- package/skills/research/SKILL.md +3 -2
- package/skills/rethink/SKILL.md +5 -3
- package/skills/rethink/levels.md +6 -6
- package/skills/roadmap/SKILL.md +2 -1
- package/skills/roles/SKILL.md +3 -3
- package/skills/roles/auditor.md +1 -1
- package/skills/roles/code-reviewer.md +2 -2
- package/skills/roles/design-reviewer.md +4 -40
- package/skills/roles/design-rubric.md +40 -0
- package/skills/roles/plan-rubric.md +11 -0
- package/skills/roles/surveyor.md +3 -2
- package/skills/triage/SKILL.md +1 -1
- package/src/adapters/inbound/cli/cli_context.ts +4 -0
- package/src/adapters/inbound/cli/commands/diff.ts +23 -0
- package/src/adapters/inbound/cli/commands/documents.ts +1 -1
- package/src/adapters/inbound/cli/commands/show.ts +66 -2
- package/src/adapters/inbound/cli/commands/status.ts +7 -3
- package/src/adapters/inbound/cli/commands.ts +9 -3
- package/src/adapters/inbound/cli/parse_command.ts +8 -0
- package/src/adapters/outbound/git_repository.ts +9 -0
- package/src/app/ports/repository.ts +4 -0
- package/src/app/use_cases/approve_artifact.ts +18 -10
- package/src/app/use_cases/check_code.ts +5 -3
- package/src/app/use_cases/journal_events.ts +6 -2
- package/src/app/use_cases/new_project_doc.ts +10 -2
- package/src/app/use_cases/run_review.ts +10 -2
- package/src/app/use_cases/show_elements.ts +18 -0
- package/src/app/use_cases/show_notes.ts +11 -0
- package/src/app/use_cases/show_scope.ts +15 -1
- package/src/app/use_cases/upstream_diff.ts +55 -0
- package/src/domain/approvals/rebase.ts +39 -0
- package/src/domain/approvals/upstream_text.ts +36 -0
- package/src/domain/check/check_source.ts +18 -1
- package/src/domain/check/decision_comments.ts +38 -0
- package/src/domain/decision_citations.ts +62 -0
- package/src/domain/edits/agents_file.ts +9 -0
- package/src/domain/ids.ts +3 -1
- package/src/domain/journal.ts +3 -1
- package/src/domain/land/merge_plan.ts +7 -2
- package/src/domain/line_diff.ts +56 -0
- package/src/domain/project/element_lookup.ts +124 -0
- package/src/domain/project/living_model.ts +2 -1
- package/src/domain/project/notes.ts +74 -0
- package/src/domain/skill_budget.ts +36 -0
- package/src/domain/status/next_step.ts +27 -5
- package/src/domain/status/pending_rethink.ts +22 -0
- package/src/domain/status/work_status.ts +17 -2
- package/src/domain/validation/decision_rules.ts +76 -0
- package/src/domain/validation/delta_rules.ts +2 -0
- package/src/domain/validation/future_rules.ts +40 -0
- package/src/domain/validation/living_rules.ts +2 -0
- package/src/domain/validation/validate_project.ts +4 -0
- package/src/domain/validation/vision_rules.ts +41 -0
- package/src/domain/versions/rule_versions.ts +3 -0
- package/templates/init/AGENTS.md +1 -1
package/skills/research/SKILL.md
CHANGED
|
@@ -15,13 +15,14 @@ Run these steps for each component in a design that isn't domain logic. Domain l
|
|
|
15
15
|
2. Look in order: the language's standard library, the project's already-approved dependencies, then mature libraries in the ecosystem. Done when you have checked all three.
|
|
16
16
|
3. For the two or three serious candidates, gather the evidence in [evaluation.md](evaluation.md).
|
|
17
17
|
4. Recommend one. Adopt a library, or build with a concrete reason: the behaviour is specific to this product, no candidate meets a stated constraint, every candidate brings disproportionate risk or complexity, or the capability is the product itself. Weigh the candidates as `.agents/skills/cruze-dependency-approval/SKILL.md` says under Weighing, where avoiding a dependency is never a reason.
|
|
18
|
-
5. Record the result as a row in the `## Adopt or build` table of the feature or standalone change, as Component, Decision, Choice and Reason. At project scope, record it as the adapter's `Adopts` fact, and put rows for anything no adapter owns in the walking-skeleton change's `## Adopt or build`. When the evidence runs longer than the reason,
|
|
18
|
+
5. Record the result as a row in the `## Adopt or build` table of the feature or standalone change, as Component, Decision, Choice and Reason. At project scope, record it as the adapter's `Adopts` fact, and put rows for anything no adapter owns in the walking-skeleton change's `## Adopt or build`. When the evidence runs longer than the reason, run `cruze new note <slug> --title "<title>" --kind research --about <feature slug or context>`, write the evidence there, and cite that note in the reason.
|
|
19
19
|
6. Take the recommendation to the user. Adopting means a new dependency, which follows `.agents/skills/cruze-dependency-approval/SKILL.md`. Building commodity functionality is the user's call as well.
|
|
20
20
|
7. Verify what the design will rely on. List each claim the design or its testing approach makes about anything it doesn't build:
|
|
21
21
|
- an adopted library or tool: the features or flags it needs, and each command the design spells out, such as a CI step;
|
|
22
22
|
- each type, trait, macro or API the design names from a package: that the package exports it at that version, and every crate, package or target that must declare the package to use it, test support included;
|
|
23
23
|
- the language or runtime, such as whether a trait with async methods can be used as a trait object;
|
|
24
|
-
- the platform's test environment, such as which permissions a test process gets;
|
|
24
|
+
- the platform's test environment, such as which permissions a test process gets, and every package a new test image installs, with the whole suite run once in it;
|
|
25
|
+
- each new method, trait or call shape the design gives the project's own types: compile a sketch beside the methods its receiver already has, on a concrete type and on a trait object, since a new name can be ambiguous on one and not the other;
|
|
25
26
|
- an external system the product talks to, such as what a broker logs or how it answers.
|
|
26
27
|
|
|
27
28
|
Once the user has approved any dependency involved, check each claim by running it: build a scratch project outside the repository with exactly the declared features, and run each command there or with `--help`, or run the external system and watch it. When a claim can't be run, check it in that version's source, and say so. Write the features into the `Adopts` fact or the row's Choice.
|
package/skills/rethink/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ Finding a design flaw mid-build is information, not failure. Rethink amends the
|
|
|
9
9
|
|
|
10
10
|
## Steps
|
|
11
11
|
|
|
12
|
-
1. **State the discovery.** Say what is wrong or new, and quote the evidence: the failing test, the output, the document line, or what the user said.
|
|
12
|
+
1. **State the discovery.** Say what is wrong or new, and quote the evidence: the failing test, the output, the document line, or what the user said. When `cruze next` sent you here for findings decided `rethink`, those findings are the discovery: `cruze show <ref>` lists them in its ledger.
|
|
13
13
|
2. **Classify it.** Pick the level from the table below, using the highest level the discovery touches. Pick its kind:
|
|
14
14
|
- **Defect:** a Cruze step should have caught it.
|
|
15
15
|
- **Discovery:** it is new information no step could have had.
|
|
@@ -19,7 +19,7 @@ Finding a design flaw mid-build is information, not failure. Rethink amends the
|
|
|
19
19
|
4. **Amend that level,** following the level's section in [levels.md](levels.md). Settle any decision the amendment needs with the user, and record it as that level records decisions.
|
|
20
20
|
5. **Keep completed work.** A ticked task stays ticked unless the amendment changes its owner, its files, or what it proves. Reopen each task that changed with `cruze task reopen T<n> "<what changed>"`. Its commits stay in history, and build redoes the task.
|
|
21
21
|
6. **Re-approve what went stale.** Run `cruze status` and work from the top down. The amended document comes first, and the user approves it as its level says. Then take each feature or change it lists as `upstream changed`, whose own text you didn't edit:
|
|
22
|
-
-
|
|
22
|
+
- Run `cruze diff <ref>`. It shows each changed element's approved and current text, and whether the work's delta needs a rebase. Check the work still holds against it. When it doesn't, amend it too, and the user approves it as an amended document.
|
|
23
23
|
- When it holds, re-stamp it with `cruze approve <ref> --restamp-unchanged`. The CLI refuses work whose own text changed, a project document, and a change with a task reopened since its approval; the user re-approves those.
|
|
24
24
|
|
|
25
25
|
Tell the user, in one line each, what you re-stamped and why it still holds. They can object, and that document goes to them. A change's verification carries over when its own design didn't change.
|
|
@@ -32,7 +32,9 @@ Finding a design flaw mid-build is information, not failure. Rethink amends the
|
|
|
32
32
|
--set agent="<the agent you run in>" [--item <ref>]
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Name the feature or change with `--item` whenever the rethink amends one: a rethink recorded for it closes the findings decided `rethink` on it.
|
|
36
|
+
|
|
37
|
+
`found_by` is the step that found it. A defect also needs `missed_by`, the earliest step whose job was to catch it. Both take one of `envision`, `architect`, `research`, `design-review`, `walkthrough`, `plan`, `plan-review`, `build`, `code-review`, `verify`, `land`, `realign`, `improve`, `validate`, `check` or `user`. When a design review ran over the element and an item of its rubric, `.agents/skills/cruze-roles/design-rubric.md` or `.agents/skills/cruze-roles/plan-rubric.md`, covers the gap, `missed_by` is `design-review`, not `architect`: a retro reads it to know which rubric to fix.
|
|
36
38
|
|
|
37
39
|
Done when `cruze status` shows every document approved and current, or names only work the user chose to leave for later.
|
|
38
40
|
|
package/skills/rethink/levels.md
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
1. Edit the change's `## Test plan` or `## Tasks` so they are right. The scope doesn't change at this level; a scope change is a feature-level rethink.
|
|
6
6
|
2. Run `cruze validate`. Done when it reports no errors for the change.
|
|
7
|
-
3. Run the plan review from `.agents/skills/cruze-roles/SKILL.md` on the diff alone, with the design reviewer's plan rubric and `review=plan`.
|
|
7
|
+
3. Run the plan review from `.agents/skills/cruze-roles/SKILL.md` on the diff alone, with the design reviewer's plan rubric, `.agents/skills/cruze-roles/plan-rubric.md`, and `review=plan`.
|
|
8
8
|
4. Re-approve with `cruze approve <change> --by-agent` once the review has closed, as plan does.
|
|
9
9
|
|
|
10
10
|
## Feature
|
|
11
11
|
|
|
12
|
-
1. Edit the feature's `## Spec delta`, `## Architecture delta` or `## Changes`. For a standalone change, edit its own deltas and scope. Write complete bodies, as `architect` does, and keep the scope rules.
|
|
12
|
+
1. Edit the feature's `## Spec delta`, `## Architecture delta` or `## Changes`. Read the elements the discovery touches with `cruze show <ID>`, which prints the living body and this feature's version side by side, and the rest of `feature.md` when the amendment reaches beyond them. For a standalone change, edit its own deltas and scope. Write complete bodies, as `architect` does, and keep the scope rules.
|
|
13
13
|
2. Run `cruze validate`. Done when it reports no errors for the feature or its changes.
|
|
14
14
|
3. Run the design review from the roles skill on the diff alone, with `review=design`. Run the walkthrough of the changed parts, following `.agents/skills/cruze-architect/walkthrough.md`.
|
|
15
15
|
4. Re-approve the feature. For each of its changes that shows as stale, check it against the diff. When the amendment touches the change's scope, test plan or tasks, update them to match, reopen touched tasks, run the plan review on the diff, and re-approve it with `cruze approve <change> --by-agent`. When it doesn't, re-stamp the change as the skill's step 6 describes.
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
- **The current change**, when the rebuild belongs to its work. Add the element to the feature's Changes row for that change and to the change's `Builds`, then re-plan and re-approve the change.
|
|
26
26
|
- **A prefactor**, otherwise. From an up-to-date main, run `architect "<prefactor>"`, which designs it as a standalone change, then `plan`, `build`, `verify` and `land` it before the current change continues.
|
|
27
27
|
6. Run `cruze status`. Every document citing a changed element shows `upstream changed`:
|
|
28
|
-
- When the document's own delta changes that element, rewrite the delta so it keeps your amendment. `cruze approve` refuses it with `rebase-required` until you do. Then approve it with `--rebase <ID>`.
|
|
29
|
-
- Otherwise, check the document against
|
|
28
|
+
- When the document's own delta still changes that element, rewrite the delta so it keeps your amendment. `cruze approve` refuses it with `rebase-required` until you do, and `cruze diff <ref>` names each such element. Then approve it with `--rebase <ID>`.
|
|
29
|
+
- Otherwise, check the document against `cruze diff <ref>`, and re-stamp it or amend it as the skill's step 6 describes. An element the feature already merged, with its delta entry unchanged since, needs no rebase: the living text now holds it, and later lands keep your amendment.
|
|
30
30
|
|
|
31
31
|
## Vision
|
|
32
32
|
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
|
|
38
38
|
## A conflict with living text
|
|
39
39
|
|
|
40
|
-
`cruze approve` refuses a feature or standalone change with `rebase-required` when an element its delta changes was edited in the living docs since its last approval, by a rethink or another branch's land. `cruze land` refuses with `merge-conflict` for the same reason when the approval came first. Either way, the delta would overwrite that edit. Record the rethink at feature level.
|
|
40
|
+
`cruze approve` refuses a feature or standalone change with `rebase-required` when an element its delta changes was edited in the living docs since its last approval, by a rethink, a realign or another branch's land, and the delta would still write that element: the work hasn't merged it yet, or has changed its delta entry since merging it. `cruze land` refuses with `merge-conflict` for the same reason when the approval came first. Either way, the delta would overwrite that edit. Record the rethink at feature level.
|
|
41
41
|
|
|
42
|
-
1. Show the user the element's current text
|
|
42
|
+
1. Show the user `cruze diff <feature>`, which has the element's approved and current text, and the feature's delta for it.
|
|
43
43
|
2. Rewrite the delta's body so that it holds both: their edit, and what this feature needs.
|
|
44
44
|
3. Re-approve the feature with `cruze approve <feature> --rebase <ID>`. This records that the feature now builds on the current text.
|
|
45
45
|
4. Re-approve the change that is landing, when it shows stale; its verification carries over. Then run `land` again.
|
package/skills/roadmap/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ description: Orders the release's features and standalone changes into phases wi
|
|
|
9
9
|
|
|
10
10
|
## Steps
|
|
11
11
|
|
|
12
|
-
1. **Read the state.** Read `docs/vision.md` (goals and feature map), `docs/roadmap.md
|
|
12
|
+
1. **Read the state.** Read `docs/vision.md` (goals and feature map), `docs/roadmap.md`, and `docs/architecture.md` as "Reading it" in `.agents/skills/cruze-formats/reference/architecture.md` says, and run `cruze status`. The vision must be approved. When no roadmap exists, stop: project-scope `architect` creates the first one with the walking skeleton.
|
|
13
13
|
2. **Pick the job.**
|
|
14
14
|
- **Add an item:** a feature or standalone change the user wants in this release. Its slug comes from the feature map when it is there.
|
|
15
15
|
- **Reorder or drop:** the order or scope of the release changed.
|
|
@@ -27,6 +27,7 @@ description: Orders the release's features and standalone changes into phases wi
|
|
|
27
27
|
## Adding an item
|
|
28
28
|
|
|
29
29
|
- Place it in the earliest phase whose items don't block it. Name its blockers: an item blocks it when it builds an element this item extends, or delivers behaviour this item changes.
|
|
30
|
+
- A prefactor restructures code that later items build on, so it goes first: each item it overlaps names it under `Blocked by`. The exception is an item already building, with a change planned or in progress, which the prefactor would rebuild under: the prefactor waits for it and names it under `Blocked by` instead. Put the order to the user either way. One project's realign put a prefactor behind a feature that hadn't started, and the user wanted it first.
|
|
30
31
|
- Add its slug to the coverage row of each goal it serves.
|
|
31
32
|
- A feature that isn't on the feature map gets there first: `cruze features add <slug> --summary <text> --goals <ids>`.
|
|
32
33
|
|
package/skills/roles/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ A role is a prompt with fixed inputs and a report as its only output. It runs in
|
|
|
9
9
|
|
|
10
10
|
| Role | File | Used by |
|
|
11
11
|
| --- | --- | --- |
|
|
12
|
-
| Design reviewer | [design-reviewer.md](design-reviewer.md) | architect, at project and feature scope; plan, for the plan review |
|
|
12
|
+
| Design reviewer | [design-reviewer.md](design-reviewer.md), with [design-rubric.md](design-rubric.md) for a design or [plan-rubric.md](plan-rubric.md) for a plan | architect, at project and feature scope; plan, for the plan review |
|
|
13
13
|
| Code reviewer | [code-reviewer.md](code-reviewer.md) | verify, for the code review |
|
|
14
14
|
| Verifier | [verifier.md](verifier.md) | verify, to run the system |
|
|
15
15
|
| Researcher | [researcher.md](researcher.md) | architect, for adopt-or-build decisions |
|
|
@@ -45,10 +45,10 @@ A review has at most two rounds. Only blockers can force the second one.
|
|
|
45
45
|
- `deferred`: it belongs to later work. When it is future scope, add it with `cruze features add <slug> --summary <text> --goals <ids>`.
|
|
46
46
|
- `rejected`: the finding is wrong, with the reason.
|
|
47
47
|
|
|
48
|
-
A finding whose fix would change an approved element, such as one marked `Needs design change`, is never `deferred` or `waived`. Recommend `rethink` at that element's level now. Once the rethink is done and the code follows it, record the finding as `fixed`.
|
|
48
|
+
A finding whose fix would change an approved element, such as one marked `Needs design change`, is never `deferred` or `waived`. Recommend `rethink` at that element's level now. Once the rethink is done and the code follows it, record the finding as `fixed`. When the user wants the rethink later, record it as `rethink` instead, with `--item` naming the feature or change it amends: `cruze next` and the build gate hold that work until a rethink is recorded for it.
|
|
49
49
|
|
|
50
50
|
Then one line for each finding you are fixing yourself. When there are no exceptions, say what you are fixing and carry on without waiting. The user can object to any line until the work is approved, and that finding becomes an exception: revert its fix and let them decide it.
|
|
51
|
-
5. **Record every disposition:** `cruze journal add disposition --set finding="<rubric item>: <summary>" --set disposition=<fixed|waived|deferred|rejected> --set reason="<reason>" --set review=<design|plan|code> --set decided=<agent|user>`, with the same `--item`. Use `decided=user` for each exception, once the user decides it, and `decided=agent` for each finding you fixed yourself. The CLI refuses `decided=agent` for anything but `fixed`. A recorded disposition is never raised again.
|
|
51
|
+
5. **Record every disposition:** `cruze journal add disposition --set finding="<rubric item>: <summary>" --set disposition=<fixed|waived|deferred|rejected|rethink> --set reason="<reason>" --set review=<design|plan|code> --set decided=<agent|user>`, with the same `--item`. Use `decided=user` for each exception, once the user decides it, and `decided=agent` for each finding you fixed yourself. The CLI refuses `decided=agent` for anything but `fixed`. A recorded disposition is never raised again.
|
|
52
52
|
6. Apply every `fixed` change, then run `cruze validate`. Done when it reports no errors.
|
|
53
53
|
7. When a finding could be caught by a tool, such as a layering, naming or size rule, tell the user which `cruze check` rule or linter setting would catch it next time.
|
|
54
54
|
|
package/skills/roles/auditor.md
CHANGED
|
@@ -6,7 +6,7 @@ You compare a project's existing code and documents with what the installed Cruz
|
|
|
6
6
|
|
|
7
7
|
- The notes to audit, from `cruze realign status`: each note's ID, `Rule`, `Ask` and `Migrate`.
|
|
8
8
|
- In a full audit, the standards instead of notes: `.agents/skills/cruze-hexagonal-design/SKILL.md` and its language file, `.agents/skills/cruze-behavioural-testing/SKILL.md`, and `.agents/skills/cruze-formats/reference/architecture.md`. You audit one module, named with its `Path`.
|
|
9
|
-
- `docs/architecture.md`, for the module map and the elements the code implements.
|
|
9
|
+
- `docs/architecture.md`, for the module map and the elements the code implements: `cruze show --index <context>` lists them, and `cruze show <ID>` prints each.
|
|
10
10
|
- The files in scope: every source and test file under the project's `source` and `tests` globs in `.cruze/config.yaml`, or under the module's `Path`.
|
|
11
11
|
- The settled ledger, as `.agents/skills/cruze-roles/SKILL.md` defines it, and the earlier realign dispositions from `cruze journal list --event disposition`. Never raise a finding they waived.
|
|
12
12
|
|
|
@@ -4,7 +4,7 @@ You review the code a change adds, before it lands. You work in two lanes. The s
|
|
|
4
4
|
|
|
5
5
|
## Inputs
|
|
6
6
|
|
|
7
|
-
- The change's `change.md`, and the output of `cruze show <ref>`: the elements it builds, the scenarios it delivers, the settled decisions and the ledger. Read an element it lists as cited only when the diff calls it
|
|
7
|
+
- The change's `change.md`, and the output of `cruze show <ref>`: the elements it builds, the scenarios it delivers, the settled decisions and the ledger. Read an element it lists as cited only when the diff calls it, with `cruze show <ID>`.
|
|
8
8
|
- The diff under review, from `git diff <base>` for the base commit you are given.
|
|
9
9
|
- The ADRs in `docs/adr/`, and the specs in `docs/specs/` for the capabilities the change touches.
|
|
10
10
|
- The references `cruze show` lists, at the sections the change's elements cite.
|
|
@@ -29,7 +29,7 @@ Review against these items and nothing else. Each finding names one.
|
|
|
29
29
|
5. **Placement.** Every file the diff adds or changes is where the architecture puts its owner, and matches the task's file targets or a recorded deviation.
|
|
30
30
|
6. **Direction.** Dependencies point inward. No technology type crosses a port. Inbound adapters hold no domain rules or workflow.
|
|
31
31
|
7. **Size.** No file holds two responsibilities, and none passes its budget without a recorded exception. No file was split by length alone, leaving one responsibility across files, and no code is bent to fit a budget, such as a type alias, a string where an error type belongs, types merged or a function placed away from its owner to stay under a limit.
|
|
32
|
-
8. **Idiom.** The code is idiomatic for the language, uses its standard tooling, and follows the language file's rules, including where tests live. Tests reuse the fixtures and harnesses in the test support module rather than redefining them.
|
|
32
|
+
8. **Idiom.** The code is idiomatic for the language, uses its standard tooling, and follows the language file's rules, including where tests live. Tests reuse the fixtures and harnesses in the test support module rather than redefining them. Each `expect`, `unwrap` or panic in the diff has a reason its case can't happen; one a caller, the clock or a concurrent call can reach is a finding.
|
|
33
33
|
9. **Libraries.** Nothing hand-writes what a mature library does without a recorded `build` decision, and every new dependency has a recorded approval. No code works around a dependency or a feature: hand-written code, a shell command or a less idiomatic construct chosen because the clean one needs a dependency is a finding.
|
|
34
34
|
10. **Contracts.** Each adapter honours its port's `Operations`, and each fake passes the same contract tests as the real adapter.
|
|
35
35
|
11. **Deviations.** Each deviation the change recorded is a choice build may make on its own: a private helper or a new file inside the owner's module, a `check.exceptions` entry, a fixture in the test support module, or two tasks swapped. A deviation that added an element, port operation or scenario, wrote a file outside the owner's module, changed an approved scenario's behaviour or its test, worked around a dependency or a feature, or settled a limit, timeout, message or error case the design doesn't give, needed a rethink: a blocker, with `Needs design change` naming the element. Two projects recorded 13 such deviations.
|
|
@@ -8,7 +8,7 @@ You review a design, or a change's plan, before any code exists. You find the pl
|
|
|
8
8
|
- Feature scope: the feature's `feature.md`, and the output of `cruze show <ref>` for the elements its delta cites, each with where it sits, and the settled ledger.
|
|
9
9
|
- Project scope: `docs/architecture.md`, `.cruze/config.yaml` and `docs/roadmap.md`, plus the walking-skeleton change once it exists.
|
|
10
10
|
- A plan: the change's `change.md`, the output of `cruze show <ref>`, and the output of `cruze status --overlap --change <ref>`.
|
|
11
|
-
- The living docs it builds on: `docs/vision.md`, `docs/glossary.md`, the ADRs in `docs/adr/`, the specs in `docs/specs/` that the artifact cites, and, from `docs/architecture.md`, its Overview, Dependency rules, Cross-cutting concerns and Decisions sections plus each element `cruze show` lists as cited. Read the whole architecture only at project scope.
|
|
11
|
+
- The living docs it builds on: `docs/vision.md`, `docs/glossary.md`, the ADRs in `docs/adr/`, the specs in `docs/specs/` that the artifact cites, and, from `docs/architecture.md`, its Overview, Dependency rules, Cross-cutting concerns and Decisions sections plus each element `cruze show` lists as cited. Read any other element with `cruze show <ID>`, and find what exists with `cruze show --index`. Read the whole architecture only at project scope.
|
|
12
12
|
- The settled ledger, as `.agents/skills/cruze-roles/SKILL.md` defines it, with the output of `cruze journal list --event disposition --item <ref>`.
|
|
13
13
|
- The output of `cruze validate`.
|
|
14
14
|
- The references `cruze show` lists, from `references:` in `.cruze/config.yaml`: read the sections the design cites or relies on.
|
|
@@ -16,46 +16,10 @@ You review a design, or a change's plan, before any code exists. You find the pl
|
|
|
16
16
|
|
|
17
17
|
## Rubric
|
|
18
18
|
|
|
19
|
-
Review against
|
|
19
|
+
Review against one rubric and nothing else, and read only that one. Each finding names one of its items.
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
3. **Placement.** Every new or changed element with code has a `Module` whose `Layer` fits its role and a `File` with a real path. No generic modules, and no file is likely to hold two responsibilities. The layout is the one normal for the kind of system and the language, and every layer, module, package or target split beyond a context's `core` and its adapters has a recorded reason. Every element, fact and value serves a requirement in scope or a `Future` fact the feature map calls for. Anything reserved for a need nobody stated is a finding.
|
|
24
|
-
4. **Direction.** Every dependency points inward and is allowed by the `RULE` elements and the `layers:` in `.cruze/config.yaml`.
|
|
25
|
-
5. **Adopt or build.** Every component that isn't domain logic has an adopt-or-build decision with a reason, and every new dependency is named with the features the design uses. Every type, trait, macro, framework or tool the design names from outside the project comes from a dependency and feature the design approves, declared by each crate, package or target that uses it, test support included, and allowed by the import rules in `XC` and the `layers:` in `.cruze/config.yaml`. A choice whose reason is avoiding a dependency, a crate or a feature, where the idiomatic design needs one, is a concern: name the idiomatic design. Every command the design spells out, such as a CI step, is spelled as that version's `--help` or source shows it. A claim the design relies on that the research left unverified is a blocker.
|
|
26
|
-
6. **Contracts.** Every new or changed port's `Operations` state what each operation guarantees, how it fails, and who owns cleanup. Check each use case and each port operation for the values build would otherwise have to pick: a named error for every failure a caller can meet, where a panic, an `expect` or "caller error" counts as missing; a number for every timeout, limit, buffer and poll interval; what a caller observes after each state transition, and what happens to queued or in-flight work at it; and one owner for every message a scenario quotes. Each one missing is a blocker: two projects settled 35 of them during build, as deviations.
|
|
27
|
-
7. **Flows.** The key scenarios have a `FLOW` whose participants are all in its `Elements`, including the failure paths the scenarios need.
|
|
28
|
-
8. **Consistency.** The design agrees with `docs/architecture.md`, the accepted ADRs, the references and what earlier changes landed, or changes them explicitly through a `MODIFIED` operation or a new ADR. Its own elements agree with each other. Check every pair, not a sample:
|
|
29
|
-
- each use case's `Output` and `Errors` against the `FLOW`s that serve it and the `XC` rules that apply to it;
|
|
30
|
-
- each adapter's duties against the port it implements and the `XC` rules it follows;
|
|
31
|
-
- each guarantee, such as "always fits" or "never returns", against the limits and failures that bound it;
|
|
32
|
-
- each `XC` rule against the other `XC` rules, the `RULE` elements and the `layers:` in `.cruze/config.yaml`, such as a logging rule that every module logs against a build rule that forbids the logging import;
|
|
33
|
-
- each pair of use cases that change the same state, for an interleaving that leaves it wrong, against the concurrency rule in `XC`;
|
|
34
|
-
- at feature scope, the prose in `docs/architecture.md` the delta makes untrue, such as an Overview sentence or a `D<n>` line describing an element the delta splits or replaces.
|
|
35
|
-
- each new or renamed operation, method or builder step against the others the same type, trait or caller reaches, for two names a caller can't tell apart, such as an `events` method beside an `events` trait method the type also implements.
|
|
36
|
-
9. **Slicing.** Each change is a vertical slice that delivers scenarios end to end and can land on its own. The order respects `Depends on`, and the first change proves the design end to end. Each change carries enough work to be worth its own plan review, code review and verify: changes that build one or two elements each on the same adapters or screens, in a chain, are one change split too fine. A change that one verifier run can't hold is split too coarse. A `change-too-small`, `change-too-large` or `feature-size` warning from `cruze validate` is a finding, unless a decision records the user accepting it. A change `Builds` an element only when its delivered scenarios prove the whole body; an element whose duties arrive in several changes is split into elements that each arrive whole. `Depends on` names every earlier change that builds something this change's scenarios need. At project scope, the roadmap starts with the walking skeleton, and every goal in the release is covered.
|
|
37
|
-
10. **Ambiguity.** Name each point where a fresh implementer could reasonably build something different from what the user expects.
|
|
38
|
-
11. **Flow control and recovery.** Follow each message, request and event from its source to its consumer through every task, channel and queue the design names, against `.agents/skills/cruze-hexagonal-design/runtime.md`. Check:
|
|
39
|
-
- each bounded queue or buffer: what a sender does when it is full, and which other work waits meanwhile. One slow peer, link, subscriber or consumer holds up only its own work unless a decision says otherwise, so one queue or one task serving several peers needs a reason. A limit meant to tell a stalled consumer from a burst says how it tells them apart;
|
|
40
|
-
- each place several sources feed one consumer: the order it takes them in, so that none starves;
|
|
41
|
-
- each asynchronous result: how it reaches the request that waits for it, including across a reconnect or a retry;
|
|
42
|
-
- each recovery, such as a reconnect, resubscribe, relist or retry: its schedule and limit, what happens when the recovery itself fails, what is lost between the failure and the recovery and how the consumer learns of it, and the order of steps that loses nothing, such as subscribing before relisting;
|
|
43
|
-
- each loop, task and retry: what stops it, and what shutdown does with the work it holds;
|
|
44
|
-
- each value the design compares with observed state: an adapter can observe it, or the difference is reported for good;
|
|
45
|
-
- each exclusive resource, such as a socket, a device or kernel state: what happens when a second instance or caller claims it.
|
|
46
|
-
|
|
47
|
-
Each one missing that a scenario or an `XC` rule depends on is a blocker: in two projects, 7 of 14 defect rethinks after a design review were one of these, found as late as verify.
|
|
48
|
-
|
|
49
|
-
## Plan rubric
|
|
50
|
-
|
|
51
|
-
When the artifact is a change's plan, review against these items instead.
|
|
52
|
-
|
|
53
|
-
1. **Test plan.** Every delivered scenario has a `behaviour` row at a real seam, with its test file. Every port that a built adapter implements has a `contract` row. Seams need fakes of driven ports only, never mocks of internal code.
|
|
54
|
-
2. **Tasks.** Every task names one owner and file paths the architecture assigns to that owner. Every scope ID is proved by a task. Each task is small enough to build red to green and commit on its own. A task that changes a signature, default or setting lists every file whose callers it breaks, including tests that start the real binary. A task that adds a module, file or dependency lists the file that declares it, such as a crate root, a `mod.rs`, a package manifest or an Xcode project. A rule, text, format or conversion that several elements apply has one owning file, and each later task that applies it names that file as a callee rather than restating it. An accessor, variant or type arrives in the task whose code first handles, matches or constructs it, never in the task that only tests it.
|
|
55
|
-
3. **Order.** Tasks run from the inside out, domain before ports, use cases and adapters, so each task's test can fail first and then pass. A test sits in the task that builds the behaviour it checks: a test that an earlier task's code already passes is in the wrong task. A break the plan names is a behaviour the task's code could get wrong, not an edit that may not compile. The last tasks wire the composition root.
|
|
56
|
-
4. **No design.** Nothing in the plan changes the architecture or the specs. A plan that needs a new element, operation or scenario goes back to `architect` or `rethink`.
|
|
57
|
-
5. **Risks and overlap.** The riskiest task is named, with how it is checked. Overlap with work on other branches is resolved or accepted.
|
|
58
|
-
6. **Ambiguity.** Name each task a fresh implementer could reasonably build differently from what the plan means.
|
|
21
|
+
- A design, at project scope or of a feature or a standalone change: `.agents/skills/cruze-roles/design-rubric.md`.
|
|
22
|
+
- A change's plan: `.agents/skills/cruze-roles/plan-rubric.md`.
|
|
59
23
|
|
|
60
24
|
## Findings
|
|
61
25
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Design rubric
|
|
2
|
+
|
|
3
|
+
The design reviewer's rubric for a design: the architecture at project scope, or the design of a feature or a standalone change. Review against these items and nothing else. Each finding names one.
|
|
4
|
+
|
|
5
|
+
1. **Behaviour.** Every requirement has at least one scenario. Every scenario has concrete values, one WHEN, and a THEN a person could check. Failure behaviour the user will meet has its own scenario.
|
|
6
|
+
2. **Seams.** Every scenario can be driven through a use case, or through an inbound adapter when the outcome is what that adapter shows. Every driven port the use case needs can be faked.
|
|
7
|
+
3. **Placement.** Every new or changed element with code has a `Module` whose `Layer` fits its role and a `File` with a real path. No generic modules, and no file is likely to hold two responsibilities. The layout is the one normal for the kind of system and the language, and every layer, module, package or target split beyond a context's `core` and its adapters has a recorded reason. Every element, fact and value serves a requirement in scope, or a `Future` fact the feature map or a `LATER` capability calls for. Anything reserved for a need nobody stated is a finding, and so is anything built, rather than left room for, for a `LATER` capability.
|
|
8
|
+
4. **Direction.** Every dependency points inward and is allowed by the `RULE` elements and the `layers:` in `.cruze/config.yaml`.
|
|
9
|
+
5. **Adopt or build.** Every component that isn't domain logic has an adopt-or-build decision with a reason, and every new dependency is named with the features the design uses. Every type, trait, macro, framework or tool the design names from outside the project comes from a dependency and feature the design approves, declared by each crate, package or target that uses it, test support included, and allowed by the import rules in `XC` and the `layers:` in `.cruze/config.yaml`. A choice whose reason is avoiding a dependency, a crate or a feature, where the idiomatic design needs one, is a concern: name the idiomatic design. Every command the design spells out, such as a CI step, is spelled as that version's `--help` or source shows it. A claim the design relies on that the research left unverified is a blocker.
|
|
10
|
+
6. **Contracts.** Every new or changed port's `Operations` state what each operation guarantees, how it fails, and who owns cleanup. Check each use case and each port operation for the values build would otherwise have to pick: a named error for every failure a caller can meet, where a panic, an `expect` or "caller error" counts as missing; a number for every timeout, limit, buffer and poll interval; what a caller observes after each state transition, and what happens to queued or in-flight work at it; and one owner for every message a scenario quotes. Each one missing is a blocker: two projects settled 35 of them during build, as deviations.
|
|
11
|
+
7. **Flows.** The key scenarios have a `FLOW` whose participants are all in its `Elements`, including the failure paths the scenarios need.
|
|
12
|
+
8. **Consistency.** The design agrees with `docs/architecture.md`, the accepted ADRs, the references and what earlier changes landed, or changes them explicitly through a `MODIFIED` operation or a new ADR. Its own elements agree with each other. Check every pair, not a sample:
|
|
13
|
+
- each use case's `Output` and `Errors` against the `FLOW`s that serve it and the `XC` rules that apply to it;
|
|
14
|
+
- each use case against every port operation it calls: it says what it does with each refusal that operation can answer, from its `Operations` and the use case behind it, and lists the port under `Uses`. A new use of an existing operation, such as the clock stamping a new kind of time, is a `MODIFIED` port whose `Operations` name the use;
|
|
15
|
+
- each adapter's duties against the port it implements and the `XC` rules it follows;
|
|
16
|
+
- each guarantee, such as "always fits" or "never returns", against the limits and failures that bound it;
|
|
17
|
+
- each `XC` rule against the other `XC` rules, the `RULE` elements and the `layers:` in `.cruze/config.yaml`, such as a logging rule that every module logs against a build rule that forbids the logging import;
|
|
18
|
+
- each pair of use cases that change the same state, for an interleaving that leaves it wrong, against the concurrency rule in `XC`;
|
|
19
|
+
- at feature scope, the prose in `docs/architecture.md`, the ADRs and the feature itself that the delta makes untrue, such as an Overview sentence, a `D<n>` line describing an element the delta splits or replaces, or any sentence stating a rule the delta retires;
|
|
20
|
+
- each message or value a scenario quotes from code already built, such as an error's printed form or a revision every write advances, against the code that produces it;
|
|
21
|
+
- each new or renamed operation, method or builder step against the others the same type, trait or caller reaches, for two names a caller can't tell apart, such as an `events` method beside an `events` trait method the type also implements.
|
|
22
|
+
9. **Slicing.** Each change is a vertical slice that delivers scenarios end to end and can land on its own. The order respects `Depends on`, and the first change proves the design end to end. Each change carries enough work to be worth its own plan review, code review and verify: changes that build one or two elements each on the same adapters or screens, in a chain, are one change split too fine. A change that one verifier run can't hold is split too coarse. A `change-too-small`, `change-too-large` or `feature-size` warning from `cruze validate` is a finding, unless a decision records the user accepting it. A change `Builds` an element only when its delivered scenarios prove the whole body; an element whose duties arrive in several changes is split into elements that each arrive whole. `Depends on` names every earlier change that builds something this change's scenarios need. At project scope, the roadmap starts with the walking skeleton, and every goal in the release is covered.
|
|
23
|
+
10. **Ambiguity.** Name each point where a fresh implementer could reasonably build something different from what the user expects.
|
|
24
|
+
11. **Flow control and recovery.** Follow each message, request and event from its source to its consumer through every task, channel and queue the design names, against `.agents/skills/cruze-hexagonal-design/runtime.md`. Check:
|
|
25
|
+
- each bounded queue or buffer: what a sender does when it is full, and which other work waits meanwhile. One slow peer, link, subscriber or consumer holds up only its own work unless a decision says otherwise, so one queue or one task serving several peers needs a reason. A limit meant to tell a stalled consumer from a burst says how it tells them apart;
|
|
26
|
+
- each place several sources feed one consumer: the order it takes them in, so that none starves;
|
|
27
|
+
- each asynchronous result: how it reaches the request that waits for it, including across a reconnect or a retry;
|
|
28
|
+
- each recovery, such as a reconnect, resubscribe, relist or retry: its schedule, its limit and when that count resets, what happens when the recovery itself fails, what is lost between the failure and the recovery and how the consumer learns of it, and the order of steps that loses nothing, such as subscribing before relisting;
|
|
29
|
+
- each loop, task and retry: what stops it, and what shutdown does with the work it holds;
|
|
30
|
+
- each value the design compares with observed state: an adapter can observe it, or the difference is reported for good;
|
|
31
|
+
- each exclusive resource, such as a socket, a device or kernel state: what happens when a second instance or caller claims it.
|
|
32
|
+
|
|
33
|
+
Each one missing that a scenario or an `XC` rule depends on is a blocker: in two projects, 7 of 14 defect rethinks after a design review were one of these, found as late as verify.
|
|
34
|
+
12. **Long-term intent.** Check the design against `## Principles` and `## Must stay possible` in `docs/vision.md`:
|
|
35
|
+
- each principle: the design follows it, or the vision's row was amended for this design and approved;
|
|
36
|
+
- each `LATER` capability, whatever its area: nothing in the design, such as a fixed set, a single owner or a one-way protocol, rules it out; and where the design touches its area, it leaves the room the row names, in a `Future` fact that cites the ID;
|
|
37
|
+
- each part of the user's input handed to this work, as the Notes section of `cruze show` lists it, or `cruze show --notes architect` at project scope: settled with the user, or the design doesn't rest on it;
|
|
38
|
+
- each settled decision of the design that states long-term intent, such as "eventually" or "later": it is a `LATER` row in the vision, since the decision is archived when the work lands.
|
|
39
|
+
|
|
40
|
+
A departure from a principle with no amendment, a `likely` capability closed off, or a design resting on an open hand-off row, is a blocker; a `possible` one closed off is a concern.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Plan rubric
|
|
2
|
+
|
|
3
|
+
The design reviewer's rubric for a change's plan. Review against these items and nothing else. Each finding names one.
|
|
4
|
+
|
|
5
|
+
1. **Test plan.** Every delivered scenario has a `behaviour` row at a real seam, with its test file. Every port that a built adapter implements has a `contract` row. Seams need fakes of driven ports only, never mocks of internal code.
|
|
6
|
+
2. **Tasks.** Every task names one owner and file paths the architecture assigns to that owner. Every scope ID is proved by a task. Each task is small enough to build red to green and commit on its own. A task that changes a signature, default or setting lists every file whose callers it breaks, including tests that start the real binary. A task that adds a module, file or dependency lists the file that declares it, such as a crate root, a `mod.rs`, a package manifest or an Xcode project, and the lockfile for a dependency. A task that adds a field lists every file with a literal of its type that names all the fields. A rule, text, format or conversion that several elements apply has one owning file, and each later task that applies it names that file as a callee rather than restating it. An accessor, variant or type arrives in the task whose code first handles, matches or constructs it, never in the task that only tests it.
|
|
7
|
+
3. **Order.** Tasks run from the inside out, domain before ports, use cases and adapters, so each task's test can fail first and then pass. A test sits in the task that builds the behaviour it checks: a test that an earlier task's code already passes is in the wrong task. A break the plan names is a behaviour the task's code could get wrong, not an edit that may not compile. The last tasks wire the composition root.
|
|
8
|
+
4. **No design.** Nothing in the plan changes the architecture or the specs. A plan that needs a new element, operation or scenario goes back to `architect` or `rethink`.
|
|
9
|
+
5. **Risks and overlap.** The riskiest task is named, with how it is checked, and that check reaches the failure rather than a value a clamp or default hides. Overlap with work on other branches is resolved or accepted.
|
|
10
|
+
6. **Ambiguity.** Name each task a fresh implementer could reasonably build differently from what the plan means.
|
|
11
|
+
7. **Prefactor.** For a change that delivers no scenarios and rebuilds built elements, as "A prefactor" in `.agents/skills/cruze-plan/SKILL.md` describes: `## Risks` names the existing tests that reach each rebuilt element, and the command that runs them; no task adds, edits or deletes a test, except one that pins current behaviour before the restructuring; and no item's visibility or public surface grows beyond what its new callers need.
|
package/skills/roles/surveyor.md
CHANGED
|
@@ -6,7 +6,8 @@ You survey existing code for structure that departs from Cruze's current standar
|
|
|
6
6
|
|
|
7
7
|
- What to survey: the system's layout, or one module, named with its `Path`.
|
|
8
8
|
- The standards: `.agents/skills/cruze-hexagonal-design/SKILL.md`, `.agents/skills/cruze-hexagonal-design/shapes.md`, the language file for the project's language when one exists, and `.agents/skills/cruze-behavioural-testing/SKILL.md`.
|
|
9
|
-
- `docs/architecture.md`, for the module map and the elements the code implements, and `.cruze/config.yaml`.
|
|
9
|
+
- `docs/architecture.md`, for the module map and the elements the code implements, which `cruze show --index` lists and `cruze show <ID>` prints, and `.cruze/config.yaml`.
|
|
10
|
+
- `## Principles` and `## Must stay possible` in `docs/vision.md`: why parts of the design exist that no current feature uses yet.
|
|
10
11
|
- The files in scope: for the layout, the build manifests, such as `Cargo.toml` or `Package.swift`, and each module's `Path`; for a module, every source and test file under its `Path`.
|
|
11
12
|
- The journal, landed work included: the output of `cruze journal list --event deviation --all`, `cruze journal list --event rethink --all` and `cruze journal list --event disposition --all`.
|
|
12
13
|
- The settled ledger, as `.agents/skills/cruze-roles/SKILL.md` defines it, and the earlier `improve` and `realign` dispositions. Never raise a candidate they waived.
|
|
@@ -18,7 +19,7 @@ You survey existing code for structure that departs from Cruze's current standar
|
|
|
18
19
|
3. **The journal.** Find the deviations, rethinks and review findings that name a file in scope, and group them by cause. A cause that recurs is friction.
|
|
19
20
|
4. **The history.** Run `git log --format=%h --name-only -n 300 -- <Path>`. Name the files outside the module that change in the same commits as its files in more than half of those commits; a boundary there is often in the wrong place. Name the files that change most.
|
|
20
21
|
5. **One operation.** Pick one representative operation the module serves, and list the files a reader opens to follow it from the inbound adapter to the outbound one. Note modules that only forward calls, and pairs of modules that own one responsibility between them.
|
|
21
|
-
6. **Shape each candidate.** Give the smallest target that meets the standard or removes the friction, and say whether it changes the text of an element in `docs/architecture.md`. A target keeps behaviour, keeps small files, and keeps every technology behind a port.
|
|
22
|
+
6. **Shape each candidate.** Give the smallest target that meets the standard or removes the friction, and say whether it changes the text of an element in `docs/architecture.md`. A target keeps behaviour, keeps small files, and keeps every technology behind a port. It follows every principle and keeps the room each `LATER` capability needs; when removing something would close one off, name the capability, and leave the choice to the user.
|
|
22
23
|
|
|
23
24
|
Done when every file in scope was read, and every candidate has evidence.
|
|
24
25
|
|
package/skills/triage/SKILL.md
CHANGED
|
@@ -11,7 +11,7 @@ Triage starts from a symptom and ends with a fix, or with the right step to fix
|
|
|
11
11
|
|
|
12
12
|
1. **Capture the symptom.** Get the exact steps, what happened (output, error, exit code), what the user expected, and the environment. Done when you can write the steps as commands.
|
|
13
13
|
2. **Reproduce it.** Run the steps against the real system. Done when you can make it fail on demand and have quoted the output. When you can't reproduce it, ask the user for what differs in their environment, and stop until you can.
|
|
14
|
-
3. **Place it in the living docs.** Find the requirement and scenarios in `docs/specs/` that cover this behaviour, and the flow in `docs/architecture.md` that runs it
|
|
14
|
+
3. **Place it in the living docs.** Find the requirement and scenarios in `docs/specs/` that cover this behaviour, and the flow in `docs/architecture.md` that runs it, with `cruze show --index` and `cruze show <ID>`. Then classify it:
|
|
15
15
|
- **Code defect:** a scenario says what should happen, and the code does something else.
|
|
16
16
|
- **Spec gap:** no scenario covers this case.
|
|
17
17
|
- **Design flaw:** the design as written can't deliver what the scenario says.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { upstreamDiff, type UpstreamDiffReport } from "../../../../app/use_cases/upstream_diff.ts";
|
|
2
|
+
import { requireArgs, type CliContext, type CommandResult } from "../cli_context.ts";
|
|
3
|
+
|
|
4
|
+
export async function runDiff(context: CliContext, args: string[]): Promise<CommandResult> {
|
|
5
|
+
requireArgs(args, ["ref"]);
|
|
6
|
+
const report = await upstreamDiff(context, args[0] ?? "");
|
|
7
|
+
return { json: report, human: render(report) };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function render(report: UpstreamDiffReport): string {
|
|
11
|
+
const lines = [`${report.artifact}: ${report.state}`];
|
|
12
|
+
if (report.changes.length === 0) lines.push("Nothing it cites changed since its approval.");
|
|
13
|
+
for (const change of report.changes) {
|
|
14
|
+
lines.push("", `${change.key}${change.path === undefined ? "" : ` in ${change.path}`}:`);
|
|
15
|
+
lines.push(...(change.diff ?? [change.note ?? ""]).map((line) => ` ${line}`));
|
|
16
|
+
}
|
|
17
|
+
if (report.rebase.length > 0) {
|
|
18
|
+
lines.push("", `Its delta changes ${report.rebase.join(", ")}: rewrite the delta to keep the new text, then approve with ${report.rebase.map((id) => `--rebase ${id}`).join(" ")}.`);
|
|
19
|
+
} else if (report.ref !== undefined && report.state === "upstream-changed") {
|
|
20
|
+
lines.push("", `No rebase needed. When the work still holds against this, re-stamp it with cruze approve ${report.ref} --restamp-unchanged.`);
|
|
21
|
+
}
|
|
22
|
+
return lines.join("\n");
|
|
23
|
+
}
|
|
@@ -34,7 +34,7 @@ export async function runNew(context: CliContext, args: string[], options: Optio
|
|
|
34
34
|
}
|
|
35
35
|
requireArgs(args, ["kind", "slug"]);
|
|
36
36
|
if (args[0] === "note") {
|
|
37
|
-
const report = await createNote(context, args[1] ?? "", requireOption(options.title, "--title"));
|
|
37
|
+
const report = await createNote(context, args[1] ?? "", requireOption(options.title, "--title"), requireOption(options.kind, "--kind"), requireOption(options.about, "--about"));
|
|
38
38
|
return { json: report, human: `Created ${report.path}` };
|
|
39
39
|
}
|
|
40
40
|
const kind = args[0] as NewKind;
|
|
@@ -1,13 +1,54 @@
|
|
|
1
|
+
import { showElements, showIndex } from "../../../../app/use_cases/show_elements.ts";
|
|
2
|
+
import { showNotes } from "../../../../app/use_cases/show_notes.ts";
|
|
3
|
+
import type { Note, NotesFor } from "../../../../domain/project/notes.ts";
|
|
1
4
|
import { showScope, type ScopeReport } from "../../../../app/use_cases/show_scope.ts";
|
|
5
|
+
import { isId } from "../../../../domain/ids.ts";
|
|
6
|
+
import type { ElementIndex } from "../../../../domain/project/element_lookup.ts";
|
|
2
7
|
import type { ShownElement } from "../../../../domain/project/scope_view.ts";
|
|
3
|
-
import { requireArgs, type CliContext, type CommandResult } from "../cli_context.ts";
|
|
8
|
+
import { UsageError, requireArgs, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
|
|
4
9
|
|
|
5
|
-
export async function runShow(context: CliContext, args: string[]): Promise<CommandResult> {
|
|
10
|
+
export async function runShow(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
|
|
11
|
+
if (options.notes) {
|
|
12
|
+
if (args.length > 1 || options.index) throw new UsageError("--notes takes at most one target: project, a step, a feature slug or a context");
|
|
13
|
+
const report = await showNotes(context, args[0]);
|
|
14
|
+
return { json: report, human: "target" in report ? renderNotesFor(report).join("\n").trimEnd() : renderNotes(report.notes) };
|
|
15
|
+
}
|
|
16
|
+
if (options.index) {
|
|
17
|
+
if (args.length > 1) throw new UsageError("--index takes at most one context or capability");
|
|
18
|
+
const index = await showIndex(context, args[0]);
|
|
19
|
+
return { json: index, human: renderIndex(index) };
|
|
20
|
+
}
|
|
6
21
|
requireArgs(args, ["ref"]);
|
|
22
|
+
if (args.every(isId)) {
|
|
23
|
+
const report = await showElements(context, args);
|
|
24
|
+
return { json: report, human: blocks(report.elements).join("\n").trimEnd() };
|
|
25
|
+
}
|
|
26
|
+
if (args.length > 1) throw new UsageError("show takes one feature or change, or one or more element IDs");
|
|
7
27
|
const report = await showScope(context, args[0] ?? "");
|
|
8
28
|
return { json: report, human: render(report) };
|
|
9
29
|
}
|
|
10
30
|
|
|
31
|
+
/** The index as a list an agent scans for what exists, before fetching bodies with `cruze show <ID>`. */
|
|
32
|
+
function renderIndex(index: ElementIndex): string {
|
|
33
|
+
const { architecture, specs } = index.words;
|
|
34
|
+
const lines = [`# Elements`, "", `docs/architecture.md holds ${architecture} words, and docs/specs/ ${specs}. Read an element's body with \`cruze show <ID>\`.`];
|
|
35
|
+
let source = "";
|
|
36
|
+
for (const entry of [...index.entries].sort((a, b) => Number(a.addedBy !== undefined) - Number(b.addedBy !== undefined))) {
|
|
37
|
+
const heading = entry.addedBy === undefined ? entry.source : "In flight, not yet merged";
|
|
38
|
+
if (heading !== source) lines.push("", `## ${heading}`, "");
|
|
39
|
+
source = heading;
|
|
40
|
+
const facts = [
|
|
41
|
+
entry.status,
|
|
42
|
+
entry.place,
|
|
43
|
+
entry.scenarios === undefined ? undefined : `${entry.scenarios} scenarios`,
|
|
44
|
+
entry.addedBy === undefined ? undefined : `added by ${entry.addedBy}`,
|
|
45
|
+
entry.changedBy.length === 0 ? undefined : `changed by ${entry.changedBy.join(", ")}`,
|
|
46
|
+
].filter((f) => f !== undefined);
|
|
47
|
+
lines.push(`- ${entry.id}: ${entry.title}${facts.length === 0 ? "" : ` (${facts.join("; ")})`}`);
|
|
48
|
+
}
|
|
49
|
+
return lines.join("\n");
|
|
50
|
+
}
|
|
51
|
+
|
|
11
52
|
/** The scope as a document an agent reads in place of the living docs. */
|
|
12
53
|
function render(report: ScopeReport): string {
|
|
13
54
|
const lines = [`# ${report.ref}${report.feature === undefined ? "" : ` (feature ${report.feature})`}`, ""];
|
|
@@ -22,6 +63,7 @@ function render(report: ScopeReport): string {
|
|
|
22
63
|
lines.push("## Dispositions", "");
|
|
23
64
|
lines.push(...(report.dispositions.length === 0 ? ["None."] : report.dispositions.map((d) => `- [${d.disposition}, ${d.review}] ${d.finding}: ${d.reason}`)), "");
|
|
24
65
|
if (report.references.length > 0) lines.push("## References", "", ...report.references.map((r) => `- \`${r.path}\`: ${r.use}`), "");
|
|
66
|
+
lines.push(...renderNotesFor(report.notes));
|
|
25
67
|
if (report.missing.length > 0) lines.push("## Missing", "", ...report.missing.map((id) => `- ${id} is defined nowhere`), "");
|
|
26
68
|
return lines.join("\n").trimEnd();
|
|
27
69
|
}
|
|
@@ -30,3 +72,25 @@ function blocks(elements: ShownElement[]): string[] {
|
|
|
30
72
|
if (elements.length === 0) return ["None.", ""];
|
|
31
73
|
return elements.flatMap((element) => [`<!-- ${element.source} -->`, ...element.body.join("\n").trimEnd().split("\n"), ""]);
|
|
32
74
|
}
|
|
75
|
+
|
|
76
|
+
/** The notes about a piece of work and the parts of the user's input handed to it; nothing when there are none. */
|
|
77
|
+
function renderNotesFor(found: NotesFor): string[] {
|
|
78
|
+
if (found.notes.length === 0 && found.handoffs.length === 0) return [];
|
|
79
|
+
return [
|
|
80
|
+
"## Notes",
|
|
81
|
+
"",
|
|
82
|
+
...found.notes.map((n) => `- \`${n.path}\`: ${n.title}${n.kind === undefined ? "" : ` (${n.kind})`}`),
|
|
83
|
+
...found.handoffs.map((h) => `- ${h.part}, from ${h.source} (${h.status}, handed off in \`${h.note}\`)`),
|
|
84
|
+
"",
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function renderNotes(notes: Note[]): string {
|
|
89
|
+
if (notes.length === 0) return "No notes.";
|
|
90
|
+
return notes
|
|
91
|
+
.flatMap((n) => [
|
|
92
|
+
`- \`${n.path}\`: ${n.title} (${n.kind ?? "no kind"}; about ${n.about.length === 0 ? "nothing named" : n.about.join(", ")})`,
|
|
93
|
+
...n.handoff.map((h) => ` - ${h.part} goes to ${h.goesTo} (${h.status})`),
|
|
94
|
+
])
|
|
95
|
+
.join("\n");
|
|
96
|
+
}
|
|
@@ -25,13 +25,13 @@ export async function runStatus(context: CliContext, _args: string[], options: O
|
|
|
25
25
|
const lines = [`Branch: ${report.branch ?? "(none)"}${report.active === undefined ? "" : `, building ${report.active}`}`];
|
|
26
26
|
for (const doc of report.documents) lines.push(describe(doc.artifact, doc));
|
|
27
27
|
for (const feature of report.features) {
|
|
28
|
-
lines.push(describe(`feature ${feature.ref}`, feature.approval));
|
|
28
|
+
lines.push(`${describe(`feature ${feature.ref}`, feature.approval)}${pendingNote(feature.rethinkPending)}`);
|
|
29
29
|
for (const change of feature.changes) {
|
|
30
30
|
const name = change.ref.split("/")[1] ?? change.ref;
|
|
31
|
-
lines.push(change.landed !== undefined ? ` ${name}: landed ${change.landed}` : ` ${describe(name, change.approval)}, tasks ${change.tasksDone}/${change.tasksTotal}`);
|
|
31
|
+
lines.push(change.landed !== undefined ? ` ${name}: landed ${change.landed}` : ` ${describe(name, change.approval)}, tasks ${change.tasksDone}/${change.tasksTotal}${pendingNote(change.rethinkPending)}`);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
for (const change of report.standalone) lines.push(`${describe(`change ${change.ref}`, change.approval)}, tasks ${change.tasksDone}/${change.tasksTotal}`);
|
|
34
|
+
for (const change of report.standalone) lines.push(`${describe(`change ${change.ref}`, change.approval)}, tasks ${change.tasksDone}/${change.tasksTotal}${pendingNote(change.rethinkPending)}`);
|
|
35
35
|
const json = {
|
|
36
36
|
...report,
|
|
37
37
|
documents: report.documents.map(compact),
|
|
@@ -48,6 +48,10 @@ function compact(status: ApprovalStatus): Omit<ApprovalStatus, "record"> & { app
|
|
|
48
48
|
return { ...rest, approvedAt: record.approvedAt, by: record.by, ...(record.basis === undefined ? {} : { basis: record.basis }) };
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
function pendingNote(findings: string[] | undefined): string {
|
|
52
|
+
return findings === undefined ? "" : `, ${findings.length} finding(s) waiting on a rethink`;
|
|
53
|
+
}
|
|
54
|
+
|
|
51
55
|
/** Every step starts a new session: one session that ran plan, build, verify and land reached 745k tokens of context. */
|
|
52
56
|
const FRESH_SESSION = "Run it in a new session, so its context starts empty.";
|
|
53
57
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Handler } from "./cli_context.ts";
|
|
2
2
|
import { runCheck, runLand, runTrace } from "./commands/code.ts";
|
|
3
|
+
import { runDiff } from "./commands/diff.ts";
|
|
3
4
|
import { runApprove, runNew, runValidate } from "./commands/documents.ts";
|
|
4
5
|
import { runInit } from "./commands/init.ts";
|
|
5
6
|
import { runInstall } from "./commands/install.ts";
|
|
@@ -23,7 +24,12 @@ export const COMMANDS: Record<string, Command> = {
|
|
|
23
24
|
validate: { handler: runValidate, options: [], usage: "validate check every document against the formats" },
|
|
24
25
|
status: { handler: runStatus, options: ["gate", "override", "overlap", "change"], usage: "status [--gate build [--override <reason>]] [--overlap [--change <ref>]]" },
|
|
25
26
|
next: { handler: runNext, options: [], usage: "next the step to run next on this branch, and why" },
|
|
26
|
-
|
|
27
|
+
diff: { handler: runDiff, options: [], usage: "diff <ref> what changed upstream of a document since its approval, and whether its delta needs a rebase" },
|
|
28
|
+
show: {
|
|
29
|
+
handler: runShow,
|
|
30
|
+
options: ["index", "notes"],
|
|
31
|
+
usage: "show <ref> | show <ID>... | show --index [<context>] | show --notes [<target>] a change's design, chosen elements, one line per element, or the notes and hand-offs for a target",
|
|
32
|
+
},
|
|
27
33
|
approve: {
|
|
28
34
|
handler: runApprove,
|
|
29
35
|
options: ["replan", "rebase", "by-agent", "restamp-unchanged"],
|
|
@@ -31,8 +37,8 @@ export const COMMANDS: Record<string, Command> = {
|
|
|
31
37
|
},
|
|
32
38
|
new: {
|
|
33
39
|
handler: runNew,
|
|
34
|
-
options: { vision: [], glossary: [], architecture: [], roadmap: [], feature: ["title", "roadmap"], change: ["title", "feature", "roadmap"], adr: ["title"], note: ["title"] },
|
|
35
|
-
usage: "new <vision|glossary|architecture|roadmap> | new <feature|change|adr
|
|
40
|
+
options: { vision: [], glossary: [], architecture: [], roadmap: [], feature: ["title", "roadmap"], change: ["title", "feature", "roadmap"], adr: ["title"], note: ["title", "kind", "about"] },
|
|
41
|
+
usage: "new <vision|glossary|architecture|roadmap> | new <feature|change|adr> <slug> --title <title> [--feature <ref>] [--roadmap <slug>] | new note <slug> --title <title> --kind <input|intake|explore|research> --about <subjects>",
|
|
36
42
|
},
|
|
37
43
|
task: { handler: runTask, options: { done: ["change", "commit"], deviation: ["change"], reopen: ["change"] }, usage: "task <done|deviation|reopen> <T#> [text] [--change <ref>] [--commit <sha>]" },
|
|
38
44
|
features: { handler: runFeatures, options: { add: ["summary", "goals"], update: ["summary"], drop: ["reason"] }, usage: "features <add|update|drop> <slug> [--summary <text>] [--goals <ids>] [--reason <text>]" },
|
|
@@ -54,6 +54,10 @@ export function parseCommand(argv: string[]): ParsedCommand {
|
|
|
54
54
|
blockers: { type: "string" },
|
|
55
55
|
"by-agent": { type: "boolean", default: false },
|
|
56
56
|
"restamp-unchanged": { type: "boolean", default: false },
|
|
57
|
+
index: { type: "boolean", default: false },
|
|
58
|
+
notes: { type: "boolean", default: false },
|
|
59
|
+
kind: { type: "string" },
|
|
60
|
+
about: { type: "string" },
|
|
57
61
|
},
|
|
58
62
|
});
|
|
59
63
|
} catch (error) {
|
|
@@ -78,6 +82,8 @@ export function parseCommand(argv: string[]): ParsedCommand {
|
|
|
78
82
|
rebase: values.rebase,
|
|
79
83
|
byAgent: values["by-agent"],
|
|
80
84
|
restampUnchanged: values["restamp-unchanged"],
|
|
85
|
+
index: values.index,
|
|
86
|
+
notes: values.notes,
|
|
81
87
|
...optional("name", values.name),
|
|
82
88
|
...optional("title", values.title),
|
|
83
89
|
...optional("feature", values.feature),
|
|
@@ -96,6 +102,8 @@ export function parseCommand(argv: string[]): ParsedCommand {
|
|
|
96
102
|
...optional("package", values.package),
|
|
97
103
|
...optional("base", values.base),
|
|
98
104
|
...optional("blockers", values.blockers),
|
|
105
|
+
...optional("kind", values.kind),
|
|
106
|
+
...optional("about", values.about),
|
|
99
107
|
};
|
|
100
108
|
const given = [...new Set(tokens.flatMap((token) => (token.kind === "option" ? [token.name] : [])))];
|
|
101
109
|
return { words: positionals, options, given, help: values.help, version: values.version };
|
|
@@ -45,6 +45,15 @@ export class GitRepository implements Repository {
|
|
|
45
45
|
return new Map(paths.flatMap((path, i) => (blobs[i] === undefined ? [] : [[path, blobs[i]] as [string, string]])));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
async firstCommitAdding(path: string, text: string): Promise<string | null> {
|
|
49
|
+
const commits = await this.git("log", "--reverse", "--format=%H", `-S${text}`, "--", path);
|
|
50
|
+
return commits?.split("\n").find((c) => c !== "") ?? null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async fileAt(commit: string, path: string): Promise<string | null> {
|
|
54
|
+
return (await this.catFiles([`${commit}:${path}`]))[0] ?? null;
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
/** The contents of each object, in order, through one `git cat-file --batch`; undefined for one that is missing. */
|
|
49
58
|
private catFiles(objects: string[]): Promise<Array<string | undefined>> {
|
|
50
59
|
return new Promise((resolve) => {
|