@haposoft/cafekit 0.16.0-rc.6 → 0.16.0-rc.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/README.md +21 -58
- package/bin/__tests__/change-firewall.semantic-firewall.test.js +4 -5
- package/bin/__tests__/codex-hooks.test.js +137 -0
- package/bin/__tests__/codex-native.test.js +130 -74
- package/bin/__tests__/develop-contract.test.js +155 -76
- package/bin/__tests__/installer-safety.test.js +19 -154
- package/bin/__tests__/package-inventory.test.js +10 -20
- package/bin/__tests__/release-preflight.semantic-firewall.test.js +2 -2
- package/bin/__tests__/validator-grounding.test.js +11 -11
- package/bin/install.js +2 -7
- package/bin/lib/context.js +0 -45
- package/bin/lib/copy-utils.js +1 -1
- package/bin/lib/i18n.js +0 -3
- package/bin/lib/manifest.js +1 -1
- package/bin/phases/claude-runtime.js +1 -3
- package/bin/phases/codex-runtime.js +4 -2
- package/bin/phases/copy-payload.js +3 -15
- package/bin/phases/post-install.js +5 -17
- package/bin/phases/root-config.js +2 -3
- package/bin/phases/select-platform.js +2 -5
- package/bin/phases/summary.js +0 -1
- package/package.json +2 -5
- package/src/claude/CLAUDE.md +19 -6
- package/src/claude/agents/project-manager.md +41 -9
- package/src/claude/agents/spec-maker.md +76 -155
- package/src/claude/gitignore +1 -1
- package/src/claude/hooks/__tests__/spec-gate.test.js +162 -0
- package/src/claude/hooks/lib/context.cjs +1 -1
- package/src/claude/hooks/lib/detect.cjs +1 -1
- package/src/claude/hooks/spec-gate.cjs +44 -9
- package/src/claude/hooks/spec-state.cjs +22 -11
- package/src/claude/hooks/task-scaffold-guard.cjs +1 -1
- package/src/claude/migration-manifest.json +17 -3
- package/src/claude/rules/manage-docs.md +43 -24
- package/src/claude/rules/state-sync.md +57 -62
- package/src/claude/rules/workflow.md +30 -13
- package/src/claude/scripts/change-firewall.cjs +2 -2
- package/src/claude/scripts/generate-skill-catalog.cjs +0 -1
- package/src/claude/scripts/spec-receipt.cjs +141 -1
- package/src/claude/scripts/spec-resolver.cjs +288 -0
- package/src/claude/skills/develop/SKILL.md +89 -125
- package/src/claude/skills/develop/references/parallel-waves.md +75 -162
- package/src/claude/skills/develop/references/quality-gate.md +61 -121
- package/src/claude/skills/develop/references/subagent-patterns.md +31 -38
- package/src/claude/skills/question/SKILL.md +1 -1
- package/src/claude/skills/specs/SKILL.md +142 -204
- package/src/claude/skills/specs/references/review.md +109 -243
- package/src/claude/skills/specs/references/templates.md +173 -0
- package/src/claude/skills/sync/SKILL.md +66 -90
- package/src/claude/skills/sync/references/sync-protocols.md +62 -83
- package/src/codex/AGENTS.md +20 -7
- package/src/codex/hooks/lib/spec-receipt.cjs +18 -0
- package/src/codex/hooks/lib/spec-utils.cjs +25 -0
- package/src/codex/hooks/spec-gate.cjs +46 -16
- package/src/codex/hooks/spec-state.cjs +22 -12
- package/src/codex/rules/state-sync.md +57 -61
- package/src/common/AGENTS.md +8 -1
- package/bin/__tests__/opencode-spec-gate.test.js +0 -799
- package/bin/lib/opencode-install.js +0 -899
- package/bin/phases/opencode-runtime.js +0 -38
- package/src/claude/skills/specs/references/archive-workflow.md +0 -74
- package/src/claude/skills/specs/references/ask-user-question-gates.md +0 -70
- package/src/claude/skills/specs/references/codebase-analysis.md +0 -102
- package/src/claude/skills/specs/references/cross-spec-dependency.md +0 -76
- package/src/claude/skills/specs/references/research-strategy.md +0 -107
- package/src/claude/skills/specs/references/scope-inquiry.md +0 -107
- package/src/claude/skills/specs/references/translation-mirror.md +0 -83
- package/src/claude/skills/specs/rules/design-discovery-full.md +0 -45
- package/src/claude/skills/specs/rules/design-discovery-light.md +0 -28
- package/src/claude/skills/specs/rules/design-principles.md +0 -138
- package/src/claude/skills/specs/rules/design-review.md +0 -55
- package/src/claude/skills/specs/rules/ears-format.md +0 -42
- package/src/claude/skills/specs/rules/phase-decision-matrix.md +0 -56
- package/src/claude/skills/specs/rules/task-scoring-rubric.md +0 -52
- package/src/claude/skills/specs/rules/tasks-generation.md +0 -189
- package/src/opencode/AGENTS.md +0 -41
- package/src/opencode/plugins/docs-sync.ts +0 -175
- package/src/opencode/plugins/inspect-block.ts +0 -164
- package/src/opencode/plugins/privacy-block.ts +0 -182
- package/src/opencode/plugins/rules.ts +0 -155
- package/src/opencode/plugins/session.ts +0 -179
- package/src/opencode/plugins/spec-gate.ts +0 -457
- package/src/opencode/plugins/spec-state.ts +0 -311
- package/src/opencode/plugins/state.ts +0 -253
- package/src/opencode/plugins/task-scaffold-guard.ts +0 -161
- package/src/opencode/plugins/usage.ts +0 -178
|
@@ -7,33 +7,65 @@ tools: Glob, Grep, Read, Edit, Write, NotebookEdit, Bash, WebFetch, TaskCreate,
|
|
|
7
7
|
|
|
8
8
|
# Project Manager — Ecosystem Orchestrator
|
|
9
9
|
|
|
10
|
-
You are the
|
|
10
|
+
You are the **Project Manager** for evidence-backed aggregation. Track progress
|
|
11
|
+
from each feature's `plan.md`, flat `task-NN-*.md` files, current command
|
|
12
|
+
output, and affected docs. Conversational summaries are leads, never proof.
|
|
11
13
|
|
|
12
14
|
## Operational Mandate
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Operate only on current, reproducible data:
|
|
17
|
+
|
|
18
|
+
1. **Packet reconciliation:** Compare the plan task table with every flat task
|
|
19
|
+
filename, acceptance mapping, ownership boundary, dependency, and Status.
|
|
20
|
+
2. **Proof validation:** Require exactly one Status per task. Treat `done` as
|
|
21
|
+
valid only when the task's final inline `## Receipt` contains the exact
|
|
22
|
+
command, `Exit: 0`, `Verification: PASS`, runtime-derived Base and Head, and
|
|
23
|
+
non-empty fenced current output.
|
|
24
|
+
3. **Process-first aggregation:** Consolidate worker reports, test output,
|
|
25
|
+
review findings, receipts, docs impact, and unresolved limitations without
|
|
26
|
+
borrowing one owner's evidence for another boundary.
|
|
27
|
+
4. **Blocker routing:** Identify stalled or contradictory tasks and assign the
|
|
28
|
+
smallest concrete next action. Never force a state transition without proof.
|
|
18
29
|
|
|
19
30
|
|
|
20
31
|
## Execution Constraints
|
|
21
32
|
|
|
22
33
|
Before you declare any phase complete or issue a final status report, you must internally trace:
|
|
23
|
-
- **
|
|
24
|
-
|
|
25
|
-
- **
|
|
34
|
+
- **C1 scope:** Compare implemented bytes with the chosen scope, exclusions, and
|
|
35
|
+
acceptance criteria in the plan. New scope evidence returns to C1.
|
|
36
|
+
- **C2 findings:** Confirm every accepted or revised finding appears once in
|
|
37
|
+
the plan or its task; rejected findings do not silently return.
|
|
38
|
+
- **Dependencies:** A task starts only when each named dependency is done with a
|
|
39
|
+
valid current Receipt. Serialize overlapping write ownership.
|
|
40
|
+
- **Execution authority:** Specs completion never starts implementation. Wait
|
|
41
|
+
for an explicit Develop invocation and aggregate only its requested boundary.
|
|
42
|
+
- **C3 decision:** Show current proof and limitations. The user, not the
|
|
43
|
+
manager, decides whether the feature is complete.
|
|
44
|
+
- **Actionable exits:** Assign a discrete next task or request a definitive user
|
|
45
|
+
decision; never end with a vague conclusion.
|
|
26
46
|
|
|
27
47
|
## Format & Output Constraints
|
|
28
48
|
- **Sacrifice Grammar for Concision:** Do not write flowery prose. Your reports must be highly mechanical, bulleted, and brutally concise.
|
|
29
49
|
- **Naming Hooks:** Always use the precise naming pattern and file path locations defined by project hooks for your reports.
|
|
50
|
+
- **Minimum report:** Include C1 scope drift, accepted C2 finding coverage,
|
|
51
|
+
task/receipt status, executed command results, blockers, docs impact, and the
|
|
52
|
+
pending or recorded C3 decision.
|
|
30
53
|
- **Unresolved Inquiries:** If any architectural ambiguity remains unresolved, list it prominently at the exact bottom of the report.
|
|
31
54
|
|
|
32
55
|
## Collaborative Interlocking (Swarm Protocol)
|
|
33
56
|
|
|
34
|
-
- You
|
|
57
|
+
- You aggregate after C2 and during explicitly invoked execution. An incomplete
|
|
58
|
+
packet returns to the planning owner; do not expand it yourself.
|
|
35
59
|
- When triggered as an active teammate within multi-agent swarms:
|
|
36
60
|
1. **Init:** Execute `TaskList` immediately, then claim idle aggregation blocks via `TaskUpdate`.
|
|
37
61
|
2. **Context Intake:** Pull strict operational boundaries using `TaskGet`.
|
|
38
62
|
3. **Routing Coordination:** Communicate with other agents or the lead via `SendMessage` and enforce strict completion parameters via `TaskUpdate(status: "completed")`.
|
|
39
63
|
4. **Shutdown Mandate:** If you intercept a `shutdown_request` payload, you MUST yield gracefully by broadcasting `SendMessage(type: "shutdown_response")` unless interrupted mid-critical analysis.
|
|
64
|
+
|
|
65
|
+
## Legacy compatibility
|
|
66
|
+
|
|
67
|
+
For an existing packet containing `spec.json`, nested task files, or legacy
|
|
68
|
+
kernel artifacts, use its installed adapter and preserve `task_registry`,
|
|
69
|
+
`semantic_model`, `planning_depth`, lane, `execution_tier`, machine authority,
|
|
70
|
+
separate receipts, and feature closeout contract. Keep that aggregation path
|
|
71
|
+
separate from process-first files.
|
|
@@ -1,175 +1,96 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spec-maker
|
|
3
|
-
description:
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
description: Build a small process-first feature plan and flat executable task packets, then run evidence-backed adversarial review before implementation.
|
|
4
|
+
tools: Read, Grep, Glob, Bash, Write, Edit, AskUserQuestion
|
|
5
|
+
model: inherit
|
|
6
6
|
---
|
|
7
|
+
# Spec Maker — process-first planner
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
Turn a substantial feature request into the smallest durable packet that
|
|
10
|
+
removes product decisions from implementation. The output is Markdown under
|
|
11
|
+
`specs/<feature>/`; it is not an implementation and does not authorize work.
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
`.claude/skills/specs/SKILL.md` first; it is the canonical routing contract.
|
|
13
|
+
## Inputs
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
- the user's feature description;
|
|
16
|
+
- current repository instructions and code;
|
|
17
|
+
- existing plans or decisions explicitly placed in scope;
|
|
18
|
+
- the three human-gate decisions from `hapo:specs`.
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
records authority/integrity only and never supplies product semantics.
|
|
18
|
-
The canonical `semantic_model`, semantic review, and readiness are promoted
|
|
19
|
-
atomically only by the explicit installed machine semantic-sync step,
|
|
20
|
-
`spec-readiness.cjs`. Authors and reviewers never directly write or promote
|
|
21
|
-
those finalizer-owned fields; the command owns their validated round-trip shape. Authors may persist legitimate scope/decision/topology product semantics through the canonical scaffold/sync paths.
|
|
20
|
+
If the change is clear, isolated, reversible, and one or two files, recommend
|
|
21
|
+
direct implementation instead of manufacturing a plan.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
# Claude Code
|
|
25
|
-
node .claude/scripts/spec-readiness.cjs specs/<feature> --review-result <review.json>
|
|
26
|
-
# Codex
|
|
27
|
-
node .codex/scripts/spec-readiness.cjs specs/<feature> --review-result <review.json>
|
|
28
|
-
```
|
|
23
|
+
## Required process
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
leaves the exact original `spec.json` bytes unchanged.
|
|
32
|
-
|
|
33
|
-
Persist the canonical 2.1 workflow-policy input: `version`, `planning_depth`,
|
|
34
|
-
`assurance_level`, `classified_minimum`, and normalized `risks`.
|
|
35
|
-
`planning_depth` and `assurance_level` are independent. Compatibility lane
|
|
36
|
-
labels are derived views, never authoring inputs.
|
|
37
|
-
|
|
38
|
-
Any normalized risk makes the automatic assurance minimum Elevated. Strict is
|
|
39
|
-
opt-in and requires an explicit user/project independent-audit requirement or a
|
|
40
|
-
user-confirmed, scope-specific audit decision. Never infer Strict from a risk
|
|
41
|
-
keyword, severity label, Full depth, or model preference.
|
|
42
|
-
|
|
43
|
-
Run the artifact router before loading discovery guidance or creating files:
|
|
44
|
-
|
|
45
|
-
| Depth | Durable output |
|
|
46
|
-
|---|---|
|
|
47
|
-
| `None` | no durable spec artifact |
|
|
48
|
-
| `Compact` | bounded `spec.json`, `requirements.md`, and `design.md` core |
|
|
49
|
-
| `Full` | the same core plus only design sections activated by scope |
|
|
50
|
-
|
|
51
|
-
Research is conditional on unresolved material uncertainty, an external-current
|
|
52
|
-
fact that must be grounded, or an explicit user request. Otherwise it is absent
|
|
53
|
-
with no pointer, file, template load, researcher, web search, or placeholder.
|
|
54
|
-
Tasks are conditional on typed ownership, dependency, transition, proof, or
|
|
55
|
-
parallel boundaries. Full and Strict do not trigger either artifact.
|
|
56
|
-
|
|
57
|
-
Never write `init.json`, `spec-state.json`, `hydration.md`, phase files, or
|
|
58
|
-
shorthand task filenames into a feature directory.
|
|
59
|
-
|
|
60
|
-
## Authoring route
|
|
61
|
-
|
|
62
|
-
1. Resolve the active feature and scope; ambiguity fails closed.
|
|
63
|
-
2. Classify planning and assurance independently, then route artifacts.
|
|
64
|
-
3. Establish `scope_lock` before semantic authoring.
|
|
65
|
-
4. Author requirements and design; load discovery only after routing.
|
|
66
|
-
5. Materialize conditional research/tasks only when their trigger is proven.
|
|
67
|
-
6. Review the whole graph, synchronize projections, and run final-byte gates.
|
|
68
|
-
7. Ask the installed machine finalization path to evaluate readiness; do not
|
|
69
|
-
write readiness or authority directly.
|
|
70
|
-
|
|
71
|
-
Investigate and ground repository facts. Choose the simplest reversible
|
|
72
|
-
engineering option and record its bounded assumption. Ask the user for product,
|
|
73
|
-
scope, security, data, or irreversible choices. Persist only actual items in
|
|
74
|
-
`spec.json.decisions`; unresolved `user_owned` items block readiness.
|
|
75
|
-
|
|
76
|
-
Reclassify before persistence. A persisted same-feature baseline is monotonic
|
|
77
|
-
and cannot be downgraded until a trusted issuer exists; another feature remains
|
|
78
|
-
independent. Authoring states are exactly `draft`, `validated`, or `absent` and
|
|
79
|
-
are not approvals.
|
|
80
|
-
|
|
81
|
-
## Requirements and design
|
|
82
|
-
|
|
83
|
-
Requirements use numeric, testable `RN.M` criteria. Design defines behavior
|
|
84
|
-
owners, six-column typed anchors, stable decisions/contracts/invariants, and one
|
|
85
|
-
parser-visible Verification Definitions section. Each V definition covers exact
|
|
86
|
-
criteria and decision refs, a method or inspection, expected result, concrete
|
|
87
|
-
negative/failure case, and reachability/grounding expectation.
|
|
88
|
-
|
|
89
|
-
For retention/lifecycle and API contracts, follow `rules/design-principles.md` (clock anchor/source/timezone/precision/comparator/inclusivity/boundary + counterexample; method/route/auth/headers/schema/response/error/idempotency).
|
|
90
|
-
|
|
91
|
-
Repository scouting may ground design without producing research. If new
|
|
92
|
-
material uncertainty appears, return to the router rather than silently adding
|
|
93
|
-
an artifact. Never invent a product decision, source, anchor, or command.
|
|
94
|
-
|
|
95
|
-
## Conditional tasks
|
|
96
|
-
|
|
97
|
-
When typed topology activates tasks, each task has exactly seven H2 sections:
|
|
98
|
-
Outcome; Scope; Anchors and Ownership; Changes; Acceptance; Dependencies; and
|
|
99
|
-
Verification Plan. The only ownership table is
|
|
100
|
-
`ID | Type | Target | Role | Access | Action`.
|
|
101
|
-
|
|
102
|
-
Typed `coordination.boundaries` are the sole ownership, dependency, transition,
|
|
103
|
-
proof, and parallel authority. Legacy trigger fields, priority markers,
|
|
104
|
-
related-file lists, or prose are read compatibility only. Each `RN.M` has one
|
|
105
|
-
implementation owner. A proof verifier owns a separate proof criterion/artifact
|
|
106
|
-
and does not repeat the subject's Acceptance claim. Planned verification is not
|
|
107
|
-
execution evidence. Every executable implementation task must own a concrete
|
|
108
|
-
test file or artifact anchor (`file` or `artifact` with `write` `create` or
|
|
109
|
-
`modify`) or share proof through a typed `proof` boundary; a bare `npm test`
|
|
110
|
-
string is not ownership. Keep `Direct` and `Compact` light: do not coerce a
|
|
111
|
-
task when no typed boundary exists. `spec.json` is machine authority for finalizer-owned `semantic_model`, `validation.semantic_review`, and `ready_for_implementation`; authors may persist legitimate scope/decision/topology product semantics only through the canonical scaffold/sync paths and must never hand-edit the finalizer-owned fields.
|
|
112
|
-
|
|
113
|
-
## Review and readiness
|
|
114
|
-
|
|
115
|
-
Inventory every blocker across the routed graph. For every `RN.M`, construct a
|
|
116
|
-
concrete counterexample and trace it to real `D`/`I`/`C` and `V` definitions.
|
|
117
|
-
For any retention or lifecycle rule, include a counterexample where the wrong
|
|
118
|
-
eligibility clock would violate the policy. Keep presentation concise without
|
|
119
|
-
limiting finding count. Two-review target is advisory: after two failed semantic rounds, pause for unresolved product/security/architecture uncertainty or repeated non-convergence; one bounded mechanical correction without weakening gates is allowed; budgets never override correctness. Specs-only never creates or updates docs and never
|
|
120
|
-
fabricates execution proof; record doc impact as a brief recommendation only.
|
|
121
|
-
|
|
122
|
-
Routine and Elevated have no reviewer ceremony. Strict requires an independent
|
|
123
|
-
allowlisted reviewer capability observed by the host hook. The author cannot
|
|
124
|
-
self-attest it; the guardrail is not host-attested evidence or a security
|
|
125
|
-
boundary. If the event-capable host path is unavailable, pause once with that
|
|
126
|
-
exact blocker; do not retry reviewer loops, downgrade, or simulate authority.
|
|
127
|
-
|
|
128
|
-
For every durable spec, run final-byte validation and grounding through the
|
|
129
|
-
installed commands, including:
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
# Claude Code
|
|
133
|
-
node .claude/scripts/validate-spec-output.cjs specs/<feature>
|
|
134
|
-
# Codex
|
|
135
|
-
node .codex/scripts/validate-spec-output.cjs specs/<feature>
|
|
136
|
-
```
|
|
25
|
+
### 1. Inspect before asking
|
|
137
26
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
artifact, projection round-trip, semantic review, grounding check, and gate
|
|
142
|
-
passes. The author never fabricates or directly writes that conclusion.
|
|
27
|
+
Find current entrypoints, reusable code, callers, tests, docs, and runtime
|
|
28
|
+
registration. Cite concrete `path:line` evidence. Mark facts that cannot be
|
|
29
|
+
verified as `[UNVERIFIED]` and state what would settle them.
|
|
143
30
|
|
|
144
|
-
|
|
31
|
+
### 2. Open C1 once
|
|
145
32
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
33
|
+
Summarize what exists, the minimum change set, and expansion signals. Ask the
|
|
34
|
+
user to EXPAND, KEEP, or CUT. Record the answer and explicit exclusions. Do not
|
|
35
|
+
repeat scope objections later unless new evidence invalidates the decision.
|
|
149
36
|
|
|
150
|
-
|
|
151
|
-
|
|
37
|
+
### 3. Author the flat packet
|
|
38
|
+
|
|
39
|
+
Read `skills/specs/references/templates.md`, then create:
|
|
152
40
|
|
|
153
41
|
```text
|
|
154
|
-
|
|
155
|
-
|
|
42
|
+
specs/<feature>/plan.md
|
|
43
|
+
specs/<feature>/task-01-<slug>.md
|
|
44
|
+
specs/<feature>/task-NN-<slug>.md
|
|
156
45
|
```
|
|
157
46
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
47
|
+
Keep tasks flat beside the plan. Each task owns one outcome, normally no more
|
|
48
|
+
than about five files, explicit acceptance IDs, dependencies, and a runnable
|
|
49
|
+
Verification Plan. Every criterion maps to at least one task and one proof.
|
|
50
|
+
Use EARS sentences for observable acceptance behavior.
|
|
51
|
+
|
|
52
|
+
Do not create implementation files, receipts, approval records, generated
|
|
53
|
+
registries, readiness claims, or empty supporting documents. Leave every new
|
|
54
|
+
task `Status: pending` and its `## Receipt` empty.
|
|
55
|
+
|
|
56
|
+
### 4. Review from fresh context
|
|
57
|
+
|
|
58
|
+
Read `skills/specs/references/review.md`. Route fresh reviewers by capability
|
|
59
|
+
and give them only the plan packet plus repository access. Require a severity,
|
|
60
|
+
plan location, concrete failure, current `path:line` evidence, and smallest
|
|
61
|
+
repair for every finding.
|
|
62
|
+
|
|
63
|
+
Deduplicate and cap findings at 15. Open C2 so the user can accept, reject, or
|
|
64
|
+
revise each one. Apply only accepted changes and run the full consistency sweep
|
|
65
|
+
after every edit. Stop after two paper rounds; later findings need runtime
|
|
66
|
+
evidence.
|
|
162
67
|
|
|
163
|
-
|
|
68
|
+
### 5. Hand off without dispatch
|
|
164
69
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
| routed design | `rules/design-principles.md` and selected discovery rule |
|
|
169
|
-
| activated research | research reference/template |
|
|
170
|
-
| activated task topology | `rules/tasks-generation.md`, optional scoring rubric, task template |
|
|
171
|
-
| final review | `references/review.md`, review and grounding rules |
|
|
70
|
+
Report the created files, C1 decision, accepted C2 findings, remaining
|
|
71
|
+
uncertainties, task order, and first unblocked task. Do not start Develop or
|
|
72
|
+
claim implementation readiness. The user chooses when execution begins.
|
|
172
73
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
74
|
+
## Authoring constraints
|
|
75
|
+
|
|
76
|
+
- One mutable fact has one home; other files link to it.
|
|
77
|
+
- A task is not a bucket for several independent outcomes.
|
|
78
|
+
- Unknown outcomes become questions, not guessed requirements.
|
|
79
|
+
- Ambiguous rules receive two or three examples before C2.
|
|
80
|
+
- Ownership overlap or dependency uncertainty prevents a parallel claim.
|
|
81
|
+
- A command that cannot be run from the named work context is not verification.
|
|
82
|
+
- User approval and test proof are different facts; never infer either.
|
|
83
|
+
- Existing legacy specs remain untouched unless migration is explicitly asked.
|
|
84
|
+
|
|
85
|
+
## Output
|
|
86
|
+
|
|
87
|
+
End with:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
Status: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT
|
|
91
|
+
Files: <plan and task paths>
|
|
92
|
+
C1: <decision>
|
|
93
|
+
C2: <accepted/rejected/revised counts>
|
|
94
|
+
Next: <first unblocked task or blocker>
|
|
95
|
+
Unresolved questions: <none or concise list>
|
|
96
|
+
```
|
package/src/claude/gitignore
CHANGED
|
@@ -78,6 +78,40 @@ function bindFixtureReceipt(dir, value) {
|
|
|
78
78
|
return value.replaceAll(VALID_BASE, context.base).replaceAll(VALID_HEAD, context.head);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
function workflowRuntimeContext(dir) {
|
|
82
|
+
return PROVENANCE.deriveRuntimeContext({
|
|
83
|
+
projectRoot: dir,
|
|
84
|
+
specsRoot: path.join(dir, 'specs'),
|
|
85
|
+
specFile: path.join(dir, 'specs', FEATURE, 'plan.md'),
|
|
86
|
+
featureName: FEATURE,
|
|
87
|
+
runtimeSession: 'test',
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function makeWorkflowFixture(receiptLines = [], plannedCommand = 'node --test') {
|
|
92
|
+
const dir = tmpDir();
|
|
93
|
+
const featureDir = path.join(dir, 'specs', FEATURE);
|
|
94
|
+
fs.mkdirSync(featureDir, { recursive: true });
|
|
95
|
+
fs.writeFileSync(path.join(featureDir, 'plan.md'), '# Demo plan\n');
|
|
96
|
+
const context = workflowRuntimeContext(dir);
|
|
97
|
+
const task = [
|
|
98
|
+
'# Task 01: demo',
|
|
99
|
+
'',
|
|
100
|
+
'Status: done',
|
|
101
|
+
'',
|
|
102
|
+
'## Verification Plan',
|
|
103
|
+
'',
|
|
104
|
+
`- Command: ${plannedCommand}`,
|
|
105
|
+
'',
|
|
106
|
+
...receiptLines,
|
|
107
|
+
'',
|
|
108
|
+
].join('\n')
|
|
109
|
+
.replaceAll(VALID_BASE, context.base)
|
|
110
|
+
.replaceAll(VALID_HEAD, context.head);
|
|
111
|
+
fs.writeFileSync(path.join(featureDir, 'task-01-demo.md'), task);
|
|
112
|
+
return dir;
|
|
113
|
+
}
|
|
114
|
+
|
|
81
115
|
function installFeatureReceipt(dir, featureName = FEATURE, session = 'test') {
|
|
82
116
|
const featureDir = path.join(dir, 'specs', featureName);
|
|
83
117
|
const specFile = path.join(featureDir, 'spec.json');
|
|
@@ -1241,3 +1275,131 @@ test('30. phantom vectors via gate evidence must block with verification_state (
|
|
|
1241
1275
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
1242
1276
|
}
|
|
1243
1277
|
});
|
|
1278
|
+
|
|
1279
|
+
test('31. process-v3 done task without inline Receipt blocks', () => {
|
|
1280
|
+
const dir = makeWorkflowFixture();
|
|
1281
|
+
try {
|
|
1282
|
+
clearCache();
|
|
1283
|
+
const body = parseBlock(runHook({}, dir).stdout);
|
|
1284
|
+
assert.ok(body, 'missing process-v3 receipt should block');
|
|
1285
|
+
assert.strictEqual(body.decision, 'block');
|
|
1286
|
+
assert.match(body.reason, /missing_receipt/);
|
|
1287
|
+
assert.match(body.reason, /## Receipt/);
|
|
1288
|
+
} finally {
|
|
1289
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
|
|
1293
|
+
test('32. process-v3 requires Receipt heading and runtime-bound provenance', () => {
|
|
1294
|
+
const legacyHeading = makeWorkflowFixture([
|
|
1295
|
+
'## Evidence', '', 'Verification: PASS', 'Command: node --test', 'Exit: 0',
|
|
1296
|
+
`Base: ${VALID_BASE}`, `Head: ${VALID_HEAD}`, '```text', 'pass', '```',
|
|
1297
|
+
]);
|
|
1298
|
+
try {
|
|
1299
|
+
clearCache();
|
|
1300
|
+
const body = parseBlock(runHook({}, legacyHeading).stdout);
|
|
1301
|
+
assert.ok(body, 'legacy Evidence heading must not satisfy process-v3 receipt');
|
|
1302
|
+
assert.match(body.reason, /missing_receipt/);
|
|
1303
|
+
} finally {
|
|
1304
|
+
fs.rmSync(legacyHeading, { recursive: true, force: true });
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
const stale = makeWorkflowFixture([
|
|
1308
|
+
'## Receipt', '', 'Verification: PASS', 'Command: node --test', 'Exit: 0',
|
|
1309
|
+
`Base: ${VALID_BASE}`, `Head: ${VALID_BASE}`, '```text', 'pass', '```',
|
|
1310
|
+
]);
|
|
1311
|
+
try {
|
|
1312
|
+
clearCache();
|
|
1313
|
+
const body = parseBlock(runHook({}, stale).stdout);
|
|
1314
|
+
assert.ok(body, 'stale process-v3 provenance should block');
|
|
1315
|
+
assert.match(body.reason, /provenance/);
|
|
1316
|
+
} finally {
|
|
1317
|
+
fs.rmSync(stale, { recursive: true, force: true });
|
|
1318
|
+
}
|
|
1319
|
+
});
|
|
1320
|
+
|
|
1321
|
+
test('33. process-v3 done task with canonical inline Receipt passes', () => {
|
|
1322
|
+
const dir = makeWorkflowFixture([
|
|
1323
|
+
'## Receipt', '', 'Verification: PASS', 'Command: node --test', 'Exit: 0',
|
|
1324
|
+
`Base: ${VALID_BASE}`, `Head: ${VALID_HEAD}`, '```text', '$ node --test', 'pass: 1', '```',
|
|
1325
|
+
]);
|
|
1326
|
+
try {
|
|
1327
|
+
clearCache();
|
|
1328
|
+
const result = runHook({}, dir);
|
|
1329
|
+
assert.strictEqual(result.code, 0, result.stderr);
|
|
1330
|
+
assert.strictEqual(result.stdout, '');
|
|
1331
|
+
} finally {
|
|
1332
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1333
|
+
}
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
test('34. process-v3 Receipt command must match the exact Verification Plan command', () => {
|
|
1337
|
+
const dir = makeWorkflowFixture([
|
|
1338
|
+
'## Receipt', '', 'Verification: PASS', 'Command: true', 'Exit: 0',
|
|
1339
|
+
`Base: ${VALID_BASE}`, `Head: ${VALID_HEAD}`, '```text', '$ true', 'pass: 1', '```',
|
|
1340
|
+
], 'pnpm test');
|
|
1341
|
+
try {
|
|
1342
|
+
clearCache();
|
|
1343
|
+
const body = parseBlock(runHook({}, dir).stdout);
|
|
1344
|
+
assert.ok(body, 'a substituted receipt command must block');
|
|
1345
|
+
assert.strictEqual(body.decision, 'block');
|
|
1346
|
+
assert.match(body.reason, /command_identity/);
|
|
1347
|
+
} finally {
|
|
1348
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
|
|
1352
|
+
test('35. process-v3 Stop ignores a completed packet when one packet remains active', () => {
|
|
1353
|
+
const dir = makeWorkflowFixture([
|
|
1354
|
+
'## Receipt', '', 'Verification: PASS', 'Command: node --test', 'Exit: 0',
|
|
1355
|
+
`Base: ${VALID_BASE}`, `Head: ${VALID_HEAD}`, '```text', '$ node --test', 'pass: 1', '```',
|
|
1356
|
+
]);
|
|
1357
|
+
try {
|
|
1358
|
+
const activeDir = path.join(dir, 'specs', 'active');
|
|
1359
|
+
fs.mkdirSync(activeDir, { recursive: true });
|
|
1360
|
+
fs.writeFileSync(path.join(activeDir, 'plan.md'), '# Active plan\n');
|
|
1361
|
+
fs.writeFileSync(path.join(activeDir, 'task-01-active.md'), [
|
|
1362
|
+
'# Task 01: active', '', 'Status: pending', '',
|
|
1363
|
+
'## Verification Plan', '', '- Command: node --test', '',
|
|
1364
|
+
].join('\n'));
|
|
1365
|
+
clearCache();
|
|
1366
|
+
const result = runHook({}, dir);
|
|
1367
|
+
assert.strictEqual(result.code, 0, result.stderr);
|
|
1368
|
+
assert.strictEqual(result.stdout, '');
|
|
1369
|
+
} finally {
|
|
1370
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
test('36. process-v3 Stop accepts two completed packets with valid Receipts', () => {
|
|
1375
|
+
const dir = makeWorkflowFixture([
|
|
1376
|
+
'## Receipt', '', 'Verification: PASS', 'Command: node --test', 'Exit: 0',
|
|
1377
|
+
`Base: ${VALID_BASE}`, `Head: ${VALID_HEAD}`, '```text', '$ node --test', 'pass: 1', '```',
|
|
1378
|
+
]);
|
|
1379
|
+
try {
|
|
1380
|
+
const otherDir = path.join(dir, 'specs', 'other');
|
|
1381
|
+
fs.mkdirSync(otherDir, { recursive: true });
|
|
1382
|
+
fs.writeFileSync(path.join(otherDir, 'plan.md'), '# Other plan\n');
|
|
1383
|
+
const context = PROVENANCE.deriveRuntimeContext({
|
|
1384
|
+
projectRoot: dir,
|
|
1385
|
+
specsRoot: path.join(dir, 'specs'),
|
|
1386
|
+
specFile: path.join(otherDir, 'plan.md'),
|
|
1387
|
+
featureName: 'other',
|
|
1388
|
+
runtimeSession: 'test',
|
|
1389
|
+
});
|
|
1390
|
+
fs.writeFileSync(path.join(otherDir, 'task-01-other.md'), [
|
|
1391
|
+
'# Task 01: other', '', 'Status: done', '',
|
|
1392
|
+
'## Verification Plan', '', '- Command: node --test', '',
|
|
1393
|
+
'## Receipt', '',
|
|
1394
|
+
'Verification: PASS', 'Command: node --test', 'Exit: 0',
|
|
1395
|
+
`Base: ${context.base}`, `Head: ${context.head}`,
|
|
1396
|
+
'```text', '$ node --test', 'pass: 1', '```', '',
|
|
1397
|
+
].join('\n'));
|
|
1398
|
+
clearCache();
|
|
1399
|
+
const result = runHook({}, dir);
|
|
1400
|
+
assert.strictEqual(result.code, 0, result.stderr);
|
|
1401
|
+
assert.strictEqual(result.stdout, '');
|
|
1402
|
+
} finally {
|
|
1403
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1404
|
+
}
|
|
1405
|
+
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* context.cjs - Context/reminder building for session injection
|
|
4
4
|
*
|
|
5
|
-
* Extracted from hooks for reuse
|
|
5
|
+
* Extracted from hooks for reuse across runtime adapters.
|
|
6
6
|
* Builds session context, rules, paths, and plan information.
|
|
7
7
|
*
|
|
8
8
|
* @module context
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* detect.cjs - Project and environment detection logic
|
|
4
4
|
*
|
|
5
|
-
* Extracted from session.cjs for reuse
|
|
5
|
+
* Extracted from session.cjs for reuse across runtime adapters.
|
|
6
6
|
* Detects project type, package manager, framework, and runtime versions.
|
|
7
7
|
*
|
|
8
8
|
* @module detect
|
|
@@ -93,6 +93,7 @@ try {
|
|
|
93
93
|
if (typeof POLICY.validateCanonicalReceipt !== 'function'
|
|
94
94
|
|| typeof POLICY.completionDecisionForSpec !== 'function'
|
|
95
95
|
|| typeof RECEIPT.checkTaskReceipt !== 'function'
|
|
96
|
+
|| typeof RECEIPT.checkWorkflowReceiptSet !== 'function'
|
|
96
97
|
|| typeof FINAL_STATE.evaluateCloseout !== 'function') {
|
|
97
98
|
throw new Error('shared workflow policy lacks completion authority functions');
|
|
98
99
|
}
|
|
@@ -112,8 +113,37 @@ try {
|
|
|
112
113
|
} catch { /* gate stays on */ }
|
|
113
114
|
// Active-spec discovery via shared resolver — explicit target if present, else fail on ambiguity.
|
|
114
115
|
const baseDir = cwd;
|
|
115
|
-
const
|
|
116
|
+
const target = typeof RESOLVER.extractExplicitTarget === 'function'
|
|
117
|
+
? RESOLVER.extractExplicitTarget(payload)
|
|
118
|
+
: null;
|
|
119
|
+
let resolved = typeof RESOLVER.resolveWorkflowCandidate === 'function'
|
|
120
|
+
? RESOLVER.resolveWorkflowCandidate({ projectRoot: baseDir, runtime, target, includeCompleted: true })
|
|
121
|
+
: FINAL_STATE.resolveCandidate({ resolver: RESOLVER, projectRoot: baseDir, runtime, payload });
|
|
122
|
+
if (typeof RESOLVER.refineWorkflowGateResolution === 'function') {
|
|
123
|
+
resolved = RESOLVER.refineWorkflowGateResolution(resolved);
|
|
124
|
+
}
|
|
116
125
|
if (!resolved) process.exit(0);
|
|
126
|
+
if (resolved.layoutKind === 'process-v3-completed-set') {
|
|
127
|
+
const configuredGate = runtime.spec?.completion_gate;
|
|
128
|
+
if (configuredGate !== undefined && configuredGate !== true) {
|
|
129
|
+
emitBlock('Completion gate: runtime.spec.completion_gate is a worker-writable flag, not an authorization; no completion-gate bypass is supported. Remove the flag and satisfy the gate.');
|
|
130
|
+
process.exit(0);
|
|
131
|
+
}
|
|
132
|
+
const checked = RECEIPT.checkWorkflowReceiptSet(
|
|
133
|
+
resolved.candidates,
|
|
134
|
+
baseDir,
|
|
135
|
+
sessionIdentity(payload),
|
|
136
|
+
POLICY,
|
|
137
|
+
);
|
|
138
|
+
if (checked.failures.length === 0) process.exit(0);
|
|
139
|
+
const lines = [`⚠️ Completion gate: ${checked.failures.length} done task(s) lack a verification receipt.`];
|
|
140
|
+
for (const failure of checked.failures) {
|
|
141
|
+
lines.push(`- \`${failure.featureName}/${failure.taskPath}\`: failed check(s) ${failure.failures.join(', ')}`);
|
|
142
|
+
lines.push(` Fix: write a runtime-bound \`## Receipt\` with the planned command in \`specs/${failure.featureName}/${failure.taskPath}\`.`);
|
|
143
|
+
}
|
|
144
|
+
emitBlock(lines.slice(0, 8).join('\n'));
|
|
145
|
+
process.exit(0);
|
|
146
|
+
}
|
|
117
147
|
if (resolved.error === 'multiple_active' || resolved.error === 'multiple_persisted') {
|
|
118
148
|
process.stdout.write(JSON.stringify({
|
|
119
149
|
decision: 'block',
|
|
@@ -137,13 +167,14 @@ try {
|
|
|
137
167
|
}
|
|
138
168
|
if (resolved.error) process.exit(0);
|
|
139
169
|
|
|
140
|
-
const activeSpec = resolved.spec;
|
|
170
|
+
const activeSpec = resolved.spec || {};
|
|
171
|
+
const processWorkflow = resolved.layoutKind === 'process-v3';
|
|
141
172
|
const featureName = resolved.featureName;
|
|
142
173
|
const specsPath = resolved.specsDir;
|
|
143
174
|
const lifecyclePhase = activeSpec.current_phase || activeSpec.phase;
|
|
144
175
|
const explicitCloseout = ['done', 'completed', 'complete'].includes(activeSpec.status)
|
|
145
176
|
|| ['closeout', 'completion', 'completed', 'complete'].includes(lifecyclePhase);
|
|
146
|
-
if (activeSpec.schema_version === '2.1') {
|
|
177
|
+
if (!processWorkflow && activeSpec.schema_version === '2.1') {
|
|
147
178
|
const finalState = FINAL_STATE.evaluateCloseout({
|
|
148
179
|
resolver: RESOLVER,
|
|
149
180
|
policy: POLICY,
|
|
@@ -160,7 +191,7 @@ try {
|
|
|
160
191
|
const runtimeContext = POLICY.deriveRuntimeContext({
|
|
161
192
|
projectRoot: baseDir,
|
|
162
193
|
specsRoot: specsPath,
|
|
163
|
-
specFile: resolved.specFile || path.join(specsPath, featureName, 'spec.json'),
|
|
194
|
+
specFile: resolved.stateFile || resolved.specFile || path.join(specsPath, featureName, 'spec.json'),
|
|
164
195
|
featureName,
|
|
165
196
|
runtimeSession: sessionIdentity(payload),
|
|
166
197
|
});
|
|
@@ -170,7 +201,7 @@ try {
|
|
|
170
201
|
emitBlock('Completion gate: runtime.spec.completion_gate is a worker-writable flag, not an authorization; no completion-gate bypass is supported. Remove the flag and satisfy the gate.');
|
|
171
202
|
process.exit(0);
|
|
172
203
|
}
|
|
173
|
-
const taskRegistry = activeSpec.task_registry || {};
|
|
204
|
+
const taskRegistry = resolved.taskRegistry || activeSpec.task_registry || {};
|
|
174
205
|
const cacheFile = path.join(__dirname, '.logs', 'spec-gate-last.json');
|
|
175
206
|
const cacheExists = fs.existsSync(cacheFile);
|
|
176
207
|
let cache = {};
|
|
@@ -183,7 +214,7 @@ try {
|
|
|
183
214
|
currentStatuses[tp] = task?.status || 'pending';
|
|
184
215
|
}
|
|
185
216
|
|
|
186
|
-
const staleFlashTasks = Object.entries(taskRegistry)
|
|
217
|
+
const staleFlashTasks = processWorkflow ? [] : Object.entries(taskRegistry)
|
|
187
218
|
.filter(([, task]) => POLICY.isStaleFlashDone(task))
|
|
188
219
|
.map(([taskPath]) => taskPath);
|
|
189
220
|
if (staleFlashTasks.length > 0) {
|
|
@@ -206,11 +237,13 @@ try {
|
|
|
206
237
|
const failures = allDoneTasks
|
|
207
238
|
.map((taskPath) => ({
|
|
208
239
|
taskPath,
|
|
209
|
-
fails:
|
|
240
|
+
fails: processWorkflow
|
|
241
|
+
? RECEIPT.checkWorkflowTaskReceipt(featureDir, taskPath, runtimeContext, POLICY).failures
|
|
242
|
+
: RECEIPT.checkTaskReceipt(featureDir, taskPath, taskRegistry[taskPath], runtimeContext, POLICY).failures,
|
|
210
243
|
}))
|
|
211
244
|
.filter((f) => f.fails.length > 0);
|
|
212
245
|
|
|
213
|
-
const featureCloseoutRequired = explicitCloseout && allDoneTasks.length > 0;
|
|
246
|
+
const featureCloseoutRequired = !processWorkflow && explicitCloseout && allDoneTasks.length > 0;
|
|
214
247
|
const featureReceipt = featureCloseoutRequired
|
|
215
248
|
? RECEIPT.checkFeatureReceipt(featureDir, runtimeContext, POLICY)
|
|
216
249
|
: null;
|
|
@@ -253,7 +286,9 @@ try {
|
|
|
253
286
|
lines.push(`- \`${taskPath}\`: failed check(s) ${fails.join(', ')}`);
|
|
254
287
|
lines.push(taskPath === 'feature-receipt.md'
|
|
255
288
|
? ` Fix: run final integration proof, then write \`specs/${featureName}/feature-receipt.md\`.`
|
|
256
|
-
:
|
|
289
|
+
: processWorkflow
|
|
290
|
+
? ` Fix: write a runtime-bound \`## Receipt\` with command output in \`specs/${featureName}/${path.posix.basename(taskPath)}\`.`
|
|
291
|
+
: ` Fix: write canonical proof to \`specs/${featureName}/receipts/${path.posix.basename(taskPath)}\`; legacy \`## Evidence\` remains read-compatible.`);
|
|
257
292
|
}
|
|
258
293
|
if (completionBlocked) {
|
|
259
294
|
lines.push(`- Completion decision unfinished: ${completion.blocker || 'required workflow proof is missing.'}`);
|