@windyroad/architect 0.15.6 → 0.15.7
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/agents/agent.md
CHANGED
|
@@ -23,6 +23,23 @@ You are the Architect. You review proposed changes against the project's archite
|
|
|
23
23
|
4. Determine if the change requires a new decision to be documented
|
|
24
24
|
5. Report: PASS if compliant, or list issues requiring attention
|
|
25
25
|
|
|
26
|
+
## Review Mode: Pre-edit / proposed-change vs. Post-edit / applied
|
|
27
|
+
|
|
28
|
+
You operate in one of two review modes depending on the calling prompt's framing. Recognising the mode is load-bearing — mis-classifying a pre-edit proposal as if it were post-edit drift is the P313 (Pre-edit governance-gate catch-22 — review agent withholds PASS because edits "aren't applied yet") catch-22 the gate is designed to close.
|
|
29
|
+
|
|
30
|
+
**Pre-edit mode (the default at a governance-gate firing).** The PreToolUse architect gate fires BEFORE a project-file edit lands on disk. The calling prompt describes a PROPOSED change, fix plan, RFC, ticket-body amendment, or about-to-be-made edit — the change is not yet on disk by design. Recognition signals (any one is sufficient): the prompt uses words like "proposed", "plan to", "about to", "PRE-EDIT", "PRE-EDIT alignment gate"; the prompt names the to-be-edited files but the edits are described in prose not yet applied; the prompt is an AFK orchestrator iter dispatch implementing a `## Fix Strategy` against a problem ticket; the prompt is a SKILL handing you an RFC body or story body before the implementation commit lands.
|
|
31
|
+
|
|
32
|
+
In pre-edit mode:
|
|
33
|
+
|
|
34
|
+
- If you receive a review request describing PROPOSED changes (not-yet-applied), classify alignment of the PROPOSAL itself. Not-yet-applied state of the proposed change is the EXPECTED baseline of a pre-edit gate. Do NOT treat "edits aren't applied yet" / "the residual old state is still live" / "the change isn't on disk yet" as ISSUES FOUND — that is the gate's design intent (P313 closes this catch-22).
|
|
35
|
+
- The ground truth you classify against is the **proposal** as described in the calling prompt (the diff sketch, the fix-strategy prose, the file-edit plan). The disk state is the legitimate "old state" the proposal is about to replace.
|
|
36
|
+
- PASS the review when the proposal aligns with existing decisions, the proposal does not require a new decision the user hasn't pinned, and the proposal's substance is sound. ISSUES FOUND on a pre-edit review must cite a problem with the **proposal**, not with the not-yet-applied-ness of the proposal.
|
|
37
|
+
- All other review machinery below (Decision Staleness, Existing Decision Compliance, Confirmation Criteria, New Decision Detection, Runtime-Path Performance, Decision Quality, Unratified Dependency, Needs Direction) applies normally — pre-edit mode does not relax any of those substantive checks. It constrains only the verdict-grammar around the not-yet-applied baseline.
|
|
38
|
+
|
|
39
|
+
**Post-edit mode (the explicit drift-detection or applied-change review).** The calling prompt asks you to verify already-applied edits against decisions — typically a `/wr-architect:review-design` invocation against staged changes and recent commits, or a release-gate audit. Recognition signals: the prompt names "staged changes", "recent commits", "the current diff", "verify compliance", or "review the applied changes against …". In post-edit mode you may flag drift between disk state and decisions exactly as the original verdict grammar describes — the change is on disk by construction; the not-yet-applied carve-out does not apply.
|
|
40
|
+
|
|
41
|
+
**Default when ambiguous.** When the calling prompt does not name the mode explicitly, default to **pre-edit mode** if a PreToolUse gate context is plausible (the prompt was likely fired by `architect-detect.sh` or an AFK iter dispatch). The pre-edit default is the safer fail-mode: a true post-edit drift will still surface as ISSUES FOUND on the substance; a true pre-edit proposal mis-classified as post-edit fires the P313 catch-22.
|
|
42
|
+
|
|
26
43
|
## What You Check
|
|
27
44
|
|
|
28
45
|
### Decision Staleness Check
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# Doc-lint guard: architect agent.md must carry an explicit pre-edit /
|
|
3
|
+
# proposed-change review-mode carve-out so the agent classifies alignment
|
|
4
|
+
# of the PROPOSAL when the calling prompt describes a not-yet-applied
|
|
5
|
+
# change, instead of mis-classifying not-yet-applied state as ISSUES FOUND
|
|
6
|
+
# (P313 catch-22: gate blocks edits; reviewer wants edits done first).
|
|
7
|
+
#
|
|
8
|
+
# tdd-review: structural-permitted (justification: P176 — agent behaviour is
|
|
9
|
+
# prompt-driven with no skill-invocation harness to exercise the verdict
|
|
10
|
+
# behaviourally; ADR-052 Surface 2 structural-justified case, NOT an ADR-005
|
|
11
|
+
# Permitted Exception — ADR-052 narrows ADR-005 to exclude prose-doc greps).
|
|
12
|
+
# When P176 lands, upgrade to a behavioural test that feeds the agent a
|
|
13
|
+
# pre-edit proposal and asserts the PASS verdict.
|
|
14
|
+
#
|
|
15
|
+
# Cross-reference:
|
|
16
|
+
# P313 (Pre-edit governance-gate catch-22 — pass withheld pending edits)
|
|
17
|
+
# ADR-052 Surface 2 (structural-justified verdict) + P176 (harness gap)
|
|
18
|
+
# @jtbd JTBD-001 (Enforce Governance Without Slowing Down — preserves the
|
|
19
|
+
# under-60-second review outcome by removing the redundant
|
|
20
|
+
# re-delegation the catch-22 currently forces)
|
|
21
|
+
|
|
22
|
+
setup() {
|
|
23
|
+
AGENT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
24
|
+
AGENT_FILE="${AGENT_DIR}/agent.md"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@test "agent.md carries a Review Mode section distinguishing pre-edit from post-edit (P313)" {
|
|
28
|
+
run grep -nE "^## Review Mode: Pre-edit / proposed-change vs\. Post-edit / applied" "$AGENT_FILE"
|
|
29
|
+
[ "$status" -eq 0 ]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@test "agent.md classifies alignment of the PROPOSAL in pre-edit mode (P313 verbatim core sentence)" {
|
|
33
|
+
run grep -nE "classify alignment of the PROPOSAL itself" "$AGENT_FILE"
|
|
34
|
+
[ "$status" -eq 0 ]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@test "agent.md treats not-yet-applied state as the EXPECTED baseline of a pre-edit gate (P313)" {
|
|
38
|
+
run grep -nE "EXPECTED baseline of a pre-edit gate" "$AGENT_FILE"
|
|
39
|
+
[ "$status" -eq 0 ]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@test "agent.md explicitly rejects 'edits aren't applied yet' as a valid ISSUES FOUND substance (P313)" {
|
|
43
|
+
run grep -nE "Do NOT treat .edits aren't applied yet" "$AGENT_FILE"
|
|
44
|
+
[ "$status" -eq 0 ]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@test "agent.md cites P313 as the catch-22 closure (audit-trail)" {
|
|
48
|
+
run grep -nE "P313" "$AGENT_FILE"
|
|
49
|
+
[ "$status" -eq 0 ]
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windyroad/architect",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.7",
|
|
4
4
|
"description": "Architecture decision enforcement for AI coding agents",
|
|
5
5
|
"bin": {
|
|
6
6
|
"windyroad-architect": "./bin/install.mjs"
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"skills/",
|
|
26
26
|
"scripts/",
|
|
27
27
|
".claude-plugin/",
|
|
28
|
-
"lib/"
|
|
28
|
+
"lib/",
|
|
29
|
+
"!skills/*/eval/"
|
|
29
30
|
]
|
|
30
31
|
}
|
|
@@ -49,6 +49,24 @@ Empty `$ARGUMENTS` halts per the Rule 6 audit above.
|
|
|
49
49
|
|
|
50
50
|
Derive a kebab-case title slug from the first 8-10 non-stopword tokens of the Title (matching the existing `create-adr` slug derivation pattern).
|
|
51
51
|
|
|
52
|
+
#### Title-as-outcome convention (P354)
|
|
53
|
+
|
|
54
|
+
ADR titles must name the **decision outcome** as a short noun phrase, not the question being decided. The title is the skim-surface for `docs/decisions/` and the ADR-077 compendium — readers should resolve what was decided from the title alone, without opening the file. User direction 2026-06-03 (P354): *"ADR titles are supposed to be the short version of what was decided, so they are skimmable."*
|
|
55
|
+
|
|
56
|
+
**GOOD** (outcome — short noun phrase; drawn from corpus): `marketplace-only-distribution`, `monorepo-per-plugin-packages`, `behavioural-tests-default-for-skill-testing`, `plugin-script-resolution-via-bin-on-path`, `every-fix-goes-through-an-rfc`.
|
|
57
|
+
|
|
58
|
+
**BAD** (question / option-pair / deliberation): `<X>-vs-<Y>` (option-pair), `should-<Z>` (deliberation), `whether-<Z>` (open question), `<X>-or-<Y>` (pure option-set).
|
|
59
|
+
|
|
60
|
+
In `capture-adr` the chosen Decision is pinned in `$ARGUMENTS` at invocation, so the caller SHOULD supply a Title already in outcome shape — the framework does not retitle here (the canonical-outcome short-name is the caller's to author, not the framework's to derive). If the parsed Title slug matches a question-shape pattern (`-vs-`, `should-`, `whether-`, `-or-`), emit an advisory in the I2-isomorphic shape via the shared `emit_stderr_advisory` helper:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
capture-adr: derived title='<slug>' from $ARGUMENTS — slug appears question-shaped (matched <pattern>); the Decision is pinned in $ARGUMENTS so an outcome-shaped Title is recommended; re-invoke with an outcome-shaped Title or rename the file at canonical expansion.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The advisory is **advisory-only** (no halt, no retitle). The caller may proceed with the question-shaped slug if they choose; the subsequent `/wr-architect:create-adr <NNN>` canonical-expansion pass picks up the retitle in its Step 5a mechanical retitle-after-decision check.
|
|
67
|
+
|
|
68
|
+
(Serves JTBD-001 — skimmable titles on the on-disk record; ADR-044 category-4 silent-framework — advisory, not ask.)
|
|
69
|
+
|
|
52
70
|
### 2. Compute the next ADR ID
|
|
53
71
|
|
|
54
72
|
Same P056-safe `local_max + origin_max + 1` formula as `/wr-architect:create-adr` Step 3:
|
|
@@ -34,7 +34,7 @@ Resolve each field via the following dispatch. **The order is load-bearing** —
|
|
|
34
34
|
|
|
35
35
|
| Field | Dispatch | ADR-044 category |
|
|
36
36
|
|-------|----------|------------------|
|
|
37
|
-
| **Title** | Derive silently. Kebab-case the first 8-10 non-stopword tokens of the user's prose problem-statement (same slug derivation as `/wr-itil:capture-problem` Step 1.4, `/wr-itil:manage-incident` Step 4, and `/wr-itil:manage-problem` Step 4 — uses the shared helper's `derive_kebab_slug` function). Emit stderr advisory: `create-adr: derived title='<slug>' from problem-statement; re-invoke with the desired title or rename the file if the slug is wrong`. Do NOT fire AskUserQuestion. | category-4 silent-framework |
|
|
37
|
+
| **Title** | Derive silently. Kebab-case the first 8-10 non-stopword tokens of the user's prose problem-statement (same slug derivation as `/wr-itil:capture-problem` Step 1.4, `/wr-itil:manage-incident` Step 4, and `/wr-itil:manage-problem` Step 4 — uses the shared helper's `derive_kebab_slug` function). At intake the derived slug typically encodes the **question** (the problem-statement is question-shaped); the title-as-outcome convention in Step 2a below names the GOOD/BAD shapes, and Step 5a's mechanical retitle-after-decision check renames the file to the chosen-option's outcome shape after substance-confirm passes. Emit stderr advisory: `create-adr: derived title='<slug>' from problem-statement; re-invoke with the desired title or rename the file if the slug is wrong`. Do NOT fire AskUserQuestion. | category-4 silent-framework |
|
|
38
38
|
| **status** (frontmatter) | Always `proposed` for new ADRs per Step 4 template convention. No ask, no advisory needed — SKILL convention is unambiguous. | category-4 silent-framework |
|
|
39
39
|
| **date** (frontmatter) | Today's date (`date +%Y-%m-%d`) per Step 4 template. No ask, no advisory needed — wall-clock derivation is unambiguous. | category-4 silent-framework |
|
|
40
40
|
| **reassessment-date** (frontmatter) | Today + 3 months (`date -v+3m +%Y-%m-%d` on BSD-date / `date -d '+3 months' +%Y-%m-%d` on GNU-date) per Step 4 template. Emit stderr advisory: `create-adr: derived reassessment-date='<YYYY-MM-DD>' from today+3-months default; re-invoke with --reassessment-date= or edit the frontmatter to override`. | category-4 silent-framework |
|
|
@@ -67,6 +67,30 @@ The advisory text shape is I2-isomorphic — same sentence structure across all
|
|
|
67
67
|
|
|
68
68
|
If the user has already provided context in `$ARGUMENTS` or earlier conversation, use what they've given and only fire AskUserQuestion for the cat-1 fields still missing.
|
|
69
69
|
|
|
70
|
+
### 2a. Title-as-outcome convention (P354)
|
|
71
|
+
|
|
72
|
+
ADR titles must name the **decision outcome** as a short noun phrase, not the question / option-pair being decided. The title is the skim-surface — a reader scanning `docs/decisions/` or the ADR-077 compendium should resolve what was decided from the title alone, without opening the file. User direction 2026-06-03 (P354): *"ADR titles are supposed to be the short version of what was decided, so they are skimmable. Titles like this force the reader to read the document to find the details of what was decided."*
|
|
73
|
+
|
|
74
|
+
**GOOD** (outcome — short noun phrase naming the decided thing; drawn from corpus):
|
|
75
|
+
|
|
76
|
+
- `marketplace-only-distribution`
|
|
77
|
+
- `monorepo-per-plugin-packages`
|
|
78
|
+
- `progressive-disclosure-for-governance-tooling-context`
|
|
79
|
+
- `behavioural-tests-default-for-skill-testing`
|
|
80
|
+
- `plugin-script-resolution-via-bin-on-path`
|
|
81
|
+
- `every-fix-goes-through-an-rfc`
|
|
82
|
+
|
|
83
|
+
**BAD** (question / option-pair / deliberation — reader must open file to learn outcome):
|
|
84
|
+
|
|
85
|
+
- `npm-release-auth-stored-token-vs-oidc` (option-pair pattern `-vs-`)
|
|
86
|
+
- `should-we-adopt-oidc-for-npm-release-auth` (deliberation pattern `should-`)
|
|
87
|
+
- `whether-to-monorepo-or-polyrepo` (open-question pattern `whether-`)
|
|
88
|
+
- `marketplace-or-direct-distribution` (pure option-set pattern `-or-`)
|
|
89
|
+
|
|
90
|
+
**At intake the derived title is acceptable in either shape**: Step 2's `derive_kebab_slug` runs against the problem-statement, which is typically question-shaped. The title-as-outcome convention is enforced at Step 5a's mechanical retitle-after-decision check (post substance-confirm, when the chosen option is locked in). The title need not be outcome-shaped before the decision is made.
|
|
91
|
+
|
|
92
|
+
(Serves JTBD-001 — skimmable titles speed the read path for the governance-enforcement persona.)
|
|
93
|
+
|
|
70
94
|
### 2b. Decision-boundary analysis (multi-decision check)
|
|
71
95
|
|
|
72
96
|
Before writing the ADR file, perform a decision-boundary analysis on the gathered context to prevent conflated ADRs that block independent status transitions and weaken auditability (P017).
|
|
@@ -253,6 +277,20 @@ This is NOT a soft "warn and proceed" path — the marker only ever writes when
|
|
|
253
277
|
|
|
254
278
|
**What the marker means.** This is the load-bearing born-confirmed gate: an ADR recorded through create-adr enters the world already human-oversighted (it does not appear in `/wr-architect:review-decisions`' unoversighted set) ONLY because the substance-confirm fire above explicitly affirmed the chosen option. Do NOT write the marker if the user has not confirmed substance (rejected / still-iterating ADRs stay unmarked). The marker is orthogonal to `status:` — a `proposed` ADR can be `human-oversight: confirmed`.
|
|
255
279
|
|
|
280
|
+
**Retitle-after-decision check (P354 — ADR-044 category-4 silent-framework).** After the marker write lands, check the on-disk filename slug for a question-shape pattern (`-vs-`, `should-`, `whether-`, `-or-`). If matched, the title was derived at intake against a question-shaped problem-statement and must be retitled to the chosen-option's outcome shape now that the substance is locked in. The convention is named in Step 2a above.
|
|
281
|
+
|
|
282
|
+
This step is **mechanical — no AskUserQuestion fires** (per P132 inverse-P078 guard). The chosen option is now known from the substance-confirm answer just above; derive the outcome slug from the chosen-option short name via the same `derive_kebab_slug` helper Step 2's Title derivation uses (`packages/architect/lib/derive-first-dispatch.sh`). Sequence (ordered to preserve marker-discipline hook semantics — the marker-introducing Edit must land BEFORE `git mv`):
|
|
283
|
+
|
|
284
|
+
1. Derive `new_slug = derive_kebab_slug "<chosen option short name>"`.
|
|
285
|
+
2. Edit the H1 in the on-disk file to the new outcome shape (H1 stays human-readable Title Case; the slug is for the filename). The `human-oversight: confirmed` line is already in `OLD_CONTENT` so `architect-oversight-marker-discipline.sh` allows this Edit per its "old content already had the marker" branch.
|
|
286
|
+
3. `git mv docs/decisions/<NNN>-<old-slug>.proposed.md docs/decisions/<NNN>-<new-slug>.proposed.md` (Bash command — no Edit/Write hook fires; rename is captured as a rename in git history).
|
|
287
|
+
4. Emit the I2-isomorphic stderr advisory: `create-adr: retitled <NNN>-<old-slug>.proposed.md -> <NNN>-<new-slug>.proposed.md from chosen-option '<short-name>'; git mv reversible via inverse rename.`
|
|
288
|
+
5. The subsequent compendium regen below picks up the new filename automatically.
|
|
289
|
+
|
|
290
|
+
If the on-disk slug does NOT match a question-shape pattern (already outcome-shaped at intake), skip this step silently — no advisory needed.
|
|
291
|
+
|
|
292
|
+
(Serves JTBD-001 — outcome-shaped on-disk title; category-4 silent-framework per ADR-044.)
|
|
293
|
+
|
|
256
294
|
#### 5b. Draft-quality review fire (optional, after 5a passes)
|
|
257
295
|
|
|
258
296
|
After the substance-confirm fire passes and the marker is written, fire a separate narrow `AskUserQuestion` for draft-quality review:
|