specpipe 1.0.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/skills/sp-build/SKILL.md +15 -0
- package/templates/skills/sp-build-behavior-matrix/SKILL.md +15 -0
- package/templates/skills/sp-challenge/SKILL.md +27 -4
- package/templates/skills/sp-challenge-behavior-matrix/SKILL.md +27 -4
- package/templates/skills/sp-explore/SKILL.md +35 -5
- package/templates/skills/sp-explore-behavior-matrix/SKILL.md +35 -5
- package/templates/skills/sp-fix/SKILL.md +14 -0
- package/templates/skills/sp-fix-behavior-matrix/SKILL.md +14 -0
- package/templates/skills/sp-investigate/SKILL.md +29 -1
- package/templates/skills/sp-investigate-behavior-matrix/SKILL.md +29 -1
- package/templates/skills/sp-plan/SKILL.md +34 -6
- package/templates/skills/sp-plan-behavior-matrix/SKILL.md +34 -6
- package/templates/skills/sp-review/SKILL.md +5 -1
- package/templates/skills/sp-review-behavior-matrix/SKILL.md +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specpipe",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Spec-first development toolkit for agentic AI coding agents — installs skills + guardrails for Claude Code, Codex, Cursor, Antigravity, and more.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"specpipe": "./bin/devkit.js",
|
|
@@ -274,6 +274,7 @@ Derive a checklist from the spec — each "promise" in this build's scope become
|
|
|
274
274
|
- Each open `GAP-NNN` (status not `resolved`) → one `[ ]` line tagged `GAP` (so a parked gap is visible, not silently dropped — see Spec Coverage Gate).
|
|
275
275
|
- Each Not-in-Scope row → one `[N/A]` line (prevents accidental ticking).
|
|
276
276
|
- Each matching project-local invariant entry under `docs/invariants/INV-*.md` with `status: enforced` and a `test_ref` → one `INV-###` checklist line carrying the invariant id and test ref. `candidate` and `confirmed` entries are visible risks/spec obligations but not build gates unless the spec turned them into AS/GAP/BM lines. Use the invariant registry README/schema as base knowledge; README examples are not runtime entries.
|
|
277
|
+
- Each confirmed `## Core Function Model` entry point, seam, external contract, invariant, or optional/absent input is checked through AS/GAP/BM/Constraint coverage, not by a separate checklist line unless the spec names an `AS-NNN`/`C-NNN`. A model entry with no coverage is a Spec Signal.
|
|
277
278
|
- Each `## Sibling Surface Map` confirmed surface is checked through its AS/GAP/BM coverage, not by a separate checklist line. Candidate rows with `GAP-NNN` or `ignore(reason)` are visible context only. A candidate row with missing disposition is a spec signal, not a build requirement to implement.
|
|
278
279
|
|
|
279
280
|
**Completeness invariant (checked, not hoped):** every `AS-NNN` and `C-NNN` in the spec's `## Stories`/Constraints MUST appear on ≥1 checklist line. Every `Coverage = AS-NNN` Behavior Matrix cell MUST appear on exactly one `BM.AS-*` checklist line; every `Coverage = GAP-NNN` Behavior Matrix cell MUST appear on exactly one `GAP-* — BM cell unresolved` checklist line; every `Coverage = N/A` Behavior Matrix cell MUST appear on one `[N/A] BM.NA.*` checklist line. An AS with no line = the checklist is wrong (re-derive), not the spec. A Behavior Matrix cell with no line = QA coverage was dropped. Deriving from Then-nouns alone silently drops AS whose Then is verb-shaped ("retries", "must not send") or whose nouns collide with another AS — anchoring on the ID closes that.
|
|
@@ -390,6 +391,8 @@ Before writing tests, trace all paths and draw a diagram to see gaps upfront —
|
|
|
390
391
|
- External/provider surface (calendar/email/payment/identity) → contract/integration against the verified boundary or provider fake that is itself verified; never a pure mock of the boundary under test.
|
|
391
392
|
- Timing/source cell (`realtime`, `refresh-required`, `persisted+served`, `transient`) → the test must assert that lifecycle point, not just the immediate action response.
|
|
392
393
|
|
|
394
|
+
**Step 2c — Trace Core Function Model:** If the spec has `## Core Function Model`, copy confirmed entry points, internal seams, external contracts, invariants, optional/absent inputs, and unknown semantics into the Coverage Map. Each item must point to `AS-NNN`, `C-NNN`, `GAP-NNN`, or BM coverage. A model item without coverage is a Spec Signal, not permission to invent behavior. Provider/external semantics require a real boundary assertion at the named seam; do not mock the seam the test claims to verify.
|
|
395
|
+
|
|
393
396
|
In the diagram, prefix these rows with `[BM]` and keep the AS id visible:
|
|
394
397
|
|
|
395
398
|
```
|
|
@@ -725,6 +728,17 @@ grep '^\\[x\\] BM\\.AS' "$CHECKLIST" | grep -vE '[[:alnum:]_./-]+:[[:alnum:]_ -]
|
|
|
725
728
|
- **Any terminal lifecycle BM line without a named cascade test → treat as `[~]` or BLOCKED**, depending on release criticality.
|
|
726
729
|
- **Any `GAP-NNN — BM cell unresolved` line → visible open gap, not a build test failure.** Do not implement or test that cell until `/sp-plan` resolves it.
|
|
727
730
|
|
|
731
|
+
### Core Function Model Gate
|
|
732
|
+
|
|
733
|
+
Run this when the spec contains `## Core Function Model`.
|
|
734
|
+
|
|
735
|
+
- Confirmed entry points, seams, provider/external contracts, invariants, and optional/absent inputs must be represented by AS/GAP/BM/Constraint lines.
|
|
736
|
+
- Optional/absent inputs named by the model need a regression AS or GAP.
|
|
737
|
+
- External/provider semantics that affect behavior need AS if stated or GAP if unknown.
|
|
738
|
+
- Any verified code seam claimed in the model must have test evidence at the correct boundary.
|
|
739
|
+
- **No-vacuous-boundary rule:** do not mock the seam the test claims to verify. Mock outside dependencies only.
|
|
740
|
+
- A model entry with no AS/GAP/BM/Constraint coverage means `/sp-plan` did not finish. Emit a Spec Signal and mark DONE_WITH_CONCERNS or BLOCKED depending on release criticality.
|
|
741
|
+
|
|
728
742
|
### Sibling Surface Map Gate
|
|
729
743
|
|
|
730
744
|
Run this when the spec contains `## Sibling Surface Map`.
|
|
@@ -820,6 +834,7 @@ TDD evidence: [S-001: RED (paste 1st failing assertion raw) → GREEN ✓ | test
|
|
|
820
834
|
Checklist: X/Y [x], A/Y [~] (destinations: <story-id list or Known-Gap refs>), B/Y [ ] (reasons), C/Y [N/A]
|
|
821
835
|
Coverage gate (Phase 3.5): PASS — all AS/C carry a test | BLOCKED — uncovered: <AS/C ids> (breadth)
|
|
822
836
|
Behavior Matrix gate: PASS — all BM cells [x] | BLOCKED — uncovered: <BM lines> | CONCERNS — partial/mocked-boundary: <BM lines>
|
|
837
|
+
Core Function Model gate: PASS — model entries covered at correct seam | CONCERNS/BLOCKED — missing coverage or vacuous boundary: <items> | N/A
|
|
823
838
|
Sibling Surface Map gate: PASS — confirmed surfaces covered | CONCERNS — candidate disposition/spec signal: <candidate ids> | N/A
|
|
824
839
|
Invariant gate: PASS — enforced invariants covered | BLOCKED — missing enforced invariant tests: <INV ids> | N/A — no enforced invariants touched
|
|
825
840
|
Edge Case Compliance: [per-story table — every row ✓ or N/A+reason] (depth)
|
|
@@ -274,6 +274,7 @@ Derive a checklist from the spec — each "promise" in this build's scope become
|
|
|
274
274
|
- Each open `GAP-NNN` (status not `resolved`) → one `[ ]` line tagged `GAP` (so a parked gap is visible, not silently dropped — see Spec Coverage Gate).
|
|
275
275
|
- Each Not-in-Scope row → one `[N/A]` line (prevents accidental ticking).
|
|
276
276
|
- Each matching project-local invariant entry under `docs/invariants/INV-*.md` with `status: enforced` and a `test_ref` → one `INV-###` checklist line carrying the invariant id and test ref. `candidate` and `confirmed` entries are visible risks/spec obligations but not build gates unless the spec turned them into AS/GAP/BM lines. Use the invariant registry README/schema as base knowledge; README examples are not runtime entries.
|
|
277
|
+
- Each confirmed `## Core Function Model` entry point, seam, external contract, invariant, or optional/absent input is checked through AS/GAP/BM/Constraint coverage, not by a separate checklist line unless the spec names an `AS-NNN`/`C-NNN`. A model entry with no coverage is a Spec Signal.
|
|
277
278
|
- Each `## Sibling Surface Map` confirmed surface is checked through its AS/GAP/BM coverage, not by a separate checklist line. Candidate rows with `GAP-NNN` or `ignore(reason)` are visible context only. A candidate row with missing disposition is a spec signal, not a build requirement to implement.
|
|
278
279
|
|
|
279
280
|
**Completeness invariant (checked, not hoped):** every `AS-NNN` and `C-NNN` in the spec's `## Stories`/Constraints MUST appear on ≥1 checklist line. Every `Coverage = AS-NNN` Behavior Matrix cell MUST appear on exactly one `BM.AS-*` checklist line; every `Coverage = GAP-NNN` Behavior Matrix cell MUST appear on exactly one `GAP-* — BM cell unresolved` checklist line; every `Coverage = N/A` Behavior Matrix cell MUST appear on one `[N/A] BM.NA.*` checklist line. An AS with no line = the checklist is wrong (re-derive), not the spec. A Behavior Matrix cell with no line = QA coverage was dropped. Deriving from Then-nouns alone silently drops AS whose Then is verb-shaped ("retries", "must not send") or whose nouns collide with another AS — anchoring on the ID closes that.
|
|
@@ -390,6 +391,8 @@ Before writing tests, trace all paths and draw a diagram to see gaps upfront —
|
|
|
390
391
|
- External/provider surface (calendar/email/payment/identity) → contract/integration against the verified boundary or provider fake that is itself verified; never a pure mock of the boundary under test.
|
|
391
392
|
- Timing/source cell (`realtime`, `refresh-required`, `persisted+served`, `transient`) → the test must assert that lifecycle point, not just the immediate action response.
|
|
392
393
|
|
|
394
|
+
**Step 2c — Trace Core Function Model:** If the spec has `## Core Function Model`, copy confirmed entry points, internal seams, external contracts, invariants, optional/absent inputs, and unknown semantics into the Coverage Map. Each item must point to `AS-NNN`, `C-NNN`, `GAP-NNN`, or BM coverage. A model item without coverage is a Spec Signal, not permission to invent behavior. Provider/external semantics require a real boundary assertion at the named seam; do not mock the seam the test claims to verify.
|
|
395
|
+
|
|
393
396
|
In the diagram, prefix these rows with `[BM]` and keep the AS id visible:
|
|
394
397
|
|
|
395
398
|
```
|
|
@@ -725,6 +728,17 @@ grep '^\\[x\\] BM\\.AS' "$CHECKLIST" | grep -vE '[[:alnum:]_./-]+:[[:alnum:]_ -]
|
|
|
725
728
|
- **Any terminal lifecycle BM line without a named cascade test → treat as `[~]` or BLOCKED**, depending on release criticality.
|
|
726
729
|
- **Any `GAP-NNN — BM cell unresolved` line → visible open gap, not a build test failure.** Do not implement or test that cell until `/sp-plan` resolves it.
|
|
727
730
|
|
|
731
|
+
### Core Function Model Gate
|
|
732
|
+
|
|
733
|
+
Run this when the spec contains `## Core Function Model`.
|
|
734
|
+
|
|
735
|
+
- Confirmed entry points, seams, provider/external contracts, invariants, and optional/absent inputs must be represented by AS/GAP/BM/Constraint lines.
|
|
736
|
+
- Optional/absent inputs named by the model need a regression AS or GAP.
|
|
737
|
+
- External/provider semantics that affect behavior need AS if stated or GAP if unknown.
|
|
738
|
+
- Any verified code seam claimed in the model must have test evidence at the correct boundary.
|
|
739
|
+
- **No-vacuous-boundary rule:** do not mock the seam the test claims to verify. Mock outside dependencies only.
|
|
740
|
+
- A model entry with no AS/GAP/BM/Constraint coverage means `/sp-plan` did not finish. Emit a Spec Signal and mark DONE_WITH_CONCERNS or BLOCKED depending on release criticality.
|
|
741
|
+
|
|
728
742
|
### Sibling Surface Map Gate
|
|
729
743
|
|
|
730
744
|
Run this when the spec contains `## Sibling Surface Map`.
|
|
@@ -820,6 +834,7 @@ TDD evidence: [S-001: RED (paste 1st failing assertion raw) → GREEN ✓ | test
|
|
|
820
834
|
Checklist: X/Y [x], A/Y [~] (destinations: <story-id list or Known-Gap refs>), B/Y [ ] (reasons), C/Y [N/A]
|
|
821
835
|
Coverage gate (Phase 3.5): PASS — all AS/C carry a test | BLOCKED — uncovered: <AS/C ids> (breadth)
|
|
822
836
|
Behavior Matrix gate: PASS — all BM cells [x] | BLOCKED — uncovered: <BM lines> | CONCERNS — partial/mocked-boundary: <BM lines>
|
|
837
|
+
Core Function Model gate: PASS — model entries covered at correct seam | CONCERNS/BLOCKED — missing coverage or vacuous boundary: <items> | N/A
|
|
823
838
|
Sibling Surface Map gate: PASS — confirmed surfaces covered | CONCERNS — candidate disposition/spec signal: <candidate ids> | N/A
|
|
824
839
|
Invariant gate: PASS — enforced invariants covered | BLOCKED — missing enforced invariant tests: <INV ids> | N/A — no enforced invariants touched
|
|
825
840
|
Edge Case Compliance: [per-story table — every row ✓ or N/A+reason] (depth)
|
|
@@ -30,6 +30,7 @@ Map the plan's attack surface:
|
|
|
30
30
|
- Scope boundaries (in/out/suspiciously unmentioned)
|
|
31
31
|
- Risk acknowledgments (mentioned vs. conspicuously absent)
|
|
32
32
|
- Story↔AS consistency (stories without acceptance scenarios? contradictions?)
|
|
33
|
+
- Core Function Model coverage if present: operation, inputs, entry points, seams, provider contracts, invariants, unknown semantics, and whether each confirmed item maps to AS/GAP/Constraint/BM
|
|
33
34
|
- Behavior Matrix coverage if present: every state/viewer/surface cell, its AS/GAP/N/A coverage, suspicious N/A cells, weak AS cells, missing surfaces, and cascade/parity obligations
|
|
34
35
|
|
|
35
36
|
Collect all file paths the reviewers will need to read.
|
|
@@ -43,9 +44,11 @@ Assess plan complexity and select which lenses to deploy:
|
|
|
43
44
|
| Simple (1 spec section, <20 acceptance scenarios, no auth/data) | 2 | Assumptions + Scope |
|
|
44
45
|
| Standard (multiple sections, auth or data involved) | 3 | + Security |
|
|
45
46
|
| Complex (multiple integrations, concurrency, migrations, 6+ phases) | 4 | + Failure Modes |
|
|
47
|
+
| Core Function Model present, or feature changes provider/payment/auth/data mutation/optional input | +1 reviewer, replacing the lowest-value generic lens if needed to stay capped at 4 | + Core Function & Contract |
|
|
46
48
|
| Behavior Matrix present (`## Behavior Matrix`) | +1 reviewer, replacing the lowest-value generic lens if needed to stay capped at 4 | + Lifecycle & Parity |
|
|
47
49
|
|
|
48
50
|
When in doubt, use 3 reviewers. 4 is for genuinely complex plans.
|
|
51
|
+
If `## Core Function Model` exists, always include the Core Function & Contract lens. This lens is not optional: the model exists because the feature has operation/input/seam/provider risk.
|
|
49
52
|
If `## Behavior Matrix` exists, always include the Lifecycle & Parity lens. This lens is not optional: the matrix exists because the feature has state/viewer/surface risk.
|
|
50
53
|
|
|
51
54
|
## Phase 3: Spawn Parallel Reviewers
|
|
@@ -111,6 +114,23 @@ Examine the plan for:
|
|
|
111
114
|
- OWASP Top 10 (2021): Broken Access Control, Crypto Failures, Injection, Insecure Design, Security Misconfiguration, Vulnerable Components, Identity Failures, Integrity Failures, Logging Failures, SSRF
|
|
112
115
|
```
|
|
113
116
|
|
|
117
|
+
**Core Function & Contract Reviewer:**
|
|
118
|
+
```
|
|
119
|
+
You are reviewing whether the spec models the operation deeply enough before code.
|
|
120
|
+
|
|
121
|
+
Use ONLY stated requirements, related specs, verified code references, and explicit GAPs. Do not invent provider behavior or extra edge cases. Your job is to catch missing operation/input/seam/provider coverage.
|
|
122
|
+
|
|
123
|
+
Examine the plan for:
|
|
124
|
+
- Missing Core Function Model when the feature changes an operation, optional input, provider/external contract, payment/auth/data mutation, stateful flow, or bug-fix path.
|
|
125
|
+
- Incomplete model rows: operation, inputs, entry points, internal seams, external contracts, invariants, or unknown semantics missing without reason.
|
|
126
|
+
- Optional-input holes: omitted input/no-op regression absent when an optional input is added or changed.
|
|
127
|
+
- Provider contract holes: typed IDs, plan applicability, duration/trial/deferred effects, retries/webhooks, rate limits, fail-closed behavior, or server revalidation stated in requirements/code but missing from AS/GAP/Constraint.
|
|
128
|
+
- Code-seam weakness: public entry -> service/helper -> provider/db/cache boundary is not verified, or file:line/symbol/config claims look stale/fabricated.
|
|
129
|
+
- Over-assertion: AS guesses provider semantics that should be GAP because requirements/code do not state it.
|
|
130
|
+
|
|
131
|
+
For suggested fixes, update the spec: add/repair Core Function Model row, add AS/GAP/Constraint, or correct the code reference. Do not suggest implementation code.
|
|
132
|
+
```
|
|
133
|
+
|
|
114
134
|
**Failure Mode Analyst:**
|
|
115
135
|
```
|
|
116
136
|
You believe Murphy's Law: everything that can go wrong, will — simultaneously, at 3 AM, during peak traffic.
|
|
@@ -162,6 +182,8 @@ You are the QA lead who historically found state/viewer/surface bugs on staging.
|
|
|
162
182
|
Use ONLY the plan's stated states, viewers, surfaces, AS, GAP, N/A, constraints, linked fields, and impact map. Do not invent unrelated edge cases. Focus on whether the matrix faithfully covers the behavior the plan already triggered.
|
|
163
183
|
|
|
164
184
|
Examine the plan for:
|
|
185
|
+
- Missing Core Function Model: if the plan changes an operation, input, provider seam, payment/auth/data mutation, or external contract, check whether it has `## Core Function Model` or an explicit reason it is not applicable.
|
|
186
|
+
- Weak provider contract: provider IDs, lifecycle timing, trial/deferred effects, retries/webhooks, and fail-closed behavior must be AS/GAP/Constraint, not only prose.
|
|
165
187
|
- Missing axes: states/statuses, viewer roles/relationships, or surfaces named elsewhere in the spec but absent from `## Behavior Matrix`.
|
|
166
188
|
- Missing sibling discovery: if the plan changes an existing operation or bug-fix path, check whether it has `## Sibling Surface Map` or an explicit reason discovery is not applicable. High/medium sibling candidates must be `cover`, `GAP-NNN`, or `ignore(reason)`; only `cover` candidates may feed Behavior Matrix surfaces.
|
|
167
189
|
- Missing invariant context: if the plan touches a component named by project-local `docs/invariants/INV-*.md`, confirm the relevant invariant is represented in Constraints, GAPs, Behavior Matrix, or explicitly ignored with a reason. Use the invariant registry README/schema as base knowledge only; README examples are not runtime entries. Do not invent new invariant entries here.
|
|
@@ -199,10 +221,11 @@ After all reviewers complete:
|
|
|
199
221
|
4. **Sort** by severity: Critical → High → Medium → Low
|
|
200
222
|
5. **Cap** at 15 findings: keep all Critical, top High by specificity, note how many Medium were dropped
|
|
201
223
|
6. **Cross-reference check** (you, not reviewers): Flag any stories without acceptance scenarios, and any AS that contradicts the story description
|
|
202
|
-
7. **
|
|
203
|
-
8. **
|
|
204
|
-
9. **
|
|
205
|
-
10. **
|
|
224
|
+
7. **Core Function Model cross-check** (you, not reviewers, when present): Every confirmed operation/input/entry-point/seam/provider contract/invariant row must map to AS/GAP/Constraint/BM. If provider/external semantics are unknown, there must be a GAP. If the plan changes an operation/provider/input but has no model, flag missing CFM unless it states why not applicable.
|
|
225
|
+
8. **Behavior Matrix cross-check** (you, not reviewers, when present): Every matrix `Coverage = AS-NNN` must point to an AS that actually asserts the same state/viewer/surface outcome; every `GAP-NNN` must exist in `## Gaps`; every `N/A` must have a reason. Missing or mismatched cells are accepted findings unless another reviewer already caught them.
|
|
226
|
+
9. **Suspicious N/A/GAP Review cross-check** (you, not reviewers, when present): If the plan has `## Behavior Matrix` and any `N/A` or `GAP` cell, the final challenge output MUST include a `Suspicious N/A/GAP Review` section. Omission is itself a Medium finding because it lets lifecycle/viewer/surface blind spots hide behind "not applicable" or unresolved gaps.
|
|
227
|
+
10. **Sibling Surface Map cross-check** (you, not reviewers, when present): If `## Sibling Surface Map` exists, every high/medium candidate must have a disposition (`cover`, `GAP-NNN`, or `ignore(reason)`). If the plan touches an existing operation and has no map, flag missing discovery unless the plan states why sibling discovery is not applicable.
|
|
228
|
+
11. **Invariant registry cross-check** (you, not reviewers, when present): If project-local `docs/invariants/INV-*.md` contains an entry matching the planned component, the plan must either carry it into Constraints/Behavior Matrix/GAPs or explicitly state why it does not apply. Missing invariant handling is a Medium/High finding depending on `status`.
|
|
206
229
|
|
|
207
230
|
## Phase 5: Adjudicate
|
|
208
231
|
|
|
@@ -30,6 +30,7 @@ Map the plan's attack surface:
|
|
|
30
30
|
- Scope boundaries (in/out/suspiciously unmentioned)
|
|
31
31
|
- Risk acknowledgments (mentioned vs. conspicuously absent)
|
|
32
32
|
- Story↔AS consistency (stories without acceptance scenarios? contradictions?)
|
|
33
|
+
- Core Function Model coverage if present: operation, inputs, entry points, seams, provider contracts, invariants, unknown semantics, and whether each confirmed item maps to AS/GAP/Constraint/BM
|
|
33
34
|
- Behavior Matrix coverage if present: every state/viewer/surface cell, its AS/GAP/N/A coverage, suspicious N/A cells, weak AS cells, missing surfaces, and cascade/parity obligations
|
|
34
35
|
|
|
35
36
|
Collect all file paths the reviewers will need to read.
|
|
@@ -43,9 +44,11 @@ Assess plan complexity and select which lenses to deploy:
|
|
|
43
44
|
| Simple (1 spec section, <20 acceptance scenarios, no auth/data) | 2 | Assumptions + Scope |
|
|
44
45
|
| Standard (multiple sections, auth or data involved) | 3 | + Security |
|
|
45
46
|
| Complex (multiple integrations, concurrency, migrations, 6+ phases) | 4 | + Failure Modes |
|
|
47
|
+
| Core Function Model present, or feature changes provider/payment/auth/data mutation/optional input | +1 reviewer, replacing the lowest-value generic lens if needed to stay capped at 4 | + Core Function & Contract |
|
|
46
48
|
| Behavior Matrix present (`## Behavior Matrix`) | +1 reviewer, replacing the lowest-value generic lens if needed to stay capped at 4 | + Lifecycle & Parity |
|
|
47
49
|
|
|
48
50
|
When in doubt, use 3 reviewers. 4 is for genuinely complex plans.
|
|
51
|
+
If `## Core Function Model` exists, always include the Core Function & Contract lens. This lens is not optional: the model exists because the feature has operation/input/seam/provider risk.
|
|
49
52
|
If `## Behavior Matrix` exists, always include the Lifecycle & Parity lens. This lens is not optional: the matrix exists because the feature has state/viewer/surface risk.
|
|
50
53
|
|
|
51
54
|
## Phase 3: Spawn Parallel Reviewers
|
|
@@ -111,6 +114,23 @@ Examine the plan for:
|
|
|
111
114
|
- OWASP Top 10 (2021): Broken Access Control, Crypto Failures, Injection, Insecure Design, Security Misconfiguration, Vulnerable Components, Identity Failures, Integrity Failures, Logging Failures, SSRF
|
|
112
115
|
```
|
|
113
116
|
|
|
117
|
+
**Core Function & Contract Reviewer:**
|
|
118
|
+
```
|
|
119
|
+
You are reviewing whether the spec models the operation deeply enough before code.
|
|
120
|
+
|
|
121
|
+
Use ONLY stated requirements, related specs, verified code references, and explicit GAPs. Do not invent provider behavior or extra edge cases. Your job is to catch missing operation/input/seam/provider coverage.
|
|
122
|
+
|
|
123
|
+
Examine the plan for:
|
|
124
|
+
- Missing Core Function Model when the feature changes an operation, optional input, provider/external contract, payment/auth/data mutation, stateful flow, or bug-fix path.
|
|
125
|
+
- Incomplete model rows: operation, inputs, entry points, internal seams, external contracts, invariants, or unknown semantics missing without reason.
|
|
126
|
+
- Optional-input holes: omitted input/no-op regression absent when an optional input is added or changed.
|
|
127
|
+
- Provider contract holes: typed IDs, plan applicability, duration/trial/deferred effects, retries/webhooks, rate limits, fail-closed behavior, or server revalidation stated in requirements/code but missing from AS/GAP/Constraint.
|
|
128
|
+
- Code-seam weakness: public entry -> service/helper -> provider/db/cache boundary is not verified, or file:line/symbol/config claims look stale/fabricated.
|
|
129
|
+
- Over-assertion: AS guesses provider semantics that should be GAP because requirements/code do not state it.
|
|
130
|
+
|
|
131
|
+
For suggested fixes, update the spec: add/repair Core Function Model row, add AS/GAP/Constraint, or correct the code reference. Do not suggest implementation code.
|
|
132
|
+
```
|
|
133
|
+
|
|
114
134
|
**Failure Mode Analyst:**
|
|
115
135
|
```
|
|
116
136
|
You believe Murphy's Law: everything that can go wrong, will — simultaneously, at 3 AM, during peak traffic.
|
|
@@ -162,6 +182,8 @@ You are the QA lead who historically found state/viewer/surface bugs on staging.
|
|
|
162
182
|
Use ONLY the plan's stated states, viewers, surfaces, AS, GAP, N/A, constraints, linked fields, and impact map. Do not invent unrelated edge cases. Focus on whether the matrix faithfully covers the behavior the plan already triggered.
|
|
163
183
|
|
|
164
184
|
Examine the plan for:
|
|
185
|
+
- Missing Core Function Model: if the plan changes an operation, input, provider seam, payment/auth/data mutation, or external contract, check whether it has `## Core Function Model` or an explicit reason it is not applicable.
|
|
186
|
+
- Weak provider contract: provider IDs, lifecycle timing, trial/deferred effects, retries/webhooks, and fail-closed behavior must be AS/GAP/Constraint, not only prose.
|
|
165
187
|
- Missing axes: states/statuses, viewer roles/relationships, or surfaces named elsewhere in the spec but absent from `## Behavior Matrix`.
|
|
166
188
|
- Missing sibling discovery: if the plan changes an existing operation or bug-fix path, check whether it has `## Sibling Surface Map` or an explicit reason discovery is not applicable. High/medium sibling candidates must be `cover`, `GAP-NNN`, or `ignore(reason)`; only `cover` candidates may feed Behavior Matrix surfaces.
|
|
167
189
|
- Missing invariant context: if the plan touches a component named by project-local `docs/invariants/INV-*.md`, confirm the relevant invariant is represented in Constraints, GAPs, Behavior Matrix, or explicitly ignored with a reason. Use the invariant registry README/schema as base knowledge only; README examples are not runtime entries. Do not invent new invariant entries here.
|
|
@@ -199,10 +221,11 @@ After all reviewers complete:
|
|
|
199
221
|
4. **Sort** by severity: Critical → High → Medium → Low
|
|
200
222
|
5. **Cap** at 15 findings: keep all Critical, top High by specificity, note how many Medium were dropped
|
|
201
223
|
6. **Cross-reference check** (you, not reviewers): Flag any stories without acceptance scenarios, and any AS that contradicts the story description
|
|
202
|
-
7. **
|
|
203
|
-
8. **
|
|
204
|
-
9. **
|
|
205
|
-
10. **
|
|
224
|
+
7. **Core Function Model cross-check** (you, not reviewers, when present): Every confirmed operation/input/entry-point/seam/provider contract/invariant row must map to AS/GAP/Constraint/BM. If provider/external semantics are unknown, there must be a GAP. If the plan changes an operation/provider/input but has no model, flag missing CFM unless it states why not applicable.
|
|
225
|
+
8. **Behavior Matrix cross-check** (you, not reviewers, when present): Every matrix `Coverage = AS-NNN` must point to an AS that actually asserts the same state/viewer/surface outcome; every `GAP-NNN` must exist in `## Gaps`; every `N/A` must have a reason. Missing or mismatched cells are accepted findings unless another reviewer already caught them.
|
|
226
|
+
9. **Suspicious N/A/GAP Review cross-check** (you, not reviewers, when present): If the plan has `## Behavior Matrix` and any `N/A` or `GAP` cell, the final challenge output MUST include a `Suspicious N/A/GAP Review` section. Omission is itself a Medium finding because it lets lifecycle/viewer/surface blind spots hide behind "not applicable" or unresolved gaps.
|
|
227
|
+
10. **Sibling Surface Map cross-check** (you, not reviewers, when present): If `## Sibling Surface Map` exists, every high/medium candidate must have a disposition (`cover`, `GAP-NNN`, or `ignore(reason)`). If the plan touches an existing operation and has no map, flag missing discovery unless the plan states why sibling discovery is not applicable.
|
|
228
|
+
11. **Invariant registry cross-check** (you, not reviewers, when present): If project-local `docs/invariants/INV-*.md` contains an entry matching the planned component, the plan must either carry it into Constraints/Behavior Matrix/GAPs or explicitly state why it does not apply. Missing invariant handling is a Medium/High finding depending on `status`.
|
|
206
229
|
|
|
207
230
|
## Phase 5: Adjudicate
|
|
208
231
|
|
|
@@ -141,14 +141,31 @@ Also note the **project domain** from CLAUDE.md (payment, booking, content, heal
|
|
|
141
141
|
|
|
142
142
|
---
|
|
143
143
|
|
|
144
|
-
## Phase 0.5 —
|
|
144
|
+
## Phase 0.5 — Core Function Discovery (candidate only)
|
|
145
145
|
|
|
146
|
-
Run this after Phase 0 when the feature changes an existing operation, fixes a bug,
|
|
146
|
+
Run this after Phase 0 when the feature changes an existing operation, fixes a bug, touches state/viewer/surface behavior, or integrates with an external provider. Purpose: model the core operation before asking or planning, so later AS/GAP/BM work is driven by the actual function, entry points, seams, and contracts.
|
|
147
147
|
|
|
148
|
-
This pass produces candidates, not requirements. A candidate may become a confirmed surface only after the user/spec/code evidence supports it. Do not auto-promote noisy matches into acceptance scenarios.
|
|
148
|
+
This pass produces candidates and evidence, not requirements. A candidate may become a confirmed surface/contract only after the user/spec/code evidence supports it. Do not auto-promote noisy matches into acceptance scenarios.
|
|
149
149
|
|
|
150
150
|
**Inputs:** raw symptom text, feature nouns, touched component/module, existing code hits from Phase 0, matching project-local `docs/invariants/INV-*.md` entries, and any shared anchors/constants already found.
|
|
151
151
|
|
|
152
|
+
### Core Function Model
|
|
153
|
+
|
|
154
|
+
Record the model first:
|
|
155
|
+
|
|
156
|
+
| Field | Evidence |
|
|
157
|
+
|---|---|
|
|
158
|
+
| Operation | `<create subscription / validate coupon / create appointment / send invite / etc.>` |
|
|
159
|
+
| Inputs | required / optional / absent inputs; identify no-op/omitted-input behavior |
|
|
160
|
+
| Entry points | UI/API/job/webhook/provider callback surfaces that can invoke the operation |
|
|
161
|
+
| Internal seams | route -> service/helper -> provider/db/cache/read-model; include injected/test seams |
|
|
162
|
+
| External contracts | provider/API semantics, IDs, lifecycle timing, retries, trial/deferred effects |
|
|
163
|
+
| State/surface axes | lifecycle/viewer/surface axes if triggered; otherwise `N/A: stateless` |
|
|
164
|
+
| Invariants | fail-closed, server revalidation, no-op unchanged, parity/cascade, no partial side effect |
|
|
165
|
+
| Unknown semantics | must become open questions/GAPs; do not guess provider behavior |
|
|
166
|
+
|
|
167
|
+
### Entry-point / sibling discovery
|
|
168
|
+
|
|
152
169
|
**Deterministic recipe:**
|
|
153
170
|
|
|
154
171
|
1. **Seed nouns and verbs:** extract 3-8 terms such as domain object (`appointment`, `invite`, `matchup`), operation (`create`, `reschedule`, `cancel`, `send`), and surface nouns (`outreach`, `modal`, `guide`, `calendar`, `queue`).
|
|
@@ -157,7 +174,7 @@ This pass produces candidates, not requirements. A candidate may become a confir
|
|
|
157
174
|
4. **Git change-coupling:** inspect recent co-change around seed files with `git log --name-only -- <seed-file>` and look for files/functions repeatedly changed with the seed. This is recall-oriented evidence, not proof.
|
|
158
175
|
5. **GA blast radius if available:** use `ga_impact` for touched symbols/files to find connected blast radius, but do not treat importers-only output as complete sibling discovery. Siblings may be co-changed or share anchors without importing each other.
|
|
159
176
|
|
|
160
|
-
Record every plausible sibling in a table:
|
|
177
|
+
Record every plausible entry point / sibling in a table:
|
|
161
178
|
|
|
162
179
|
| Candidate | Operation | Evidence | Confidence | Obligation |
|
|
163
180
|
|---|---|---|---|---|
|
|
@@ -172,7 +189,7 @@ Rules:
|
|
|
172
189
|
- `GAP`: candidate seems material but expected behavior/scope is unknown.
|
|
173
190
|
- `ignore(reason)`: candidate is false positive or intentionally out of scope.
|
|
174
191
|
|
|
175
|
-
Exit condition: every high/medium candidate has `cover`, `GAP`, or `ignore(reason)`. Low-confidence candidates can be listed as notes and do not block handoff.
|
|
192
|
+
Exit condition: the Core Function Model is filled for every triggered field, and every high/medium entry-point candidate has `cover`, `GAP-NNN`, or `ignore(reason)`. Low-confidence candidates can be listed as notes and do not block handoff.
|
|
176
193
|
|
|
177
194
|
---
|
|
178
195
|
|
|
@@ -719,6 +736,18 @@ Timeout: [if role B does not act within X hours then...]
|
|
|
719
736
|
|
|
720
737
|
**Behavior Matrix discovery axes:** _(required for stateful / role-sensitive / multi-surface features; consumed by `/sp-plan`)_
|
|
721
738
|
|
|
739
|
+
Core Function Model: _(required when Phase 0.5 ran; consumed by `/sp-plan`)_
|
|
740
|
+
| Field | Evidence |
|
|
741
|
+
|---|---|
|
|
742
|
+
| Operation | [core operation being changed] |
|
|
743
|
+
| Inputs | [required / optional / absent inputs + no-op behavior] |
|
|
744
|
+
| Entry points | [UI/API/job/webhook/provider callbacks] |
|
|
745
|
+
| Internal seams | [route -> service/helper -> provider/db/cache/read-model; include test seam] |
|
|
746
|
+
| External contracts | [provider semantics / lifecycle / retries / trial/deferred effects, or N/A] |
|
|
747
|
+
| State/surface axes | [states/viewers/surfaces triggered, or N/A with reason] |
|
|
748
|
+
| Invariants | [fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect] |
|
|
749
|
+
| Unknown semantics | [open questions to become GAPs] |
|
|
750
|
+
|
|
722
751
|
Sibling Candidate Table: _(required when Phase 0.5 ran; consumed by `/sp-plan`)_
|
|
723
752
|
| Candidate | Operation | Evidence | Confidence | Obligation |
|
|
724
753
|
|---|---|---|---|---|
|
|
@@ -817,6 +846,7 @@ Self-check before writing the output file:
|
|
|
817
846
|
- [ ] Input validation is clear for every user-facing field
|
|
818
847
|
- [ ] Permissions are clear for every relevant role
|
|
819
848
|
- [ ] If multi-role: cross-role flow confirmed, including timeouts and conflicts
|
|
849
|
+
- [ ] If Phase 0.5 ran: Core Function Model is filled with operation, inputs, entry points, seams, contracts, invariants, and unknown semantics
|
|
820
850
|
- [ ] If stateful / role-sensitive / multi-surface: Behavior Matrix discovery axes are filled with States, Viewers, Surfaces, and CREATE/READ pair map
|
|
821
851
|
- [ ] If existing-operation or bug-fix discovery ran: Sibling Candidate Table lists every high/medium candidate with cover / GAP / ignore(reason)
|
|
822
852
|
- [ ] UI expectation confirmed — dev team has no room to improvise
|
|
@@ -141,14 +141,31 @@ Also note the **project domain** from CLAUDE.md (payment, booking, content, heal
|
|
|
141
141
|
|
|
142
142
|
---
|
|
143
143
|
|
|
144
|
-
## Phase 0.5 —
|
|
144
|
+
## Phase 0.5 — Core Function Discovery (candidate only)
|
|
145
145
|
|
|
146
|
-
Run this after Phase 0 when the feature changes an existing operation, fixes a bug,
|
|
146
|
+
Run this after Phase 0 when the feature changes an existing operation, fixes a bug, touches state/viewer/surface behavior, or integrates with an external provider. Purpose: model the core operation before asking or planning, so later AS/GAP/BM work is driven by the actual function, entry points, seams, and contracts.
|
|
147
147
|
|
|
148
|
-
This pass produces candidates, not requirements. A candidate may become a confirmed surface only after the user/spec/code evidence supports it. Do not auto-promote noisy matches into acceptance scenarios.
|
|
148
|
+
This pass produces candidates and evidence, not requirements. A candidate may become a confirmed surface/contract only after the user/spec/code evidence supports it. Do not auto-promote noisy matches into acceptance scenarios.
|
|
149
149
|
|
|
150
150
|
**Inputs:** raw symptom text, feature nouns, touched component/module, existing code hits from Phase 0, matching project-local `docs/invariants/INV-*.md` entries, and any shared anchors/constants already found.
|
|
151
151
|
|
|
152
|
+
### Core Function Model
|
|
153
|
+
|
|
154
|
+
Record the model first:
|
|
155
|
+
|
|
156
|
+
| Field | Evidence |
|
|
157
|
+
|---|---|
|
|
158
|
+
| Operation | `<create subscription / validate coupon / create appointment / send invite / etc.>` |
|
|
159
|
+
| Inputs | required / optional / absent inputs; identify no-op/omitted-input behavior |
|
|
160
|
+
| Entry points | UI/API/job/webhook/provider callback surfaces that can invoke the operation |
|
|
161
|
+
| Internal seams | route -> service/helper -> provider/db/cache/read-model; include injected/test seams |
|
|
162
|
+
| External contracts | provider/API semantics, IDs, lifecycle timing, retries, trial/deferred effects |
|
|
163
|
+
| State/surface axes | lifecycle/viewer/surface axes if triggered; otherwise `N/A: stateless` |
|
|
164
|
+
| Invariants | fail-closed, server revalidation, no-op unchanged, parity/cascade, no partial side effect |
|
|
165
|
+
| Unknown semantics | must become open questions/GAPs; do not guess provider behavior |
|
|
166
|
+
|
|
167
|
+
### Entry-point / sibling discovery
|
|
168
|
+
|
|
152
169
|
**Deterministic recipe:**
|
|
153
170
|
|
|
154
171
|
1. **Seed nouns and verbs:** extract 3-8 terms such as domain object (`appointment`, `invite`, `matchup`), operation (`create`, `reschedule`, `cancel`, `send`), and surface nouns (`outreach`, `modal`, `guide`, `calendar`, `queue`).
|
|
@@ -157,7 +174,7 @@ This pass produces candidates, not requirements. A candidate may become a confir
|
|
|
157
174
|
4. **Git change-coupling:** inspect recent co-change around seed files with `git log --name-only -- <seed-file>` and look for files/functions repeatedly changed with the seed. This is recall-oriented evidence, not proof.
|
|
158
175
|
5. **GA blast radius if available:** use `ga_impact` for touched symbols/files to find connected blast radius, but do not treat importers-only output as complete sibling discovery. Siblings may be co-changed or share anchors without importing each other.
|
|
159
176
|
|
|
160
|
-
Record every plausible sibling in a table:
|
|
177
|
+
Record every plausible entry point / sibling in a table:
|
|
161
178
|
|
|
162
179
|
| Candidate | Operation | Evidence | Confidence | Obligation |
|
|
163
180
|
|---|---|---|---|---|
|
|
@@ -172,7 +189,7 @@ Rules:
|
|
|
172
189
|
- `GAP`: candidate seems material but expected behavior/scope is unknown.
|
|
173
190
|
- `ignore(reason)`: candidate is false positive or intentionally out of scope.
|
|
174
191
|
|
|
175
|
-
Exit condition: every high/medium candidate has `cover`, `GAP`, or `ignore(reason)`. Low-confidence candidates can be listed as notes and do not block handoff.
|
|
192
|
+
Exit condition: the Core Function Model is filled for every triggered field, and every high/medium entry-point candidate has `cover`, `GAP-NNN`, or `ignore(reason)`. Low-confidence candidates can be listed as notes and do not block handoff.
|
|
176
193
|
|
|
177
194
|
---
|
|
178
195
|
|
|
@@ -719,6 +736,18 @@ Timeout: [if role B does not act within X hours then...]
|
|
|
719
736
|
|
|
720
737
|
**Behavior Matrix discovery axes:** _(required for stateful / role-sensitive / multi-surface features; consumed by `/sp-plan`)_
|
|
721
738
|
|
|
739
|
+
Core Function Model: _(required when Phase 0.5 ran; consumed by `/sp-plan`)_
|
|
740
|
+
| Field | Evidence |
|
|
741
|
+
|---|---|
|
|
742
|
+
| Operation | [core operation being changed] |
|
|
743
|
+
| Inputs | [required / optional / absent inputs + no-op behavior] |
|
|
744
|
+
| Entry points | [UI/API/job/webhook/provider callbacks] |
|
|
745
|
+
| Internal seams | [route -> service/helper -> provider/db/cache/read-model; include test seam] |
|
|
746
|
+
| External contracts | [provider semantics / lifecycle / retries / trial/deferred effects, or N/A] |
|
|
747
|
+
| State/surface axes | [states/viewers/surfaces triggered, or N/A with reason] |
|
|
748
|
+
| Invariants | [fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect] |
|
|
749
|
+
| Unknown semantics | [open questions to become GAPs] |
|
|
750
|
+
|
|
722
751
|
Sibling Candidate Table: _(required when Phase 0.5 ran; consumed by `/sp-plan`)_
|
|
723
752
|
| Candidate | Operation | Evidence | Confidence | Obligation |
|
|
724
753
|
|---|---|---|---|---|
|
|
@@ -817,6 +846,7 @@ Self-check before writing the output file:
|
|
|
817
846
|
- [ ] Input validation is clear for every user-facing field
|
|
818
847
|
- [ ] Permissions are clear for every relevant role
|
|
819
848
|
- [ ] If multi-role: cross-role flow confirmed, including timeouts and conflicts
|
|
849
|
+
- [ ] If Phase 0.5 ran: Core Function Model is filled with operation, inputs, entry points, seams, contracts, invariants, and unknown semantics
|
|
820
850
|
- [ ] If stateful / role-sensitive / multi-surface: Behavior Matrix discovery axes are filled with States, Viewers, Surfaces, and CREATE/READ pair map
|
|
821
851
|
- [ ] If existing-operation or bug-fix discovery ran: Sibling Candidate Table lists every high/medium candidate with cover / GAP / ignore(reason)
|
|
822
852
|
- [ ] UI expectation confirmed — dev team has no room to improvise
|
|
@@ -83,6 +83,20 @@ Use the invariant registry README/schema as base knowledge; README examples are
|
|
|
83
83
|
- `candidate` → use as an investigation hint; do not treat it as a hard build requirement unless the bug confirms it.
|
|
84
84
|
- `retired` → ignore unless this fix reintroduces the retired component.
|
|
85
85
|
|
|
86
|
+
**Core Function Mapping (required before fix):** Map the bug to the operation it breaks before writing the failing test.
|
|
87
|
+
|
|
88
|
+
| Field | Evidence |
|
|
89
|
+
|---|---|
|
|
90
|
+
| Operation | core create/update/delete/send/read/validate/charge/auth operation |
|
|
91
|
+
| Inputs | required / optional / absent inputs involved in the bug |
|
|
92
|
+
| Entry points | UI/API/job/webhook/provider callback surfaces that can invoke the operation |
|
|
93
|
+
| Internal seams | route -> service/helper -> provider/db/cache/read-model boundary; include test seam |
|
|
94
|
+
| External contracts | provider/API semantics, IDs, lifecycle timing, retries, trial/deferred effects, or N/A |
|
|
95
|
+
| Invariants | fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect |
|
|
96
|
+
| Unknown semantics | spec GAP or investigation question; do not guess |
|
|
97
|
+
|
|
98
|
+
For provider/external/payment/auth/data mutation bugs, identify the public entry → service/helper → provider/db/cache boundary and decide what must be tested. Do not jump from symptom to one-line fix before this mapping.
|
|
99
|
+
|
|
86
100
|
**Sibling Discovery Pass (candidate only):** Run this for lifecycle/parity/cascade bugs, existing-operation fixes, or any bug whose symptom names one surface but the operation may exist on sibling entry-points. This is the same recipe as `/sp-explore` Phase 0.5, scoped to the bug:
|
|
87
101
|
|
|
88
102
|
1. Seed nouns/verbs from the raw symptom, failing test, touched component, and matching invariant entries.
|
|
@@ -83,6 +83,20 @@ Use the invariant registry README/schema as base knowledge; README examples are
|
|
|
83
83
|
- `candidate` → use as an investigation hint; do not treat it as a hard build requirement unless the bug confirms it.
|
|
84
84
|
- `retired` → ignore unless this fix reintroduces the retired component.
|
|
85
85
|
|
|
86
|
+
**Core Function Mapping (required before fix):** Map the bug to the operation it breaks before writing the failing test.
|
|
87
|
+
|
|
88
|
+
| Field | Evidence |
|
|
89
|
+
|---|---|
|
|
90
|
+
| Operation | core create/update/delete/send/read/validate/charge/auth operation |
|
|
91
|
+
| Inputs | required / optional / absent inputs involved in the bug |
|
|
92
|
+
| Entry points | UI/API/job/webhook/provider callback surfaces that can invoke the operation |
|
|
93
|
+
| Internal seams | route -> service/helper -> provider/db/cache/read-model boundary; include test seam |
|
|
94
|
+
| External contracts | provider/API semantics, IDs, lifecycle timing, retries, trial/deferred effects, or N/A |
|
|
95
|
+
| Invariants | fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect |
|
|
96
|
+
| Unknown semantics | spec GAP or investigation question; do not guess |
|
|
97
|
+
|
|
98
|
+
For provider/external/payment/auth/data mutation bugs, identify the public entry → service/helper → provider/db/cache boundary and decide what must be tested. Do not jump from symptom to one-line fix before this mapping.
|
|
99
|
+
|
|
86
100
|
**Sibling Discovery Pass (candidate only):** Run this for lifecycle/parity/cascade bugs, existing-operation fixes, or any bug whose symptom names one surface but the operation may exist on sibling entry-points. This is the same recipe as `/sp-explore` Phase 0.5, scoped to the bug:
|
|
87
101
|
|
|
88
102
|
1. Seed nouns/verbs from the raw symptom, failing test, touched component, and matching invariant entries.
|
|
@@ -134,13 +134,33 @@ Invariant match: <INV/C id + status | invariant text | none | no registry found>
|
|
|
134
134
|
|
|
135
135
|
If no spec or invariant registry exists, continue. Do not invent one during investigation; report the absence as a gap if it matters. If the bug confirms a repeated lifecycle/parity/cascade rule, end the report with `Invariant action needed: add/update invariant: ...`.
|
|
136
136
|
|
|
137
|
+
### 1.55 — Core Function Mapping
|
|
138
|
+
|
|
139
|
+
Run this before Sibling Discovery when the report touches an existing operation, provider/external contract, payment/auth/data mutation, optional input, stateful flow, or cross-surface inconsistency.
|
|
140
|
+
|
|
141
|
+
Purpose: define the operation and seams being investigated so blast radius and root cause do not collapse to the first file that matched the symptom.
|
|
142
|
+
|
|
143
|
+
Record the model in the investigation output:
|
|
144
|
+
|
|
145
|
+
| Field | Evidence |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Operation | core create/update/delete/send/read/validate/charge/auth operation |
|
|
148
|
+
| Inputs | required / optional / absent inputs involved |
|
|
149
|
+
| Entry points | UI/API/job/webhook/provider callback surfaces |
|
|
150
|
+
| Internal seams | route -> service/helper -> provider/db/cache/read-model boundary; include test seam |
|
|
151
|
+
| External contracts | provider/API semantics, IDs, lifecycle timing, retries, trial/deferred effects, or N/A |
|
|
152
|
+
| Invariants | fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect |
|
|
153
|
+
| Unknown semantics | open question or spec GAP; do not guess |
|
|
154
|
+
|
|
155
|
+
For external providers, separate facts verified in code/docs from assumptions. Unknown provider semantics become investigation gaps.
|
|
156
|
+
|
|
137
157
|
### 1.6 — Sibling Discovery Pass (candidate only)
|
|
138
158
|
|
|
139
159
|
Run this for lifecycle/parity/cascade bugs, existing-operation investigations, or any report whose symptom names one surface but the operation may exist on sibling entry-points.
|
|
140
160
|
|
|
141
161
|
Purpose: diagnose blast radius before deciding root cause. This produces candidates, not requirements or fixes.
|
|
142
162
|
|
|
143
|
-
1. Seed nouns/verbs from the raw symptom, touched component, related spec/BM context, and matching invariant entries.
|
|
163
|
+
1. Seed nouns/verbs from the raw symptom, Core Function Mapping, touched component, related spec/BM context, and matching invariant entries.
|
|
144
164
|
2. Find shared-anchor callers (`ga_callers` if GA is available; otherwise grep) for helpers/constants/schemas that define the operation.
|
|
145
165
|
3. Fuzzy-search parallel names such as `create_from_*`, `*_from_<source>`, `send_*invite*`, `*_outcome*`, `reschedule*`, `book_next*`, `cancel*`, `delete*`, plus domain verbs from the symptom.
|
|
146
166
|
4. Inspect recent git co-change around touched files (`git log --name-only -- <seed-file>`) for repeatedly paired files/functions.
|
|
@@ -613,6 +633,14 @@ HYPOTHESIS A (PRIMARY — <confidence>)
|
|
|
613
633
|
Location: <file:line>
|
|
614
634
|
Mechanism: <what is wrong>
|
|
615
635
|
Chain: <cause> → <step> → ... → <symptom>
|
|
636
|
+
Core Function Model:
|
|
637
|
+
Operation: <core operation>
|
|
638
|
+
Inputs: <required / optional / absent inputs involved>
|
|
639
|
+
Entry points: <UI/API/job/webhook/provider callback surfaces>
|
|
640
|
+
Internal seams: <route -> service/helper -> provider/db/cache/read-model>
|
|
641
|
+
External contracts: <provider/API semantics or N/A>
|
|
642
|
+
Invariants: <fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect>
|
|
643
|
+
Unknown semantics: <open question / GAP / none>
|
|
616
644
|
Behavior Matrix:
|
|
617
645
|
State/status: <state or transition>
|
|
618
646
|
Viewer/role: <viewer/relationship>
|
|
@@ -134,13 +134,33 @@ Invariant match: <INV/C id + status | invariant text | none | no registry found>
|
|
|
134
134
|
|
|
135
135
|
If no spec or invariant registry exists, continue. Do not invent one during investigation; report the absence as a gap if it matters. If the bug confirms a repeated lifecycle/parity/cascade rule, end the report with `Invariant action needed: add/update invariant: ...`.
|
|
136
136
|
|
|
137
|
+
### 1.55 — Core Function Mapping
|
|
138
|
+
|
|
139
|
+
Run this before Sibling Discovery when the report touches an existing operation, provider/external contract, payment/auth/data mutation, optional input, stateful flow, or cross-surface inconsistency.
|
|
140
|
+
|
|
141
|
+
Purpose: define the operation and seams being investigated so blast radius and root cause do not collapse to the first file that matched the symptom.
|
|
142
|
+
|
|
143
|
+
Record the model in the investigation output:
|
|
144
|
+
|
|
145
|
+
| Field | Evidence |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Operation | core create/update/delete/send/read/validate/charge/auth operation |
|
|
148
|
+
| Inputs | required / optional / absent inputs involved |
|
|
149
|
+
| Entry points | UI/API/job/webhook/provider callback surfaces |
|
|
150
|
+
| Internal seams | route -> service/helper -> provider/db/cache/read-model boundary; include test seam |
|
|
151
|
+
| External contracts | provider/API semantics, IDs, lifecycle timing, retries, trial/deferred effects, or N/A |
|
|
152
|
+
| Invariants | fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect |
|
|
153
|
+
| Unknown semantics | open question or spec GAP; do not guess |
|
|
154
|
+
|
|
155
|
+
For external providers, separate facts verified in code/docs from assumptions. Unknown provider semantics become investigation gaps.
|
|
156
|
+
|
|
137
157
|
### 1.6 — Sibling Discovery Pass (candidate only)
|
|
138
158
|
|
|
139
159
|
Run this for lifecycle/parity/cascade bugs, existing-operation investigations, or any report whose symptom names one surface but the operation may exist on sibling entry-points.
|
|
140
160
|
|
|
141
161
|
Purpose: diagnose blast radius before deciding root cause. This produces candidates, not requirements or fixes.
|
|
142
162
|
|
|
143
|
-
1. Seed nouns/verbs from the raw symptom, touched component, related spec/BM context, and matching invariant entries.
|
|
163
|
+
1. Seed nouns/verbs from the raw symptom, Core Function Mapping, touched component, related spec/BM context, and matching invariant entries.
|
|
144
164
|
2. Find shared-anchor callers (`ga_callers` if GA is available; otherwise grep) for helpers/constants/schemas that define the operation.
|
|
145
165
|
3. Fuzzy-search parallel names such as `create_from_*`, `*_from_<source>`, `send_*invite*`, `*_outcome*`, `reschedule*`, `book_next*`, `cancel*`, `delete*`, plus domain verbs from the symptom.
|
|
146
166
|
4. Inspect recent git co-change around touched files (`git log --name-only -- <seed-file>`) for repeatedly paired files/functions.
|
|
@@ -613,6 +633,14 @@ HYPOTHESIS A (PRIMARY — <confidence>)
|
|
|
613
633
|
Location: <file:line>
|
|
614
634
|
Mechanism: <what is wrong>
|
|
615
635
|
Chain: <cause> → <step> → ... → <symptom>
|
|
636
|
+
Core Function Model:
|
|
637
|
+
Operation: <core operation>
|
|
638
|
+
Inputs: <required / optional / absent inputs involved>
|
|
639
|
+
Entry points: <UI/API/job/webhook/provider callback surfaces>
|
|
640
|
+
Internal seams: <route -> service/helper -> provider/db/cache/read-model>
|
|
641
|
+
External contracts: <provider/API semantics or N/A>
|
|
642
|
+
Invariants: <fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect>
|
|
643
|
+
Unknown semantics: <open question / GAP / none>
|
|
616
644
|
Behavior Matrix:
|
|
617
645
|
State/status: <state or transition>
|
|
618
646
|
Viewer/role: <viewer/relationship>
|
|
@@ -109,7 +109,8 @@ Before writing anything, run this checklist:
|
|
|
109
109
|
| P0-2 | **Related specs** | List `docs/specs/` directories. Read the main spec of any related feature. Is there overlap? |
|
|
110
110
|
| P0-2b | **Explore doc** | Derive feature name from `$ARGUMENTS` as kebab-case (same convention as `docs/specs/<feature>/`). Check `docs/explore/<feature-name>.md`. If no exact match, list `docs/explore/` and fuzzy-match by keywords. If found → read it. Log: "Explore findings found for '<feature>' — using as primary input. Skipping P0-3, P0-4 (already covered)." Continue with P0-5, P0-6. Full field-to-section mapping + Mode A/B/C scope: see **Explore → Spec mapping** subsection right after this table. |
|
|
111
111
|
| P0-2c | **Invariant registry** | Use the invariant registry README/schema as base knowledge; README examples are not runtime entries. Then read matching project-local entries under `docs/invariants/INV-*.md` when their `component_keys`, `sibling_set`, `shared_anchor`, title, or origin bugs match the feature. Carry `confirmed`/`enforced` invariants into `## Constraints & Invariants`; treat `candidate` entries as risk notes or confirmation GAPs, not automatic requirements. |
|
|
112
|
-
| P0-2d | **
|
|
112
|
+
| P0-2d | **Core Function Model** | If the feature changes an operation, optional input, external/provider contract, payment/auth/data mutation, stateful flow, or bug-fix path, build or refresh `## Core Function Model` before stories. Use code evidence, related specs, explore handoff, project-local invariants, and provider semantics already present in repo/docs. Verify every file:line/symbol/config claim against code. Unknown provider semantics become `GAP-NNN`; do not guess. |
|
|
113
|
+
| P0-2e | **Entry-point / sibling discovery** | If the Core Function Model shows multiple entry points, or the feature changes an existing operation/fix path, run the same candidate-only recipe as `/sp-explore` Phase 0.5 unless an explore doc already provides a Sibling Candidate Table. Sources: raw symptom/feature nouns, project-local invariants, shared anchors (`ga_callers` or grep), fuzzy sibling names (`create_from_*`, `*_from_*`, `send_*invite*`, `*_outcome*`, `reschedule*`, `book_next*`, etc.), and recent git co-change. Output feeds `## Sibling Candidate Table`; high/medium candidates must be `cover`, `GAP-NNN`, or `ignore(reason)`. Candidates do not become requirements until confirmed. |
|
|
113
114
|
| P0-3 | **Dependency scan** | `ga_architecture` for the module map and `ga_importers` / `ga_callees` on touched symbols to see what this code reaches. Manual import-grep is a fallback. |
|
|
114
115
|
| P0-4 | **Reusable utilities** | `ga_symbols` (fuzzy match) on names like `validate`, `format`, `parse`, `<domain>Helper` to find existing helpers; `ga_hubs` to surface the most-connected utilities worth reusing. |
|
|
115
116
|
| P0-5 | **Project patterns** | Identify test framework, naming conventions, directory structure from existing code. |
|
|
@@ -412,8 +413,31 @@ point to a `GAP-NNN`. See Phase 1 §"Linked fields — pin cross-spec contracts
|
|
|
412
413
|
- `<field>` — consumed by `<sibling>:AS-NNN` on <surface> (<persisted+served | transient-in-response>).
|
|
413
414
|
Produced by `<sibling>:AS-NNN` on <surface>. ✔ match. | ✘ <surface|lifecycle> mismatch → GAP-NNN.]
|
|
414
415
|
|
|
416
|
+
## Core Function Model
|
|
417
|
+
[OPTIONAL — required when P0-2d ran or the explore handoff includes a Core Function Model.
|
|
418
|
+
|
|
419
|
+
Purpose: model the operation before AS/BM/GAP so code seams, optional inputs, and provider contracts
|
|
420
|
+
are not lost while writing acceptance scenarios.
|
|
421
|
+
|
|
422
|
+
| Field | Evidence |
|
|
423
|
+
|---|---|
|
|
424
|
+
| Operation | [core operation being changed] |
|
|
425
|
+
| Inputs | [required / optional / absent inputs; no-op behavior] |
|
|
426
|
+
| Entry points | [UI/API/job/webhook/provider callback surfaces] |
|
|
427
|
+
| Internal seams | [route -> service/helper -> provider/db/cache/read-model; include injected/test seam] |
|
|
428
|
+
| External contracts | [provider/API semantics, IDs, lifecycle timing, retries, trial/deferred effects, or N/A] |
|
|
429
|
+
| State/surface axes | [states/viewers/surfaces triggered, or N/A with reason] |
|
|
430
|
+
| Invariants | [fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect] |
|
|
431
|
+
| Unknown semantics | [GAP-NNN links; do not guess] |
|
|
432
|
+
|
|
433
|
+
Rules:
|
|
434
|
+
- Every code reference in this model must be verified against the repo or marked unverified.
|
|
435
|
+
- External/provider semantics that affect behavior must be AS if stated, or GAP if unknown.
|
|
436
|
+
- Optional inputs must include the omitted-input regression behavior or a GAP.
|
|
437
|
+
- This model is the source for Sibling Surface Map, Behavior Matrix, Constraints, provider-contract gaps, and code-seam test targets.]
|
|
438
|
+
|
|
415
439
|
## Sibling Surface Map
|
|
416
|
-
[OPTIONAL — required when P0-
|
|
440
|
+
[OPTIONAL — required when P0-2e or the explore handoff found sibling candidates.
|
|
417
441
|
|
|
418
442
|
Purpose: separate noisy discovery evidence from confirmed planning surfaces. The Candidate Table
|
|
419
443
|
is evidence; the Confirmed Surface Map is what can feed `## Behavior Matrix`.
|
|
@@ -589,9 +613,11 @@ Two kinds of "missing", handled differently:
|
|
|
589
613
|
- **Underspecified** — trigger present, outcome not stated → a **Gap** (`GAP-NNN`, see the Gaps section), not a guessed AS — and not an AS shell either: never write an AS whose Then is only "see GAP-NNN". If a minimal safe outcome IS assertable (e.g. "request refused, state unchanged"), write that as the AS and point to the Gap for the unspecified detail; if nothing concrete is assertable, it is a Gap alone. *Explore-doc case:* if a trigger appears in the description (Happy path / Edge cases / Permissions / Integration) but its outcome lives in the explore's `Open questions` or `Assumptions` rather than being stated, that is still Underspecified — emit `GAP-NNN (status: open)` with `Source:` quoting the explore phrase; do not invent an AS.
|
|
590
614
|
- **Out of scope** — no trigger at all → emit nothing. Don't invent "what about concurrent edits?" when the text never mentions concurrency.
|
|
591
615
|
|
|
592
|
-
**
|
|
616
|
+
**Core Function Model pass (run before AS derivation when triggered).** If `## Core Function Model` exists or P0-2d triggers, derive AS/GAP/Constraints from each confirmed entry point, seam, external contract, invariant, optional/absent input, and unknown semantic. Provider/external features must include a verified seam from public entry to provider call/test seam. If the model names an optional input, include the absent-input regression or GAP. If provider semantics are unknown, write GAP — not AS. If a code reference cannot be verified, mark it unverified or remove it; do not leave fabricated file:line/symbol claims in the spec.
|
|
617
|
+
|
|
618
|
+
**Cross-surface invariant pass (run after the atom list and Core Function Model pass).** For every constraint stated as a system-wide rule (or carrying `scope:`/`surfaces:` in `## Constraints & Invariants`), enumerate EVERY story whose `When` can exercise it. Each such story binds it via `**Applies Constraints:**` and carries an AS asserting the invariant's OUTCOME at that surface. **For a stated cross-surface invariant the minimal-safe outcome (at-most-once: a repeat at this surface causes ≤1 effect) IS assertable** — it is the stated invariant applied to the surface, not a new requirement — so write the outcome AS; do NOT downgrade the whole surface to a bare Gap. If the surface's *mechanism* is unstated (e.g. a provider idempotency-key vs a server-side guard), attach a `GAP-NNN` from that AS for the mechanism detail — outcome asserted, mechanism deferred. A surface becomes a *bare* Gap (no AS) only when no minimal-safe outcome is assertable at all. This removes the AS-vs-Gap coin-flip: a money/effect surface under a stated invariant ALWAYS gets an outcome AS (+ a mechanism Gap if needed), never a bare Gap by default. This does NOT invent the invariant — it is already stated; it forces a stated invariant to be acknowledged at every surface it reaches, closing the "stated once, silently dropped at a second endpoint" hole (an idempotency rule that guarded one endpoint but not a second one — the class of bug this pass exists to kill). Still derive-or-Gap for any genuinely unstated outcome: never a guessed one.
|
|
593
619
|
|
|
594
|
-
**Sibling Surface Map pass (run before the Behavior Matrix pass).** If P0-
|
|
620
|
+
**Sibling Surface Map pass (run before the Behavior Matrix pass).** If P0-2e or the explore handoff found sibling candidates, create `## Sibling Surface Map`. Treat discovery output as evidence, not a contract:
|
|
595
621
|
- High/medium candidates require a disposition: `cover`, `GAP-NNN`, or `ignore(reason)`.
|
|
596
622
|
- `cover` candidates become confirmed sibling surfaces and may feed Behavior Matrix surfaces.
|
|
597
623
|
- `GAP-NNN` candidates do not become BM cells until clarified, but the gap must name what is unknown.
|
|
@@ -600,10 +626,10 @@ Two kinds of "missing", handled differently:
|
|
|
600
626
|
|
|
601
627
|
This pass is the upstream discovery gate for sibling-drift bugs: first find plausible sibling entry-points, then deliberately confirm or park them. It must not manufacture requirements from fuzzy matches.
|
|
602
628
|
|
|
603
|
-
**Behavior Matrix pass (run after the cross-surface invariant pass).** If the feature triggers any state/status/stage, viewer role, permission-dependent affordance, cross-module read/write path, or repeated read surface, create `## Behavior Matrix` before finalizing AS. Derive the axes only from the spec/explore/codebase scan:
|
|
629
|
+
**Behavior Matrix pass (run after the Core Function Model and cross-surface invariant pass).** If the feature triggers any state/status/stage, viewer role, permission-dependent affordance, cross-module read/write path, or repeated read surface, create `## Behavior Matrix` before finalizing AS. Derive the axes only from the spec/explore/codebase scan:
|
|
604
630
|
- States from the state machine or named lifecycle/status values.
|
|
605
631
|
- Viewers from roles, owners/assignees, actor/recipient relationships, and permission rules.
|
|
606
|
-
- Surfaces from confirmed sibling surfaces, Module Dependency Map style source/target pairs, UI pages, API read paths, notifications/email, calendar/provider surfaces, feeds, counts, and dashboards.
|
|
632
|
+
- Surfaces from confirmed sibling surfaces, Core Function Model entry points/seams, Module Dependency Map style source/target pairs, UI pages, API read paths, notifications/email, calendar/provider surfaces, feeds, counts, and dashboards.
|
|
607
633
|
|
|
608
634
|
For each material cell, either:
|
|
609
635
|
- write an AS asserting the exact behavior for that state/viewer/surface, including label, visibility, allowed action, data source/timing, and cascade/parity obligations when applicable;
|
|
@@ -662,6 +688,7 @@ Include only sections that apply:
|
|
|
662
688
|
| CC12 | If the feature triggers state/viewer/surface behavior, `## Behavior Matrix` exists and every material cell has `Coverage` = `AS-NNN`, `GAP-NNN`, or `N/A: <reason>`. No blank coverage cells. Every non-N/A cell maps to an existing AS/GAP; every `N/A` has a concrete reason. State-transition cells list cascade obligations or `none`; read-surface cells list source/timing/lifecycle | Add the matrix, fill the cells, bind each non-N/A cell to AS/GAP, or explain why the matrix is not applicable |
|
|
663
689
|
| CC13 | Every matching `docs/invariants/INV-*.md` entry is handled according to status: `enforced` → referenced `test_ref` or equivalent regression is named in implementation guidance; `confirmed` → sibling/component coverage is represented by AS/GAP/N/A; `candidate` → confirmation GAP/risk note or explicit ignore reason; `retired` → ignored with reason if matched | Add invariant coverage, record a confirmation GAP/risk note, or explain why the invariant does not apply |
|
|
664
690
|
| CC14 | If sibling discovery ran or the explore handoff includes a Sibling Candidate Table, every high/medium candidate has `cover`, `GAP-NNN`, or `ignore(reason)`. Only `cover` candidates feed `## Behavior Matrix`; `GAP`/`ignore` candidates do not create AS/BM requirements | Add the disposition, create the confirmation GAP, or remove the candidate with reason |
|
|
691
|
+
| CC15 | If Core Function Model is required or present, it names operation, inputs, entry points, internal seams, external contracts or N/A, invariants, and unknown semantics. Every confirmed model item is represented by AS/GAP/Constraint/BM. Provider/external semantics that are unknown are GAPs; file:line/symbol/config claims are verified or marked unverified | Add/repair the model, verify references, or create the missing AS/GAP/Constraint/BM coverage |
|
|
665
692
|
|
|
666
693
|
**CC5 enforcement procedure (mandatory, no exceptions):**
|
|
667
694
|
1. Enumerate every `C-xxx` line in `## Constraints & Invariants`.
|
|
@@ -939,6 +966,7 @@ After updating, verify:
|
|
|
939
966
|
| CC12 | If this run ADDS or MODIFIES state/viewer/surface behavior, the touched `## Behavior Matrix` cells exist and each has `Coverage` = `AS-NNN`, `GAP-NNN`, or `N/A: <reason>`. Untouched legacy matrix cells are not re-audited. If no matrix exists and this update introduces the trigger, add the matrix for the touched scope | Add/update the matrix cells and bind non-N/A cells to AS/GAP; do not ship a new state/viewer/surface path as prose only |
|
|
940
967
|
| CC13 | If this run touches a component named by `docs/invariants/INV-*.md`, the matching invariant entry is handled by status (`enforced` test_ref/equivalent named; `confirmed` covered or GAP/N/A; `candidate` confirmation GAP/risk note; `retired` ignored with reason). Untouched unrelated invariants are not re-audited | Add/update invariant coverage or record the confirmation/risk disposition |
|
|
941
968
|
| CC14 | If this Mode C update adds/modifies an existing operation or bug-fix path, sibling discovery has either run for the touched scope or a prior Sibling Surface Map is reused. High/medium candidates are disposed as `cover`, `GAP-NNN`, or `ignore(reason)`; only `cover` candidates feed new BM cells | Run sibling discovery for the touched scope, then update the Sibling Surface Map disposition |
|
|
969
|
+
| CC15 | If this Mode C update changes an operation/input/provider seam/external contract, Core Function Model is updated for the touched scope and confirmed model entries are covered by AS/GAP/Constraint/BM. New or changed file:line/symbol/config claims are verified or marked unverified | Update the model, verify references, and add missing coverage or GAP |
|
|
942
970
|
|
|
943
971
|
> **⛔ Consistency check is NOT optional.**
|
|
944
972
|
> Run CC1-CC6 after EVERY update (Major and Minor).
|
|
@@ -109,7 +109,8 @@ Before writing anything, run this checklist:
|
|
|
109
109
|
| P0-2 | **Related specs** | List `docs/specs/` directories. Read the main spec of any related feature. Is there overlap? |
|
|
110
110
|
| P0-2b | **Explore doc** | Derive feature name from `$ARGUMENTS` as kebab-case (same convention as `docs/specs/<feature>/`). Check `docs/explore/<feature-name>.md`. If no exact match, list `docs/explore/` and fuzzy-match by keywords. If found → read it. Log: "Explore findings found for '<feature>' — using as primary input. Skipping P0-3, P0-4 (already covered)." Continue with P0-5, P0-6. Full field-to-section mapping + Mode A/B/C scope: see **Explore → Spec mapping** subsection right after this table. |
|
|
111
111
|
| P0-2c | **Invariant registry** | Use the invariant registry README/schema as base knowledge; README examples are not runtime entries. Then read matching project-local entries under `docs/invariants/INV-*.md` when their `component_keys`, `sibling_set`, `shared_anchor`, title, or origin bugs match the feature. Carry `confirmed`/`enforced` invariants into `## Constraints & Invariants`; treat `candidate` entries as risk notes or confirmation GAPs, not automatic requirements. |
|
|
112
|
-
| P0-2d | **
|
|
112
|
+
| P0-2d | **Core Function Model** | If the feature changes an operation, optional input, external/provider contract, payment/auth/data mutation, stateful flow, or bug-fix path, build or refresh `## Core Function Model` before stories. Use code evidence, related specs, explore handoff, project-local invariants, and provider semantics already present in repo/docs. Verify every file:line/symbol/config claim against code. Unknown provider semantics become `GAP-NNN`; do not guess. |
|
|
113
|
+
| P0-2e | **Entry-point / sibling discovery** | If the Core Function Model shows multiple entry points, or the feature changes an existing operation/fix path, run the same candidate-only recipe as `/sp-explore` Phase 0.5 unless an explore doc already provides a Sibling Candidate Table. Sources: raw symptom/feature nouns, project-local invariants, shared anchors (`ga_callers` or grep), fuzzy sibling names (`create_from_*`, `*_from_*`, `send_*invite*`, `*_outcome*`, `reschedule*`, `book_next*`, etc.), and recent git co-change. Output feeds `## Sibling Candidate Table`; high/medium candidates must be `cover`, `GAP-NNN`, or `ignore(reason)`. Candidates do not become requirements until confirmed. |
|
|
113
114
|
| P0-3 | **Dependency scan** | `ga_architecture` for the module map and `ga_importers` / `ga_callees` on touched symbols to see what this code reaches. Manual import-grep is a fallback. |
|
|
114
115
|
| P0-4 | **Reusable utilities** | `ga_symbols` (fuzzy match) on names like `validate`, `format`, `parse`, `<domain>Helper` to find existing helpers; `ga_hubs` to surface the most-connected utilities worth reusing. |
|
|
115
116
|
| P0-5 | **Project patterns** | Identify test framework, naming conventions, directory structure from existing code. |
|
|
@@ -412,8 +413,31 @@ point to a `GAP-NNN`. See Phase 1 §"Linked fields — pin cross-spec contracts
|
|
|
412
413
|
- `<field>` — consumed by `<sibling>:AS-NNN` on <surface> (<persisted+served | transient-in-response>).
|
|
413
414
|
Produced by `<sibling>:AS-NNN` on <surface>. ✔ match. | ✘ <surface|lifecycle> mismatch → GAP-NNN.]
|
|
414
415
|
|
|
416
|
+
## Core Function Model
|
|
417
|
+
[OPTIONAL — required when P0-2d ran or the explore handoff includes a Core Function Model.
|
|
418
|
+
|
|
419
|
+
Purpose: model the operation before AS/BM/GAP so code seams, optional inputs, and provider contracts
|
|
420
|
+
are not lost while writing acceptance scenarios.
|
|
421
|
+
|
|
422
|
+
| Field | Evidence |
|
|
423
|
+
|---|---|
|
|
424
|
+
| Operation | [core operation being changed] |
|
|
425
|
+
| Inputs | [required / optional / absent inputs; no-op behavior] |
|
|
426
|
+
| Entry points | [UI/API/job/webhook/provider callback surfaces] |
|
|
427
|
+
| Internal seams | [route -> service/helper -> provider/db/cache/read-model; include injected/test seam] |
|
|
428
|
+
| External contracts | [provider/API semantics, IDs, lifecycle timing, retries, trial/deferred effects, or N/A] |
|
|
429
|
+
| State/surface axes | [states/viewers/surfaces triggered, or N/A with reason] |
|
|
430
|
+
| Invariants | [fail-closed / server revalidation / no-op unchanged / parity/cascade / no partial side effect] |
|
|
431
|
+
| Unknown semantics | [GAP-NNN links; do not guess] |
|
|
432
|
+
|
|
433
|
+
Rules:
|
|
434
|
+
- Every code reference in this model must be verified against the repo or marked unverified.
|
|
435
|
+
- External/provider semantics that affect behavior must be AS if stated, or GAP if unknown.
|
|
436
|
+
- Optional inputs must include the omitted-input regression behavior or a GAP.
|
|
437
|
+
- This model is the source for Sibling Surface Map, Behavior Matrix, Constraints, provider-contract gaps, and code-seam test targets.]
|
|
438
|
+
|
|
415
439
|
## Sibling Surface Map
|
|
416
|
-
[OPTIONAL — required when P0-
|
|
440
|
+
[OPTIONAL — required when P0-2e or the explore handoff found sibling candidates.
|
|
417
441
|
|
|
418
442
|
Purpose: separate noisy discovery evidence from confirmed planning surfaces. The Candidate Table
|
|
419
443
|
is evidence; the Confirmed Surface Map is what can feed `## Behavior Matrix`.
|
|
@@ -589,9 +613,11 @@ Two kinds of "missing", handled differently:
|
|
|
589
613
|
- **Underspecified** — trigger present, outcome not stated → a **Gap** (`GAP-NNN`, see the Gaps section), not a guessed AS — and not an AS shell either: never write an AS whose Then is only "see GAP-NNN". If a minimal safe outcome IS assertable (e.g. "request refused, state unchanged"), write that as the AS and point to the Gap for the unspecified detail; if nothing concrete is assertable, it is a Gap alone. *Explore-doc case:* if a trigger appears in the description (Happy path / Edge cases / Permissions / Integration) but its outcome lives in the explore's `Open questions` or `Assumptions` rather than being stated, that is still Underspecified — emit `GAP-NNN (status: open)` with `Source:` quoting the explore phrase; do not invent an AS.
|
|
590
614
|
- **Out of scope** — no trigger at all → emit nothing. Don't invent "what about concurrent edits?" when the text never mentions concurrency.
|
|
591
615
|
|
|
592
|
-
**
|
|
616
|
+
**Core Function Model pass (run before AS derivation when triggered).** If `## Core Function Model` exists or P0-2d triggers, derive AS/GAP/Constraints from each confirmed entry point, seam, external contract, invariant, optional/absent input, and unknown semantic. Provider/external features must include a verified seam from public entry to provider call/test seam. If the model names an optional input, include the absent-input regression or GAP. If provider semantics are unknown, write GAP — not AS. If a code reference cannot be verified, mark it unverified or remove it; do not leave fabricated file:line/symbol claims in the spec.
|
|
617
|
+
|
|
618
|
+
**Cross-surface invariant pass (run after the atom list and Core Function Model pass).** For every constraint stated as a system-wide rule (or carrying `scope:`/`surfaces:` in `## Constraints & Invariants`), enumerate EVERY story whose `When` can exercise it. Each such story binds it via `**Applies Constraints:**` and carries an AS asserting the invariant's OUTCOME at that surface. **For a stated cross-surface invariant the minimal-safe outcome (at-most-once: a repeat at this surface causes ≤1 effect) IS assertable** — it is the stated invariant applied to the surface, not a new requirement — so write the outcome AS; do NOT downgrade the whole surface to a bare Gap. If the surface's *mechanism* is unstated (e.g. a provider idempotency-key vs a server-side guard), attach a `GAP-NNN` from that AS for the mechanism detail — outcome asserted, mechanism deferred. A surface becomes a *bare* Gap (no AS) only when no minimal-safe outcome is assertable at all. This removes the AS-vs-Gap coin-flip: a money/effect surface under a stated invariant ALWAYS gets an outcome AS (+ a mechanism Gap if needed), never a bare Gap by default. This does NOT invent the invariant — it is already stated; it forces a stated invariant to be acknowledged at every surface it reaches, closing the "stated once, silently dropped at a second endpoint" hole (an idempotency rule that guarded one endpoint but not a second one — the class of bug this pass exists to kill). Still derive-or-Gap for any genuinely unstated outcome: never a guessed one.
|
|
593
619
|
|
|
594
|
-
**Sibling Surface Map pass (run before the Behavior Matrix pass).** If P0-
|
|
620
|
+
**Sibling Surface Map pass (run before the Behavior Matrix pass).** If P0-2e or the explore handoff found sibling candidates, create `## Sibling Surface Map`. Treat discovery output as evidence, not a contract:
|
|
595
621
|
- High/medium candidates require a disposition: `cover`, `GAP-NNN`, or `ignore(reason)`.
|
|
596
622
|
- `cover` candidates become confirmed sibling surfaces and may feed Behavior Matrix surfaces.
|
|
597
623
|
- `GAP-NNN` candidates do not become BM cells until clarified, but the gap must name what is unknown.
|
|
@@ -600,10 +626,10 @@ Two kinds of "missing", handled differently:
|
|
|
600
626
|
|
|
601
627
|
This pass is the upstream discovery gate for sibling-drift bugs: first find plausible sibling entry-points, then deliberately confirm or park them. It must not manufacture requirements from fuzzy matches.
|
|
602
628
|
|
|
603
|
-
**Behavior Matrix pass (run after the cross-surface invariant pass).** If the feature triggers any state/status/stage, viewer role, permission-dependent affordance, cross-module read/write path, or repeated read surface, create `## Behavior Matrix` before finalizing AS. Derive the axes only from the spec/explore/codebase scan:
|
|
629
|
+
**Behavior Matrix pass (run after the Core Function Model and cross-surface invariant pass).** If the feature triggers any state/status/stage, viewer role, permission-dependent affordance, cross-module read/write path, or repeated read surface, create `## Behavior Matrix` before finalizing AS. Derive the axes only from the spec/explore/codebase scan:
|
|
604
630
|
- States from the state machine or named lifecycle/status values.
|
|
605
631
|
- Viewers from roles, owners/assignees, actor/recipient relationships, and permission rules.
|
|
606
|
-
- Surfaces from confirmed sibling surfaces, Module Dependency Map style source/target pairs, UI pages, API read paths, notifications/email, calendar/provider surfaces, feeds, counts, and dashboards.
|
|
632
|
+
- Surfaces from confirmed sibling surfaces, Core Function Model entry points/seams, Module Dependency Map style source/target pairs, UI pages, API read paths, notifications/email, calendar/provider surfaces, feeds, counts, and dashboards.
|
|
607
633
|
|
|
608
634
|
For each material cell, either:
|
|
609
635
|
- write an AS asserting the exact behavior for that state/viewer/surface, including label, visibility, allowed action, data source/timing, and cascade/parity obligations when applicable;
|
|
@@ -662,6 +688,7 @@ Include only sections that apply:
|
|
|
662
688
|
| CC12 | If the feature triggers state/viewer/surface behavior, `## Behavior Matrix` exists and every material cell has `Coverage` = `AS-NNN`, `GAP-NNN`, or `N/A: <reason>`. No blank coverage cells. Every non-N/A cell maps to an existing AS/GAP; every `N/A` has a concrete reason. State-transition cells list cascade obligations or `none`; read-surface cells list source/timing/lifecycle | Add the matrix, fill the cells, bind each non-N/A cell to AS/GAP, or explain why the matrix is not applicable |
|
|
663
689
|
| CC13 | Every matching `docs/invariants/INV-*.md` entry is handled according to status: `enforced` → referenced `test_ref` or equivalent regression is named in implementation guidance; `confirmed` → sibling/component coverage is represented by AS/GAP/N/A; `candidate` → confirmation GAP/risk note or explicit ignore reason; `retired` → ignored with reason if matched | Add invariant coverage, record a confirmation GAP/risk note, or explain why the invariant does not apply |
|
|
664
690
|
| CC14 | If sibling discovery ran or the explore handoff includes a Sibling Candidate Table, every high/medium candidate has `cover`, `GAP-NNN`, or `ignore(reason)`. Only `cover` candidates feed `## Behavior Matrix`; `GAP`/`ignore` candidates do not create AS/BM requirements | Add the disposition, create the confirmation GAP, or remove the candidate with reason |
|
|
691
|
+
| CC15 | If Core Function Model is required or present, it names operation, inputs, entry points, internal seams, external contracts or N/A, invariants, and unknown semantics. Every confirmed model item is represented by AS/GAP/Constraint/BM. Provider/external semantics that are unknown are GAPs; file:line/symbol/config claims are verified or marked unverified | Add/repair the model, verify references, or create the missing AS/GAP/Constraint/BM coverage |
|
|
665
692
|
|
|
666
693
|
**CC5 enforcement procedure (mandatory, no exceptions):**
|
|
667
694
|
1. Enumerate every `C-xxx` line in `## Constraints & Invariants`.
|
|
@@ -939,6 +966,7 @@ After updating, verify:
|
|
|
939
966
|
| CC12 | If this run ADDS or MODIFIES state/viewer/surface behavior, the touched `## Behavior Matrix` cells exist and each has `Coverage` = `AS-NNN`, `GAP-NNN`, or `N/A: <reason>`. Untouched legacy matrix cells are not re-audited. If no matrix exists and this update introduces the trigger, add the matrix for the touched scope | Add/update the matrix cells and bind non-N/A cells to AS/GAP; do not ship a new state/viewer/surface path as prose only |
|
|
940
967
|
| CC13 | If this run touches a component named by `docs/invariants/INV-*.md`, the matching invariant entry is handled by status (`enforced` test_ref/equivalent named; `confirmed` covered or GAP/N/A; `candidate` confirmation GAP/risk note; `retired` ignored with reason). Untouched unrelated invariants are not re-audited | Add/update invariant coverage or record the confirmation/risk disposition |
|
|
941
968
|
| CC14 | If this Mode C update adds/modifies an existing operation or bug-fix path, sibling discovery has either run for the touched scope or a prior Sibling Surface Map is reused. High/medium candidates are disposed as `cover`, `GAP-NNN`, or `ignore(reason)`; only `cover` candidates feed new BM cells | Run sibling discovery for the touched scope, then update the Sibling Surface Map disposition |
|
|
969
|
+
| CC15 | If this Mode C update changes an operation/input/provider seam/external contract, Core Function Model is updated for the touched scope and confirmed model entries are covered by AS/GAP/Constraint/BM. New or changed file:line/symbol/config claims are verified or marked unverified | Update the model, verify references, and add missing coverage or GAP |
|
|
942
970
|
|
|
943
971
|
> **⛔ Consistency check is NOT optional.**
|
|
944
972
|
> Run CC1-CC6 after EVERY update (Major and Minor).
|
|
@@ -101,8 +101,12 @@ Spend 60% of analysis on the primary focus. Cover all categories, but proportion
|
|
|
101
101
|
|
|
102
102
|
### Behavior Matrix & Invariants (High)
|
|
103
103
|
|
|
104
|
-
Use this section when the spec has `## Behavior Matrix`, `## Sibling Surface Map`, or project-local invariant logs match the diff.
|
|
104
|
+
Use this section when the spec has `## Core Function Model`, `## Behavior Matrix`, `## Sibling Surface Map`, or project-local invariant logs match the diff.
|
|
105
105
|
|
|
106
|
+
- **Core model trace:** For each changed operation, input, entry point, seam, provider contract, or external side effect, identify the corresponding `## Core Function Model` row. If the diff changes provider/payment/auth/data semantics and no AS/GAP/Constraint/BM/test covers it, flag High.
|
|
107
|
+
- **Optional-input regression:** If the diff adds or changes an optional input, omitted-input/no-op behavior must be covered by AS/GAP or a test. Flag missing absent-input regression coverage.
|
|
108
|
+
- **Provider contract drift:** For external providers, verify typed IDs, lifecycle timing, retries/trials/webhooks, fail-closed behavior, and deferred-effect semantics are covered by AS/GAP/Constraint. Unknown provider semantics should be GAPs, not guessed AS.
|
|
109
|
+
- **Reference accuracy:** If the spec cites file:line/symbol/config and the diff/code contradicts it, flag High/Medium depending on release risk. Stale or fabricated references are review findings, not harmless prose.
|
|
106
110
|
- **Cell-to-diff trace:** For each changed state transition, viewer rule, read surface, notification, queue, dashboard count, feed, calendar, or API projection, identify the corresponding `BM.AS-NNN.<surface>` row. If code changes behavior for a matrix cell but tests do not reference that AS ID or `BM.AS-NNN`, flag High.
|
|
107
111
|
- **Surface parity:** If the diff updates one read surface for a state/viewer change, check matrix siblings for list/detail/worklist/dashboard/feed/API/email/calendar parity. Flag missing sibling updates unless the matrix marks them `N/A` with a concrete reason.
|
|
108
112
|
- **Sibling candidate disposition:** If the spec has `## Sibling Surface Map`, every high/medium candidate must be `cover`, `GAP-NNN`, or `ignore(reason)`. Flag missing dispositions. If the diff changes a confirmed sibling surface but omits sibling tests/updates for the other confirmed surfaces, flag High unless a GAP/N/A covers it.
|
|
@@ -101,8 +101,12 @@ Spend 60% of analysis on the primary focus. Cover all categories, but proportion
|
|
|
101
101
|
|
|
102
102
|
### Behavior Matrix & Invariants (High)
|
|
103
103
|
|
|
104
|
-
Use this section when the spec has `## Behavior Matrix`, `## Sibling Surface Map`, or project-local invariant logs match the diff.
|
|
104
|
+
Use this section when the spec has `## Core Function Model`, `## Behavior Matrix`, `## Sibling Surface Map`, or project-local invariant logs match the diff.
|
|
105
105
|
|
|
106
|
+
- **Core model trace:** For each changed operation, input, entry point, seam, provider contract, or external side effect, identify the corresponding `## Core Function Model` row. If the diff changes provider/payment/auth/data semantics and no AS/GAP/Constraint/BM/test covers it, flag High.
|
|
107
|
+
- **Optional-input regression:** If the diff adds or changes an optional input, omitted-input/no-op behavior must be covered by AS/GAP or a test. Flag missing absent-input regression coverage.
|
|
108
|
+
- **Provider contract drift:** For external providers, verify typed IDs, lifecycle timing, retries/trials/webhooks, fail-closed behavior, and deferred-effect semantics are covered by AS/GAP/Constraint. Unknown provider semantics should be GAPs, not guessed AS.
|
|
109
|
+
- **Reference accuracy:** If the spec cites file:line/symbol/config and the diff/code contradicts it, flag High/Medium depending on release risk. Stale or fabricated references are review findings, not harmless prose.
|
|
106
110
|
- **Cell-to-diff trace:** For each changed state transition, viewer rule, read surface, notification, queue, dashboard count, feed, calendar, or API projection, identify the corresponding `BM.AS-NNN.<surface>` row. If code changes behavior for a matrix cell but tests do not reference that AS ID or `BM.AS-NNN`, flag High.
|
|
107
111
|
- **Surface parity:** If the diff updates one read surface for a state/viewer change, check matrix siblings for list/detail/worklist/dashboard/feed/API/email/calendar parity. Flag missing sibling updates unless the matrix marks them `N/A` with a concrete reason.
|
|
108
112
|
- **Sibling candidate disposition:** If the spec has `## Sibling Surface Map`, every high/medium candidate must be `cover`, `GAP-NNN`, or `ignore(reason)`. Flag missing dispositions. If the diff changes a confirmed sibling surface but omits sibling tests/updates for the other confirmed surfaces, flag High unless a GAP/N/A covers it.
|