feat: harden OpenSpec SDD workflow

This commit is contained in:
2026-08-26 00:42:35 +03:00
parent 039b72eed3
commit a8b2c4eed9
42 changed files with 4024 additions and 181 deletions
+24
View File
@@ -0,0 +1,24 @@
# OpenCode agent projection authority
This directory is the committed canonical source for WealthLedger-owned
OpenCode `commands` and `skills`. Workspace root `.opencode/commands` and
`.opencode/skills` are derived output, not a second SDD authority.
The source intentionally excludes `.opencode/package.json`, lockfiles,
`node_modules`, `.gitignore` and all machine-local runtime state.
From the workspace root:
```bash
bash specs/scripts/sync-agent-projection.sh
bash specs/scripts/verify-agent-projection.sh
```
Edit this source tree first. The sync performs a verified cutover and restores
the previous local projection if installation or verification fails. The
non-mutating verifier checks the exact required file set, contents and each
skill's `generatedBy` marker against `specs/openspec/.cli-version`.
For an OpenSpec upgrade, prepare the upstream projection in isolated staging,
reapply the minimal WealthLedger overlays, update the exact version contract
only after compatibility fixtures pass, then sync this canonical tree.
@@ -0,0 +1,186 @@
---
description: "Implement tasks from an OpenSpec change (Experimental)"
---
Implement tasks from an OpenSpec change.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Apply is allowed only after explicit Change Owner approval of Proposal, Delta Specs, Design and Tasks in sequence. CLI status and file existence prove structure, not approval. Establish approvals from the conversation; if evidence is unavailable, ask again and stop. If any approved upstream artifact changed after downstream approval, invalidate dependent approvals and return to planning before implementation.
**Planning gate and feedback:** Before implementation run `bash specs/scripts/verify-openspec-planning.sh "<name>"`. A structural failure blocks Apply. During Apply route intent/scope to Proposal, observable behavior to Delta Specs, architecture/rollback to Design, and decomposition/ownership/coverage to Tasks; stop downstream work and invalidate dependent approvals. A format-only correction may be fixed and revalidated without reapproval only when it changes none of those semantics.
**Input**: Optionally specify a change name (e.g., `/opsx-apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes and ask the user to select one
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-apply <other>`).
2. **Check status to understand the schema**
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Parse the JSON to understand:
- `schemaName`: The workflow being used (e.g., "spec-driven")
- `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints
- Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
3. **Get apply instructions**
```bash
openspec instructions apply --change "<name>" --json --store wealth-ledger-specs
```
This returns:
- `contextFiles`: artifact ID -> array of concrete file paths (varies by schema - could be proposal/specs/design/tasks or spec/tests/implementation/docs)
- Progress (total, complete, remaining)
- Task list with status
- Dynamic instruction based on current state
- Optional `context`: current required project instruction input from the selected root
- Optional `operationGuidance`: current advisory guidance for apply
**Handle states:**
- If `state: "blocked"` (missing artifacts): show message, suggest using `/opsx-continue` (if it is not installed, run `openspec status --change "<name>" --json --store wealth-ledger-specs` to see the next artifact and `openspec instructions <artifact-id> --change "<name>" --json --store wealth-ledger-specs` for how to create it)
- If `state: "all_done"`: congratulate, suggest archive
- Otherwise: proceed to implementation
Treat `context` as a required prompt-level input. Read and consider it, and
apply relevant project facts, conventions, and constraints while implementing.
Treat `operationGuidance` as optional additive advice. Read and consider every
entry, and follow entries that are applicable and compatible with the built-in
workflow.
Keep both fields separate from CLI-returned state, missing artifacts, tasks,
progress, `contextFiles`, and the built-in `instruction`. They are not
evidence of task completion, do not replace the built-in instruction, and do
not permit bypassing a blocked state. If context conflicts with the built-in
instruction, an explicit user choice, or a CLI-controlled value, report the
conflict and preserve the controlling value. If guidance is inapplicable or
conflicts with those controlling inputs, do not follow it and explain why.
These are prompt-level behavior contracts, not enforceable checks.
4. **Read context files**
Read every file path listed under `contextFiles` from the apply instructions output.
The files depend on the schema being used:
- **spec-driven**: proposal, specs, design, tasks
- Other schemas: follow the contextFiles from CLI output
Do not copy `context` or `operationGuidance` verbatim into implementation
files or planning artifacts unless the user separately asks for that content.
5. **Show current progress**
Display:
- Schema being used
- Progress: "N/M tasks complete"
- Remaining tasks overview
- Dynamic instruction from CLI
6. **Implement tasks (loop until done or blocked)**
For each pending task:
- Show which task is being worked on
- Make the code changes required
- Keep changes minimal and focused
- Mark task complete in the tasks file: `- [ ]` → `- [x]`
- Continue to next task
**Pause if:**
- Task is unclear → ask for clarification
- Implementation reveals a design issue → suggest updating artifacts
- A task needs work beyond what the spec and tasks describe, or you are tempted to drop, narrow, defer, or accept exceptions to specified behavior to make it fit → surface the added scope and ask; do not absorb it silently
- Error or blocker encountered → report and wait for guidance
- User interrupts
7. **On completion or pause, show status**
Display:
- Tasks completed this session
- Overall progress: "N/M tasks complete"
- If all done: suggest archive
- If paused: explain why and wait for guidance
**Output During Implementation**
```
## Implementing: <change-name> (schema: <schema-name>)
Working on task 3/7: <task description>
[...implementation happening...]
✓ Task complete
Working on task 4/7: <task description>
[...implementation happening...]
✓ Task complete
```
**Output On Completion**
```
## Implementation Complete
**Change:** <change-name>
**Schema:** <schema-name>
**Progress:** 7/7 tasks complete ✓
### Completed This Session
- [x] Task 1
- [x] Task 2
...
All tasks complete! You can archive this change with `/opsx-archive`.
```
**Output On Pause (Issue Encountered)**
```
## Implementation Paused
**Change:** <change-name>
**Schema:** <schema-name>
**Progress:** 4/7 tasks complete
### Issue Encountered
<description of the issue>
**Options:**
1. <option 1>
2. <option 2>
3. Other approach
What would you like to do?
```
**Guardrails**
- Keep going through tasks until done or blocked
- Always read context files before starting (from the apply instructions output)
- If task is ambiguous, pause and ask before implementing
- If implementation reveals issues, pause and suggest artifact updates
- Keep code changes minimal and scoped to each task
- Update task checkbox immediately after completing each task
- Pause on errors, blockers, or unclear requirements - don't guess
- When a task needs work beyond what the spec describes, surface the added scope and pause - never silently narrow, defer, or simplify away specified behavior
- Only mark a task `- [x]` when its specified behavior is fully implemented, not when it is partially done or deferred
- Use contextFiles from CLI output, don't assume specific file names
- Do not use context or operation guidance as proof that a task is complete
- Apply relevant project context; report conflicts with controlling workflow inputs
- Consider every guidance entry; explain any inapplicable or conflicting advice
- Do not copy runtime context or operation guidance into implementation files or planning artifacts
- Preserve CLI-controlled blocked/ready/all-done behavior and completion criteria
**Fluid Workflow Integration**
This skill supports the "actions on a change" model:
- **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly
@@ -0,0 +1,222 @@
---
description: "Archive a completed change in the experimental workflow"
---
Archive a completed change in the experimental workflow.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Archive requires explicit Change Owner approval of Proposal, Delta Specs, Design and Tasks in sequence. File/status existence is not approval. If approval evidence is unavailable, or an upstream artifact changed, invalidate dependent approvals and require cascading reapproval; stop without offering an override.
**Planning gate:** Before any archive mutation run `bash specs/scripts/verify-openspec-planning.sh "<name>"`; the full workspace dispatcher repeats it. A failure blocks archive without override, and structural success cannot replace semantic verification or independent read-only review.
`<capability-path>` is the spec directory relative to `specs/` (for example, `user-auth` or `identity/user-auth`). Preserve the full path from each delta spec when resolving its main spec.
**Input**: Optionally specify a change name after `/opsx-archive` (e.g., `/opsx-archive add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes and ask the user to select one
When prompting, show only active changes (not already archived).
Include the schema used for each change if available.
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-archive <other>`).
**Load current archive inputs before the existing archive checks:**
After resolving the selected change and planning root, run:
```bash
openspec instructions archive --change "<name>" --json --store wealth-ledger-specs
```
Keep the same selected-root flags on this command. This lookup is advisory and
optional: it only supplies extra prompt inputs, so it must never block archiving.
If it exits non-zero or returns invalid JSON — for example on an older CLI that
does not support this command yet — continue the archive workflow with no
context and no operation guidance. Do not report an error and do not stop.
A successful response may omit both optional fields. Treat `context` as a
required prompt-level input: read and consider it, and apply relevant project
facts, conventions, and constraints. Treat `operationGuidance` as optional
additive advice: read and consider every entry, and follow entries that are
applicable and compatible with the built-in archive workflow.
Keep both fields separate from built-in steps, explicit user choices, resolved
paths, CLI checks, and command contracts. If context conflicts with one of those
controlling inputs, report the conflict and preserve the controlling value. If
guidance is inapplicable or conflicts with a controlling input, do not follow it
and explain why. Do not infer replacement paths, skipped prompts, or flags from
either field, and do not copy their text verbatim into specs, change artifacts,
or archive summaries unless the user separately asks for it. These are
prompt-level behavior contracts, not enforceable checks.
2. **Check artifact completion status**
Run `openspec status --change "<name>" --json --store wealth-ledger-specs` to check artifact completion.
Parse the JSON to understand:
- `schemaName`: The workflow being used
- `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context
- `artifacts`: List of artifacts with their status (`done`, `skipped`, or other)
**If any artifacts are neither `done` nor `skipped`** (skipped artifacts satisfy the requirement - the change declares skip_specs):
- Stop without syncing or archiving.
- Report the incomplete artifacts as blocking conditions.
- Do not ask for or accept a confirmation override.
3. **Check task completion status**
Read the tasks file (typically `tasks.md`) to check for incomplete tasks.
Count tasks marked with `- [ ]` (incomplete) vs `- [x]` (complete).
**If incomplete tasks found:**
- Stop without syncing or archiving.
- Report the incomplete tasks as blocking conditions.
- Do not ask for or accept a confirmation override.
**If no tasks file exists:** Stop without syncing or archiving. Report the missing `tasks.md` as a blocking condition.
**WealthLedger pre-archive gates:**
- Run `bash specs/scripts/verify-workspace-change.sh "<name>"` from the workspace root and require a successful result for every affected delivery area.
- Require successful semantic verification against Proposal, Delta Specs, Design and Tasks.
- Require a completed independent read-only review with no unresolved Critical or Important finding.
- Stop if any gate or evidence is missing or unsuccessful. Do not ask for or accept a confirmation override.
4. **Assess delta spec sync state**
Use `artifactPaths.specs.existingOutputPaths` from status JSON as the only
delta-spec source. If the `specs` entry is missing or
`existingOutputPaths` is empty, proceed without a sync prompt and do not infer
delta specs from other artifacts.
**If delta specs exist:**
- Compare each delta spec with its corresponding main spec at `<planningHome.root>/openspec/specs/<capability-path>/spec.md` (use the store-aware `planningHome.root` from step 2, not a hardcoded repo path)
- Determine what changes would be applied (adds, modifications, removals, renames)
- Show a combined summary before prompting
**Prompt options:**
- If changes needed: "Sync now (recommended)", "Archive without syncing"
- If already synced: "Archive now", "Sync anyway", "Cancel"
Route on the answer:
- "Cancel" — stop, do not archive
- "Archive without syncing" or "Archive now" — proceed to archive
- "Sync now" or "Sync anyway" — sync, then verify (below)
- Anything else — ask again rather than archiving
Before a selected sync writes any main spec, run
`openspec instructions specs --change "<name>" --json --store wealth-ledger-specs` once with the same
selected-root flags. Require a zero exit status and valid artifact-instruction
JSON. If the lookup fails or returns invalid JSON, report the error and stop
before writing any main spec or moving the change. A valid response with omitted
`rules` is the no-rules case. Apply returned `rules` only to the content and
form of main specs produced by this merge; do not use them as archive guidance,
change CLI behavior, or copy the rule text into any output file.
Then run the `/opsx-sync` workflow inline (agent-driven intelligent merge) for change '<name>', passing the delta spec analysis and the fetched specs-rule snapshot from above, and wait for it to finish. The inline sync must reuse that snapshot without fetching `specs` instructions again. Do not delegate it to a background task — step 5 would move `changeRoot` out from under a sync that is still reading it, leaving the change archived and the main specs never updated. If your agent can only run it by delegation, delegate synchronously and wait for the result.
Then re-run the comparison from the top of this step against every capability that has a delta spec in `artifactPaths.specs.existingOutputPaths` — not only the ones the sync reports it touched. A successful sync leaves nothing left to apply, so each capability must now read as already synced:
- ADDED requirements present
- MODIFIED requirements carrying the scenario and description changes named in the delta, with their other scenarios intact
- REMOVED requirements gone — and where this sync retired a capability (removed its last requirement, leaving `## Requirements` empty), its main spec deleted rather than left empty; a spec the sync deliberately kept and reported is also a match
- RENAMED requirements present under the new name and absent under the old one
If the sync failed, or any capability does not match, report what differs and stop — do not archive. Nothing has moved and `changeRoot` is intact, so the user can fix the mismatch or re-run the sync and start the archive again.
5. **Perform the archive**
Create an `archive` directory under `planningHome.changesDir` if it doesn't exist:
```bash
mkdir -p "<planningHome.changesDir>/archive"
```
Generate the target name: use the change name as-is when it already starts with a `YYYY-MM-DD-` prefix; otherwise prepend the current date as `YYYY-MM-DD-<change-name>`. Never stack a second date (same rule as `openspec archive --store wealth-ledger-specs`).
**Check if target already exists:**
- If yes: Fail with error, suggest renaming existing archive or using different date
- If no: Move `changeRoot` to the archive directory
```bash
mv "<changeRoot>" "<planningHome.changesDir>/archive/<target-name>"
```
6. **Display summary**
Show archive completion summary including:
- Change name
- Schema that was used
- Archive location
- Spec sync status (synced / sync skipped / no delta specs)
- Confirmation that all planning artifacts and tasks were complete before archive
After the move succeeds, use a deterministic two-phase evidence protocol:
- First commit the delivered changes in each affected repository, including the synced/archive state in `specs` and any as-built documentation in `docs`, and collect their actual commit IDs.
- Then write Completion Evidence in the durable registry/history with the archive path, Delivery Map, those delivery commit IDs, exact verification commands, observed results and independent review verdict.
- Commit Completion Evidence as a final follow-up in `docs`. The evidence cites the preceding docs delivery commit when docs was affected; when docs was `N/A`, it preserves that reason and does not invent an implementation commit. Its own follow-up commit cannot self-reference and is reported in the archive summary instead of repeatedly rewriting the record.
Do not add these post-archive actions as unchecked tasks in the archived change and do not claim terminal `done` before the evidence follow-up commit succeeds.
**Output On Success**
```markdown
## Archive Complete
**Change:** <change-name>
**Schema:** <schema-name>
**Archived to:** the archive path derived from `planningHome.changesDir`/<target-name>/
**Specs:** ✓ Synced to main specs
All artifacts complete. All tasks complete.
```
**Output On Success (No Delta Specs)**
```markdown
## Archive Complete
**Change:** <change-name>
**Schema:** <schema-name>
**Archived to:** the archive path derived from `planningHome.changesDir`/<target-name>/
**Specs:** No delta specs
All artifacts complete. All tasks complete.
```
**Output On Error (Archive Exists)**
```markdown
## Archive Failed
**Change:** <change-name>
**Target:** the archive path derived from `planningHome.changesDir`/<target-name>/
Target archive directory already exists.
**Options:**
1. Rename the existing archive
2. Delete the existing archive if it's a duplicate
3. Wait until a different date to archive
```
**Guardrails**
- Announce the selected change; prompt for selection when it is ambiguous
- Use artifact graph (`openspec status --json --store wealth-ledger-specs`) for completion checking
- Treat incomplete artifacts, a missing `tasks.md`, incomplete tasks, an affected delivery area failure, missing semantic verification and missing independent read-only review as hard blockers; never offer an override
- Preserve .openspec.yaml when moving to archive (it moves with the directory)
- Show clear summary of what happened
- If sync is requested, run the `/opsx-sync` workflow inline (agent-driven)
- Never archive while a spec sync is still in flight — run the sync inline and verify the main specs before moving `changeRoot`
- If delta specs exist, always run the sync assessment and show the combined summary before prompting
- Apply relevant runtime context and report conflicts; operation guidance remains advisory
- Consider every guidance entry and explain any inapplicable or conflicting advice
- Existing CLI checks, resolved paths, prompts, and command contracts are unchanged
- Artifact rules constrain only the specs being written and are never operation guidance
- Never copy runtime context, operation guidance, or artifact-rule text verbatim into output files
@@ -0,0 +1,116 @@
---
description: "Continue working on a change - create the next artifact (Experimental)"
---
Continue working on a change by creating the next artifact.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Create at most ONE planning artifact per invocation, then STOP for explicit Change Owner approval. Before creating a downstream artifact, establish from the conversation that every completed dependency was explicitly approved; file/status existence is not approval. If approval cannot be established, ask again and stop. If an approved upstream artifact changed, invalidate dependent approvals and return to that artifact instead of continuing downstream.
**Planning gate:** After writing or editing the one artifact and before requesting approval, run `bash specs/scripts/verify-openspec-planning.sh "<name>"`. Fix structural failures and rerun the available stage checks. Structural success does not grant approval; a semantic mismatch returns to the earliest affected artifact and invalidates dependent approvals.
**Input**: Optionally specify a change name after `/opsx-continue` (e.g., `/opsx-continue add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes sorted by most recently modified, and ask the user to select one
When prompting, present the top 3-4 most recently modified changes as options, showing:
- Change name
- Schema (from `schema` field if present, otherwise "spec-driven")
- Status (e.g., "0/5 tasks", "complete", "no tasks")
- How recently it was modified (from `lastModified` field)
Mark the most recently modified change as "(Recommended)" since it's likely what the user wants to continue.
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-continue <other>`).
2. **Check current status**
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Parse the JSON to understand current state. The response includes:
- `schemaName`: The workflow schema being used (e.g., "spec-driven")
- `artifacts`: Array of artifacts with their status ("done", "skipped", "ready", "blocked")
- `isPlanningComplete`: Boolean indicating if all planning artifacts are complete. Older CLI versions expose the same value as `isComplete`.
- `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context. Use these instead of assuming repo-local paths.
3. **Act based on status**:
---
**If all planning artifacts are complete (`isPlanningComplete: true`, or legacy `isComplete: true`)**:
- Congratulate the user
- Show final status including the schema used
- Suggest: "Planning is complete! You can now implement this change with `/opsx-apply`. Once implementation and any tracked work are complete, archive it with `/opsx-archive`."
- STOP
---
**If artifacts are ready to create** (status shows artifacts with `status: "ready"`):
- Pick the FIRST artifact with `status: "ready"` from the status output
- Get its instructions:
```bash
openspec instructions <artifact-id> --change "<name>" --json --store wealth-ledger-specs
```
- Parse the JSON. The key fields are:
- `context`: Project background (constraints for you - do NOT include in output)
- `rules`: Artifact-specific rules (constraints for you - do NOT include in output)
- `template`: The structure to use for your output file
- `instruction`: Schema-specific guidance
- `resolvedOutputPath`: Resolved path or pattern to write the artifact
- `dependencies`: Completed artifacts to read for context (entries with `skipped: true` have no files - do not look for them)
- `skipped`/`warning`: present when the change declares skip_specs and this artifact must NOT be created - pick another artifact
- **Create the artifact file**:
- Read any completed dependency files for context - always re-read them from disk, even if you saw them earlier in the conversation (the user may have edited them)
- If the `instruction` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at `resolvedOutputPath`
- Otherwise use `template` as the structure - fill in its sections
- Apply `context` and `rules` as constraints when writing - but do NOT copy them into the file
- Write to the `resolvedOutputPath` specified in instructions. If it is a glob pattern, choose the concrete file path using the schema instruction and the change's context
- Show what was created and what's now unlocked
- STOP after creating ONE artifact
---
**If no artifacts are ready (all blocked)**:
- This shouldn't happen with a valid schema
- Show status and suggest checking for issues
4. **After creating an artifact, show progress**
```bash
openspec status --change "<name>" --store wealth-ledger-specs
```
**Output**
After each invocation, show:
- Which artifact was created
- Schema workflow being used
- Current progress (N/M complete)
- What artifacts are now unlocked
- Prompt: "Run `/opsx-continue` to create the next artifact"
**Artifact Creation Guidelines**
The artifact types and their purpose depend on the schema. The `instruction` field from the instructions output is the authoritative guidance for each artifact - follow it even when the artifact has a familiar name (proposal.md, tasks.md, etc.), since custom schemas may define different content or a different process for the same file names.
If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly.
**Guardrails**
- Create ONE artifact per invocation
- Always read dependency artifacts before creating a new one - re-read from disk, not from conversation memory (files may have changed since you last saw them)
- Never skip artifacts or create out of order
- If context is unclear, ask the user before creating
- Verify the artifact file exists after writing before marking progress
- Use the schema's artifact sequence, don't assume specific artifact names
- **IMPORTANT**: `context` and `rules` are constraints for YOU, not content for the file
- Do NOT copy `<context>`, `<rules>`, `<project_context>` blocks into the artifact
- These guide what you write, but should never appear in the output
@@ -0,0 +1,37 @@
---
description: "Explore ideas without implementing or bypassing SDD approvals"
---
Enter explore mode as a thinking partner: investigate the codebase, clarify intent, compare mature solutions, surface risks and visualize trade-offs. Do not implement features or modify application code.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Exploration does not approve artifacts. If the user explicitly asks to capture a decision, create at most ONE planning artifact per invocation and then STOP for explicit Change Owner approval. Do not create an unapproved prerequisite or a downstream artifact merely because status reports it ready.
**Planning gate:** When exploration captures an artifact, run `bash specs/scripts/verify-openspec-planning.sh "<name>"` after the write and before requesting approval. Fix structural failures; if the captured decision changes upstream semantics, return to the earliest affected artifact and invalidate dependent approvals.
## Explore
- Read relevant code, durable docs and existing change artifacts.
- Use `openspec list --json --store wealth-ledger-specs` to discover active changes and `openspec status --change "<name>" --json --store wealth-ledger-specs` to resolve their paths.
- Ask questions only where the answer materially changes intent, behavior or architecture.
- For auth, security, storage, integrations, observability, caching, concurrency, infrastructure or tooling, compare mature supported solutions before recommending custom work.
- Offer to capture a stable decision in the appropriate current artifact; do not auto-capture it.
## Capture one artifact when explicitly requested
1. For a new change, scaffold it with `openspec new change "<name>" --store wealth-ledger-specs`. For an existing change, read its fresh status.
2. Confirm from the conversation that dependencies of the requested current artifact were explicitly approved. If approval cannot be established, ask again and stop.
3. The requested artifact must be the first `ready` artifact. Run `openspec instructions "<artifact-id>" --change "<name>" --json --store wealth-ledger-specs`, read completed dependencies and follow the returned template/instruction at `resolvedOutputPath`.
4. Create or update only that artifact, show fresh status, explain what downstream artifacts remain blocked by approval, and stop.
If an approved Proposal, Delta Specs or Design is edited, explicitly invalidate approval of its dependent artifacts according to the project cascade, report the affected artifacts and stop. Never rewrite downstream artifacts in the same invocation.
## Guardrails
- Explore mode may read and analyze freely but never writes implementation code.
- Create at most ONE planning artifact per invocation.
- File existence and CLI status are structural state, not owner approval.
- Do not create versioned planning documents outside `specs/openspec`.
@@ -0,0 +1,70 @@
---
description: "Start a new change using the experimental artifact workflow (OPSX)"
---
Start a new change using the experimental artifact-driven approach.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Input**: The argument after `/opsx-new` is the change name (kebab-case), OR a description of what the user wants to build.
**Steps**
1. **If no input provided, ask what they want to build**
Ask the user (open-ended, no preset options):
> "What change do you want to work on? Describe what you want to build or fix."
From their description, derive a kebab-case name (e.g., "add user authentication" → `add-user-auth`).
**IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
2. **Determine the workflow schema**
Use the default schema (omit `--schema`) unless the user explicitly requests a different workflow.
**Use a different schema only if the user mentions:**
- A specific schema name → use `--schema <name>`
- "show workflows" or "what workflows" → run `openspec schemas --json --store wealth-ledger-specs` and let them choose
**Otherwise**: Omit `--schema` to use the default.
3. **Create the change directory**
```bash
openspec new change "<name>" --store wealth-ledger-specs
```
Add `--schema <name>` only if the user requested a specific workflow.
This creates a scaffolded change in the planning home resolved by the CLI.
4. **Show the artifact status**
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Use the returned `planningHome`, `changeRoot`, `artifactPaths`, and `nextSteps` instead of assuming repo-local paths.
5. **Get instructions for the first artifact**
The first artifact depends on the schema. Check the status output to find the first artifact with status "ready".
```bash
openspec instructions <first-artifact-id> --change "<name>" --store wealth-ledger-specs
```
This outputs the template and context for creating the first artifact.
6. **STOP and wait for user direction**
**Output**
After completing the steps, summarize:
- Change name and location
- Schema/workflow being used and its artifact sequence
- Current status (0/N artifacts complete)
- The template for the first artifact
- Prompt: "Ready to create the first artifact? Run `/opsx-continue` or just describe what this change is about and I'll draft it."
**Guardrails**
- Do NOT create any artifacts yet - just show the instructions
- Do NOT advance beyond showing the first artifact template
- If the name is invalid (not kebab-case), ask for a valid name
- If a change with that name already exists, suggest using `/opsx-continue` instead
- Pass --schema if using a non-default workflow
@@ -0,0 +1,56 @@
---
description: "Start a change and draft its first planning artifact"
---
Start a WealthLedger OpenSpec change and draft only its first currently ready planning artifact. This workflow authorizes planning only and never implementation.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Create at most ONE planning artifact per invocation. After showing it, STOP for explicit Change Owner approval. File existence or OpenSpec `done` status is not approval. If approval of a dependency cannot be established from the current conversation, ask again before creating a downstream artifact.
**Planning gate:** After writing or editing the one artifact and before requesting approval, run `bash specs/scripts/verify-openspec-planning.sh "<name>"`. Fix structural failures and rerun the available stage checks. Structural success does not grant approval; a semantic mismatch returns to the earliest affected artifact and invalidates dependent approvals.
**Input:** A kebab-case change name or a description of the intended change.
## Steps
1. Understand the intent. If material scope, observable behavior, compatibility or acceptance criteria are ambiguous, ask before writing. Derive a kebab-case name when needed.
2. Use the configured default schema unless the user explicitly names another schema. To show available schemas, run `openspec schemas --json --store wealth-ledger-specs` and let the user choose.
3. Create only the scaffold:
```bash
openspec new change "<name>" --store wealth-ledger-specs
```
Add `--schema "<schema-name>"` only after an explicit schema choice.
4. Read status:
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Use returned `planningHome`, `changeRoot`, `artifactPaths` and `actionContext`; do not assume paths.
5. Select the first artifact with `status: "ready"`, then obtain its instructions:
```bash
openspec instructions "<artifact-id>" --change "<name>" --json --store wealth-ledger-specs
```
Apply `context`, `rules`, `template` and `instruction` as constraints. Write only to `resolvedOutputPath`; do not copy prompt-level context/rules into the artifact. For the default `wealth-ledger-sdd` schema the first artifact is Proposal and contains owner-readable intent without implementation details.
6. Verify that one artifact exists and show fresh status:
```bash
openspec status --change "<name>" --store wealth-ledger-specs
```
7. Show the drafted artifact and stop. Tell the user that explicit approval is required before `/opsx-continue` may create the next artifact.
## Guardrails
- Never create a downstream artifact in the same invocation, even if OpenSpec reports it ready.
- Never treat generated status, silence or the agent's own assessment as owner approval.
- If an approved upstream artifact changes, state which downstream approvals are invalidated and stop; do not regenerate them in this invocation.
- Do not edit application code or begin Apply.
- If the change already exists, ask whether to continue it instead of overwriting it.
@@ -0,0 +1,256 @@
---
description: "Sync delta specs from a change to main specs"
---
Sync delta specs from a change to main specs.
This is an **agent-driven** operation - you will read delta specs and directly edit main specs to apply the changes. This allows intelligent merging (e.g., adding a scenario without copying the entire requirement).
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
`<capability-path>` is the spec directory relative to `specs/` (for example, `user-auth` or `identity/user-auth`). Preserve the full path from each delta spec when resolving its main spec.
**Input**: Optionally specify a change name after `/opsx-sync` (e.g., `/opsx-sync add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes and ask the user to select one
When prompting, show changes that have delta specs (under `specs/` directory).
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-sync <other>`).
2. **Resolve change context**
Run:
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
The JSON includes `planningHome.root`. Main specs live under `<planningHome.root>/openspec/specs/` — use that (store-aware) root for every main-spec path below, not a hardcoded repo path. When a store is selected it points at the store, not the current repository.
3. **Find delta specs**
Use `artifactPaths.specs.existingOutputPaths` from the status JSON as the
only source of delta spec paths. If the `specs` entry is missing or
`existingOutputPaths` is empty, report that there are no delta specs to sync,
do not infer them from other artifacts, and stop without requesting artifact
instructions or writing a main spec.
Sync every path in `existingOutputPaths` unless the caller narrowed the set.
A caller narrows it by naming an explicit list of complete entries from
`existingOutputPaths` — copy those absolute values verbatim. Archive does
this inline, and a user can too (for example, by selecting the entry ending
in `/specs/billing/invoices/spec.md`).
Then sync only the named paths and leave the remaining delta specs untouched:
bulk archive excludes a delta whose implementation it could not find, and
syncing it anyway would write a main spec the caller deliberately withheld.
Carry that narrowed selection through step 4; never widen it back to the full
list. If a named path is not in `existingOutputPaths`, do not sync it —
report it and stop, rather than dropping it silently. If the named list is
empty, report that there is nothing to sync and stop without writing a main
spec.
Each delta spec file contains sections like:
- `## ADDED Requirements` - New requirements to add
- `## MODIFIED Requirements` - Changes to existing requirements
- `## REMOVED Requirements` - Requirements to remove
- `## RENAMED Requirements` - Requirements to rename (FROM:/TO: format)
If no delta specs found, inform user and stop.
4. **For each delta spec, apply changes to main specs**
Before the first main-spec write, obtain one current specs-rule snapshot:
- If archive invoked this workflow inline and supplied a valid snapshot from
`openspec instructions specs --change "<name>" --json --store wealth-ledger-specs`, reuse it and do not
fetch the same instructions again.
- Otherwise run that command once now with the same selected-root flags.
- If the direct lookup exits non-zero or returns invalid artifact-instruction
JSON, report the error and stop before writing any main spec. Do not treat the
failure as an absent rule set.
- A valid response with omitted `rules` means no artifact rules are configured
and the existing semantic merge continues.
Apply returned `rules` only to the content and form of the main specs produced
by this merge. Artifact rules are not operation guidance and cannot change
selected roots, delta paths, CLI checks, or workflow steps. Use their text as
constraints without copying it verbatim into a main spec or summary.
For each capability delta spec path selected in step 3 — the full `existingOutputPaths` list, or the narrowed subset when a caller supplied one (these may belong to a selected store, not the repo):
a. **Read the delta spec** to understand the intended changes
b. **Read the main spec** at `<planningHome.root>/openspec/specs/<capability-path>/spec.md` (may not exist yet)
c. **Apply changes intelligently**:
**ADDED Requirements:**
- If requirement doesn't exist in main spec → add it
- If requirement already exists → update it to match (treat as implicit MODIFIED)
**MODIFIED Requirements:**
- Find the requirement in main spec
- Apply the changes - this can be:
- Adding new scenarios the main spec does not have yet
- Modifying existing scenarios
- Changing the requirement description
- Preserve scenarios/content not mentioned in the delta
**REMOVED Requirements:**
- Remove the entire requirement block from main spec
- Retiring the capability. Delete the whole `spec.md` - and the directory once
nothing else is left in it - only when ALL of these hold:
1. removing the requirements *this run* left no requirement blocks;
2. the rest of the spec is well-formed (it still has a `## Purpose`);
3. the main spec was not already empty before this sync - if you removed
nothing, change nothing;
4. every other nonblank line in the whole file is accounted for as the
title, Purpose, Requirements header, or a canonical requirement's
statement, scenarios, or fenced examples;
5. the change's `.openspec.yaml` declares `retire_capabilities: true`;
6. the `spec.md` resolves inside the real specs root (do not follow a
capability-directory symlink to delete an external file).
If removing the selected requirements would leave no requirement blocks and
any retirement condition is not satisfied, do not modify the main spec. Stop
the sync for that capability, report the blocking condition, and tell the user
how to resolve it. Never write or leave an empty `## Requirements` section.
When only the marker is missing, say that too - it is the one thing the user
can add to make the retirement go through.
- Deleting the file also deletes its `## Purpose`; any other section blocks
retirement. Name Purpose when you report the retirement. Include a pasteable
`git checkout` only when the spec lived in the caller's checkout;
otherwise give checkout-scoped recovery guidance.
**RENAMED Requirements:**
- Find the FROM requirement, rename to TO
**`## Purpose` in the delta:**
- The main spec already has one and it is authoritative - leave it alone
(this is what `openspec archive --store wealth-ledger-specs` does; it warns and moves on)
d. **Create new main spec** if capability doesn't exist yet:
- Create `<planningHome.root>/openspec/specs/<capability-path>/spec.md`
- Add Purpose section: copy the delta's `## Purpose` body verbatim when it has one
(this is what `openspec archive --store wealth-ledger-specs` does); only write a brief TBD placeholder when it does not
- Add Requirements section with the ADDED requirements
- Follow the **Main Spec Format Reference** below
5. **Validate updated main specs**
Run `openspec validate --specs --store wealth-ledger-specs` with the same selected-root flags used earlier.
If validation fails, report the problems and do not claim the sync succeeded.
6. **Show summary**
After applying all changes, summarize:
- Which capabilities were updated
- What changes were made (requirements added/modified/removed/renamed)
- Any new main spec left with a TBD Purpose placeholder, so it gets written
now rather than lingering
- Any capability retired, naming the deleted `spec.md`, its Purpose, and
either a pasteable `git checkout` or checkout-scoped recovery guidance
**Delta Spec Format Reference**
```markdown
## Purpose
Only on a delta that introduces a brand-new capability. Seeds the new main spec.
## ADDED Requirements
### Requirement: New Feature
The system SHALL do something new.
#### Scenario: Basic case
- **WHEN** user does X
- **THEN** system does Y
## MODIFIED Requirements
### Requirement: Existing Feature
The system SHALL keep doing the existing thing, now also handling A.
#### Scenario: Scenario the main spec already has
- **WHEN** user does X
- **THEN** system does Y
#### Scenario: New scenario to add
- **WHEN** user does A
- **THEN** system does B
## REMOVED Requirements
### Requirement: Deprecated Feature
## RENAMED Requirements
- FROM: `### Requirement: Old Name`
- TO: `### Requirement: New Name`
```
**Main Spec Format Reference**
Main specs are what the delta merges INTO. They must never contain delta operation headers (`## ADDED/MODIFIED/REMOVED/RENAMED Requirements`) - after syncing, every requirement lives under a single `## Requirements` section:
```markdown
# <capability> Specification
## Purpose
Short description of what this capability does and why it exists.
## Requirements
### Requirement: New Feature
The system SHALL do something new.
#### Scenario: Basic case
- **WHEN** user does X
- **THEN** system does Y
```
**Key Principle: Intelligent Merging**
Unlike programmatic merging, you merge rather than overwrite:
- A MODIFIED block carries the whole requirement - body plus every scenario that survives the change. `openspec validate --store wealth-ledger-specs` and `openspec archive --store wealth-ledger-specs` both reject one that drops a scenario the main spec still has.
- Keep anything the delta does not mention, in the main spec's existing order
- Use your judgment to merge changes sensibly
**Output On Success**
```markdown
## Specs Synced: <change-name>
Updated main specs:
**<capability-1>**:
- Added requirement: "New Feature"
- Modified requirement: "Existing Feature" (added 1 scenario)
**<capability-2>**:
- Created new spec file
- Added requirement: "Another Feature"
Main specs are now updated. The change remains active - archive when implementation is complete.
```
**Guardrails**
- Read both delta and main specs before making changes
- Preserve existing content not mentioned in delta
- Never copy a delta file into a main spec as-is - merge its content so the main spec keeps the Main Spec Format Reference structure, with no delta operation headers
- If something is unclear, ask for clarification
- Show what you're changing as you go
- The operation should be idempotent - running twice should give same result
- Use only `artifactPaths.specs.existingOutputPaths`; never infer delta specs from unrelated artifacts
- Honor a caller-supplied subset of `existingOutputPaths`; never widen it back to the full list
- Fetch specs instructions once for direct sync, or reuse the archive-supplied snapshot inline
- Stop before every main-spec write on a non-zero or invalid JSON specs-instruction response
- Artifact rules constrain only the specs being written and are never copied into output files
@@ -0,0 +1,185 @@
---
description: "Verify implementation matches change artifacts before archiving"
---
Verify that an implementation matches the change artifacts (specs, tasks, design).
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Planning gate:** Before delivery verification run `bash specs/scripts/verify-openspec-planning.sh "<name>"`. The workspace verifier repeats this gate before affected-area checks. Structural success does not replace semantic verification or independent read-only review.
**Input**: Optionally specify a change name after `/opsx-verify` (e.g., `/opsx-verify add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes and ask the user to select one
When prompting, show changes that have implementation tasks (tasks artifact exists).
Include the schema used for each change if available.
Mark changes with incomplete tasks as "(In Progress)".
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-verify <other>`).
2. **Check status to understand the schema**
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Parse the JSON to understand:
- `schemaName`: The workflow being used (e.g., "spec-driven")
- `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context
- Which artifacts exist for this change
3. **Get planning context and load artifacts**
```bash
openspec instructions apply --change "<name>" --json --store wealth-ledger-specs
```
This returns the change directory and `contextFiles` (artifact ID -> array of concrete file paths). Read all available artifacts from `contextFiles`.
Read the Design Delivery Map and account for frontend, backend, specs and
docs. Run the workspace verifier from the workspace root:
```bash
bash specs/scripts/verify-workspace-change.sh "<name>"
```
A missing decision or failed canonical gate for any affected delivery area
is CRITICAL. The semantic report does not replace independent review:
require evidence of a completed independent read-only review and report its
absence or any unresolved Critical/Important finding as CRITICAL.
4. **Initialize verification report structure**
Create a report structure with three dimensions:
- **Completeness**: Track tasks and spec coverage
- **Correctness**: Track requirement implementation and scenario coverage
- **Coherence**: Track design adherence and pattern consistency
Each dimension can have CRITICAL, WARNING, or SUGGESTION issues.
5. **Verify Completeness**
**Task Completion**:
- If `contextFiles.tasks` exists, read every file path in it
- Parse checkboxes: `- [ ]` (incomplete) vs `- [x]` (complete)
- Count complete vs total tasks
- If incomplete tasks exist:
- Add CRITICAL issue for each incomplete task
- Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
**Spec Coverage**:
- If delta specs exist in `contextFiles.specs`:
- Extract all requirements (marked with "### Requirement:")
- For each requirement:
- Search codebase for keywords related to the requirement
- Assess if implementation likely exists
- If requirements appear unimplemented:
- Add CRITICAL issue: "Requirement not found: <requirement name>"
- Recommendation: "Implement requirement X: <description>"
6. **Verify Correctness**
**Requirement Implementation Mapping**:
- For each requirement from delta specs:
- Search codebase for implementation evidence
- If found, note file paths and line ranges
- Assess if implementation matches requirement intent
- If divergence detected:
- Add WARNING: "Implementation may diverge from spec: <details>"
- Recommendation: "Review <file>:<lines> against requirement X"
**Scenario Coverage**:
- For each scenario in delta specs (marked with "#### Scenario:"):
- Check if conditions are handled in code
- Check if tests exist covering the scenario
- If scenario appears uncovered:
- Add WARNING: "Scenario not covered: <scenario name>"
- Recommendation: "Add test or implementation for scenario: <description>"
7. **Verify Coherence**
**Design Adherence**:
- If `contextFiles.design` exists:
- Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
- Verify implementation follows those decisions
- If contradiction detected:
- Add WARNING: "Design decision not followed: <decision>"
- Recommendation: "Update implementation or revise design.md to match reality"
- If no design.md: Skip design adherence check, note "No design.md to verify against"
**Code Pattern Consistency**:
- Review new code for consistency with project patterns
- Check file naming, directory structure, coding style
- If significant deviations found:
- Add SUGGESTION: "Code pattern deviation: <details>"
- Recommendation: "Consider following project pattern: <example>"
8. **Generate Verification Report**
**Summary Scorecard**:
```markdown
## Verification Report: <change-name>
### Summary
| Dimension | Status |
|--------------|------------------|
| Completeness | X/Y tasks, N reqs|
| Correctness | M/N reqs covered |
| Coherence | Followed/Issues |
```
**Issues by Priority**:
1. **CRITICAL** (Must fix before archive):
- Incomplete tasks
- Missing requirement implementations
- Missing or failed affected delivery area gate
- Missing independent read-only review
- Each with specific, actionable recommendation
2. **WARNING** (Should fix):
- Spec/design divergences
- Missing scenario coverage
- Each with specific recommendation
3. **SUGGESTION** (Nice to fix):
- Pattern inconsistencies
- Minor improvements
- Each with specific recommendation
**Final Assessment**:
- If CRITICAL issues: "X critical issue(s) found. Fix before archiving."
- If only warnings: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
- If all clear: "All checks passed. Ready for archive."
**Verification Heuristics**
- **Completeness**: Focus on objective checklist items (checkboxes, requirements list)
- **Correctness**: Use keyword search, file path analysis, reasonable inference - don't require perfect certainty
- **Coherence**: Look for glaring inconsistencies, don't nitpick style
- **False Positives**: When uncertain, prefer SUGGESTION over WARNING, WARNING over CRITICAL
- **Actionability**: Every issue must have a specific recommendation with file/line references where applicable
**Graceful Degradation**
- If only tasks.md exists: verify task completion only, skip spec/design checks
- If tasks + specs exist: verify completeness and correctness, skip design
- If full artifacts: verify all three dimensions
- Always note which checks were skipped and why
**Output Format**
Use clear markdown with:
- Table for summary scorecard
- Grouped lists for issues (CRITICAL/WARNING/SUGGESTION)
- Code references in format: `file.ts:123`
- Specific, actionable recommendations
- No vague suggestions like "consider reviewing"
@@ -0,0 +1,194 @@
---
name: openspec-apply-change
description: Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
generatedBy: "1.10.0"
---
Implement tasks from an OpenSpec change.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Apply is allowed only after explicit Change Owner approval of Proposal, Delta Specs, Design and Tasks in sequence. CLI status and file existence prove structure, not approval. Establish approvals from the conversation; if evidence is unavailable, ask again and stop. If any approved upstream artifact changed after downstream approval, invalidate dependent approvals and return to planning before implementation.
**Planning gate and feedback:** Before implementation run `bash specs/scripts/verify-openspec-planning.sh "<name>"`. A structural failure blocks Apply. During Apply route intent/scope to Proposal, observable behavior to Delta Specs, architecture/rollback to Design, and decomposition/ownership/coverage to Tasks; stop downstream work and invalidate dependent approvals. A format-only correction may be fixed and revalidated without reapproval only when it changes none of those semantics.
**Input**: Optionally specify a change name (e.g., `/opsx-apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes and ask the user to select one
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-apply <other>`).
2. **Check status to understand the schema**
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Parse the JSON to understand:
- `schemaName`: The workflow being used (e.g., "spec-driven")
- `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints
- Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
3. **Get apply instructions**
```bash
openspec instructions apply --change "<name>" --json --store wealth-ledger-specs
```
This returns:
- `contextFiles`: artifact ID -> array of concrete file paths (varies by schema - could be proposal/specs/design/tasks or spec/tests/implementation/docs)
- Progress (total, complete, remaining)
- Task list with status
- Dynamic instruction based on current state
- Optional `context`: current required project instruction input from the selected root
- Optional `operationGuidance`: current advisory guidance for apply
**Handle states:**
- If `state: "blocked"` (missing artifacts): show message, suggest using `/opsx-continue` (if it is not installed, run `openspec status --change "<name>" --json --store wealth-ledger-specs` to see the next artifact and `openspec instructions <artifact-id> --change "<name>" --json --store wealth-ledger-specs` for how to create it)
- If `state: "all_done"`: congratulate, suggest archive
- Otherwise: proceed to implementation
Treat `context` as a required prompt-level input. Read and consider it, and
apply relevant project facts, conventions, and constraints while implementing.
Treat `operationGuidance` as optional additive advice. Read and consider every
entry, and follow entries that are applicable and compatible with the built-in
workflow.
Keep both fields separate from CLI-returned state, missing artifacts, tasks,
progress, `contextFiles`, and the built-in `instruction`. They are not
evidence of task completion, do not replace the built-in instruction, and do
not permit bypassing a blocked state. If context conflicts with the built-in
instruction, an explicit user choice, or a CLI-controlled value, report the
conflict and preserve the controlling value. If guidance is inapplicable or
conflicts with those controlling inputs, do not follow it and explain why.
These are prompt-level behavior contracts, not enforceable checks.
4. **Read context files**
Read every file path listed under `contextFiles` from the apply instructions output.
The files depend on the schema being used:
- **spec-driven**: proposal, specs, design, tasks
- Other schemas: follow the contextFiles from CLI output
Do not copy `context` or `operationGuidance` verbatim into implementation
files or planning artifacts unless the user separately asks for that content.
5. **Show current progress**
Display:
- Schema being used
- Progress: "N/M tasks complete"
- Remaining tasks overview
- Dynamic instruction from CLI
6. **Implement tasks (loop until done or blocked)**
For each pending task:
- Show which task is being worked on
- Make the code changes required
- Keep changes minimal and focused
- Mark task complete in the tasks file: `- [ ]` → `- [x]`
- Continue to next task
**Pause if:**
- Task is unclear → ask for clarification
- Implementation reveals a design issue → suggest updating artifacts
- A task needs work beyond what the spec and tasks describe, or you are tempted to drop, narrow, defer, or accept exceptions to specified behavior to make it fit → surface the added scope and ask; do not absorb it silently
- Error or blocker encountered → report and wait for guidance
- User interrupts
7. **On completion or pause, show status**
Display:
- Tasks completed this session
- Overall progress: "N/M tasks complete"
- If all done: suggest archive
- If paused: explain why and wait for guidance
**Output During Implementation**
```
## Implementing: <change-name> (schema: <schema-name>)
Working on task 3/7: <task description>
[...implementation happening...]
✓ Task complete
Working on task 4/7: <task description>
[...implementation happening...]
✓ Task complete
```
**Output On Completion**
```
## Implementation Complete
**Change:** <change-name>
**Schema:** <schema-name>
**Progress:** 7/7 tasks complete ✓
### Completed This Session
- [x] Task 1
- [x] Task 2
...
All tasks complete! You can archive this change with `/opsx-archive`.
```
**Output On Pause (Issue Encountered)**
```
## Implementation Paused
**Change:** <change-name>
**Schema:** <schema-name>
**Progress:** 4/7 tasks complete
### Issue Encountered
<description of the issue>
**Options:**
1. <option 1>
2. <option 2>
3. Other approach
What would you like to do?
```
**Guardrails**
- Keep going through tasks until done or blocked
- Always read context files before starting (from the apply instructions output)
- If task is ambiguous, pause and ask before implementing
- If implementation reveals issues, pause and suggest artifact updates
- Keep code changes minimal and scoped to each task
- Update task checkbox immediately after completing each task
- Pause on errors, blockers, or unclear requirements - don't guess
- When a task needs work beyond what the spec describes, surface the added scope and pause - never silently narrow, defer, or simplify away specified behavior
- Only mark a task `- [x]` when its specified behavior is fully implemented, not when it is partially done or deferred
- Use contextFiles from CLI output, don't assume specific file names
- Do not use context or operation guidance as proof that a task is complete
- Apply relevant project context; report conflicts with controlling workflow inputs
- Consider every guidance entry; explain any inapplicable or conflicting advice
- Do not copy runtime context or operation guidance into implementation files or planning artifacts
- Preserve CLI-controlled blocked/ready/all-done behavior and completion criteria
**Fluid Workflow Integration**
This skill supports the "actions on a change" model:
- **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly
@@ -0,0 +1,201 @@
---
name: openspec-archive-change
description: Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
generatedBy: "1.10.0"
---
Archive a completed change in the experimental workflow.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Archive requires explicit Change Owner approval of Proposal, Delta Specs, Design and Tasks in sequence. File/status existence is not approval. If approval evidence is unavailable, or an upstream artifact changed, invalidate dependent approvals and require cascading reapproval; stop without offering an override.
**Planning gate:** Before any archive mutation run `bash specs/scripts/verify-openspec-planning.sh "<name>"`; the full workspace dispatcher repeats it. A failure blocks archive without override, and structural success cannot replace semantic verification or independent read-only review.
`<capability-path>` is the spec directory relative to `specs/` (for example, `user-auth` or `identity/user-auth`). Preserve the full path from each delta spec when resolving its main spec.
**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes and ask the user to select one
When prompting, show only active changes (not already archived).
Include the schema used for each change if available.
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-archive <other>`).
**Load current archive inputs before the existing archive checks:**
After resolving the selected change and planning root, run:
```bash
openspec instructions archive --change "<name>" --json --store wealth-ledger-specs
```
Keep the same selected-root flags on this command. This lookup is advisory and
optional: it only supplies extra prompt inputs, so it must never block archiving.
If it exits non-zero or returns invalid JSON — for example on an older CLI that
does not support this command yet — continue the archive workflow with no
context and no operation guidance. Do not report an error and do not stop.
A successful response may omit both optional fields. Treat `context` as a
required prompt-level input: read and consider it, and apply relevant project
facts, conventions, and constraints. Treat `operationGuidance` as optional
additive advice: read and consider every entry, and follow entries that are
applicable and compatible with the built-in archive workflow.
Keep both fields separate from built-in steps, explicit user choices, resolved
paths, CLI checks, and command contracts. If context conflicts with one of those
controlling inputs, report the conflict and preserve the controlling value. If
guidance is inapplicable or conflicts with a controlling input, do not follow it
and explain why. Do not infer replacement paths, skipped prompts, or flags from
either field, and do not copy their text verbatim into specs, change artifacts,
or archive summaries unless the user separately asks for it. These are
prompt-level behavior contracts, not enforceable checks.
2. **Check artifact completion status**
Run `openspec status --change "<name>" --json --store wealth-ledger-specs` to check artifact completion.
Parse the JSON to understand:
- `schemaName`: The workflow being used
- `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context
- `artifacts`: List of artifacts with their status (`done`, `skipped`, or other)
**If any artifacts are neither `done` nor `skipped`** (skipped artifacts satisfy the requirement - the change declares skip_specs):
- Stop without syncing or archiving.
- Report the incomplete artifacts as blocking conditions.
- Do not ask for or accept a confirmation override.
3. **Check task completion status**
Read the tasks file (typically `tasks.md`) to check for incomplete tasks.
Count tasks marked with `- [ ]` (incomplete) vs `- [x]` (complete).
**If incomplete tasks found:**
- Stop without syncing or archiving.
- Report the incomplete tasks as blocking conditions.
- Do not ask for or accept a confirmation override.
**If no tasks file exists:** Stop without syncing or archiving. Report the missing `tasks.md` as a blocking condition.
**WealthLedger pre-archive gates:**
- Run `bash specs/scripts/verify-workspace-change.sh "<name>"` from the workspace root and require a successful result for every affected delivery area.
- Require successful semantic verification against Proposal, Delta Specs, Design and Tasks.
- Require a completed independent read-only review with no unresolved Critical or Important finding.
- Stop if any gate or evidence is missing or unsuccessful. Do not ask for or accept a confirmation override.
4. **Assess delta spec sync state**
Use `artifactPaths.specs.existingOutputPaths` from status JSON as the only
delta-spec source. If the `specs` entry is missing or
`existingOutputPaths` is empty, proceed without a sync prompt and do not infer
delta specs from other artifacts.
**If delta specs exist:**
- Compare each delta spec with its corresponding main spec at `<planningHome.root>/openspec/specs/<capability-path>/spec.md` (use the store-aware `planningHome.root` from step 2, not a hardcoded repo path)
- Determine what changes would be applied (adds, modifications, removals, renames)
- Show a combined summary before prompting
**Prompt options:**
- If changes needed: "Sync now (recommended)", "Archive without syncing"
- If already synced: "Archive now", "Sync anyway", "Cancel"
Route on the answer:
- "Cancel" — stop, do not archive
- "Archive without syncing" or "Archive now" — proceed to archive
- "Sync now" or "Sync anyway" — sync, then verify (below)
- Anything else — ask again rather than archiving
Before a selected sync writes any main spec, run
`openspec instructions specs --change "<name>" --json --store wealth-ledger-specs` once with the same
selected-root flags. Require a zero exit status and valid artifact-instruction
JSON. If the lookup fails or returns invalid JSON, report the error and stop
before writing any main spec or moving the change. A valid response with omitted
`rules` is the no-rules case. Apply returned `rules` only to the content and
form of main specs produced by this merge; do not use them as archive guidance,
change CLI behavior, or copy the rule text into any output file.
Then run the `openspec-sync-specs` workflow inline (agent-driven intelligent merge) for change '<name>', passing the delta spec analysis and the fetched specs-rule snapshot from above, and wait for it to finish. The inline sync must reuse that snapshot without fetching `specs` instructions again. Do not delegate it to a background task — step 5 would move `changeRoot` out from under a sync that is still reading it, leaving the change archived and the main specs never updated. If your agent can only run it by delegation, delegate synchronously and wait for the result.
Then re-run the comparison from the top of this step against every capability that has a delta spec in `artifactPaths.specs.existingOutputPaths` — not only the ones the sync reports it touched. A successful sync leaves nothing left to apply, so each capability must now read as already synced:
- ADDED requirements present
- MODIFIED requirements carrying the scenario and description changes named in the delta, with their other scenarios intact
- REMOVED requirements gone — and where this sync retired a capability (removed its last requirement, leaving `## Requirements` empty), its main spec deleted rather than left empty; a spec the sync deliberately kept and reported is also a match
- RENAMED requirements present under the new name and absent under the old one
If the sync failed, or any capability does not match, report what differs and stop — do not archive. Nothing has moved and `changeRoot` is intact, so the user can fix the mismatch or re-run the sync and start the archive again.
5. **Perform the archive**
Create an `archive` directory under `planningHome.changesDir` if it doesn't exist:
```bash
mkdir -p "<planningHome.changesDir>/archive"
```
Generate the target name: use the change name as-is when it already starts with a `YYYY-MM-DD-` prefix; otherwise prepend the current date as `YYYY-MM-DD-<change-name>`. Never stack a second date (same rule as `openspec archive --store wealth-ledger-specs`).
**Check if target already exists:**
- If yes: Fail with error, suggest renaming existing archive or using different date
- If no: Move `changeRoot` to the archive directory
```bash
mv "<changeRoot>" "<planningHome.changesDir>/archive/<target-name>"
```
6. **Display summary**
Show archive completion summary including:
- Change name
- Schema that was used
- Archive location
- Whether specs were synced (if applicable)
- Confirmation that all planning artifacts and tasks were complete before archive
After the move succeeds, use a deterministic two-phase evidence protocol:
- First commit the delivered changes in each affected repository, including the synced/archive state in `specs` and any as-built documentation in `docs`, and collect their actual commit IDs.
- Then write Completion Evidence in the durable registry/history with the archive path, Delivery Map, those delivery commit IDs, exact verification commands, observed results and independent review verdict.
- Commit Completion Evidence as a final follow-up in `docs`. The evidence cites the preceding docs delivery commit when docs was affected; when docs was `N/A`, it preserves that reason and does not invent an implementation commit. Its own follow-up commit cannot self-reference and is reported in the archive summary instead of repeatedly rewriting the record.
Do not add these post-archive actions as unchecked tasks in the archived change and do not claim terminal `done` before the evidence follow-up commit succeeds.
**Output On Success**
```markdown
## Archive Complete
**Change:** <change-name>
**Schema:** <schema-name>
**Archived to:** the archive path derived from `planningHome.changesDir`/<target-name>/
**Specs:** <"✓ Synced to main specs" only if the step 4 verification passed; otherwise "No delta specs" or "Sync skipped">
All artifacts complete. All tasks complete.
```
**Guardrails**
- Announce the selected change; prompt for selection when it is ambiguous
- Use artifact graph (`openspec status --json --store wealth-ledger-specs`) for completion checking
- Treat incomplete artifacts, a missing `tasks.md`, incomplete tasks, an affected delivery area failure, missing semantic verification and missing independent read-only review as hard blockers; never offer an override
- Preserve .openspec.yaml when moving to archive (it moves with the directory)
- Show clear summary of what happened
- If sync is requested, run the `openspec-sync-specs` workflow inline (agent-driven)
- Never archive while a spec sync is still in flight — run the sync inline and verify the main specs before moving `changeRoot`
- If delta specs exist, always run the sync assessment and show the combined summary before prompting
- Apply relevant runtime context and report conflicts; operation guidance remains advisory
- Consider every guidance entry and explain any inapplicable or conflicting advice
- Existing CLI checks, resolved paths, prompts, and command contracts are unchanged
- Artifact rules constrain only the specs being written and are never operation guidance
- Never copy runtime context, operation guidance, or artifact-rule text verbatim into output files
@@ -0,0 +1,124 @@
---
name: openspec-continue-change
description: Continue working on an OpenSpec change by creating the next artifact. Use when the user wants to progress their change, create the next artifact, or continue their workflow.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
generatedBy: "1.10.0"
---
Continue working on a change by creating the next artifact.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Create at most ONE planning artifact per invocation, then STOP for explicit Change Owner approval. Before creating a downstream artifact, establish from the conversation that every completed dependency was explicitly approved; file/status existence is not approval. If approval cannot be established, ask again and stop. If an approved upstream artifact changed, invalidate dependent approvals and return to that artifact instead of continuing downstream.
**Planning gate:** After writing or editing the one artifact and before requesting approval, run `bash specs/scripts/verify-openspec-planning.sh "<name>"`. Fix structural failures and rerun the available stage checks. Structural success does not grant approval; a semantic mismatch returns to the earliest affected artifact and invalidates dependent approvals.
**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes sorted by most recently modified, and ask the user to select one
When prompting, present the top 3-4 most recently modified changes as options, showing:
- Change name
- Schema (from `schema` field if present, otherwise "spec-driven")
- Status (e.g., "0/5 tasks", "complete", "no tasks")
- How recently it was modified (from `lastModified` field)
Mark the most recently modified change as "(Recommended)" since it's likely what the user wants to continue.
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-continue <other>`).
2. **Check current status**
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Parse the JSON to understand current state. The response includes:
- `schemaName`: The workflow schema being used (e.g., "spec-driven")
- `artifacts`: Array of artifacts with their status ("done", "skipped", "ready", "blocked")
- `isPlanningComplete`: Boolean indicating if all planning artifacts are complete. Older CLI versions expose the same value as `isComplete`.
- `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context. Use these instead of assuming repo-local paths.
3. **Act based on status**:
---
**If all planning artifacts are complete (`isPlanningComplete: true`, or legacy `isComplete: true`)**:
- Congratulate the user
- Show final status including the schema used
- Suggest: "Planning is complete! You can now implement this change. Once implementation and any tracked work are complete, archive it."
- STOP
---
**If artifacts are ready to create** (status shows artifacts with `status: "ready"`):
- Pick the FIRST artifact with `status: "ready"` from the status output
- Get its instructions:
```bash
openspec instructions <artifact-id> --change "<name>" --json --store wealth-ledger-specs
```
- Parse the JSON. The key fields are:
- `context`: Project background (constraints for you - do NOT include in output)
- `rules`: Artifact-specific rules (constraints for you - do NOT include in output)
- `template`: The structure to use for your output file
- `instruction`: Schema-specific guidance
- `resolvedOutputPath`: Resolved path or pattern to write the artifact
- `dependencies`: Completed artifacts to read for context (entries with `skipped: true` have no files - do not look for them)
- `skipped`/`warning`: present when the change declares skip_specs and this artifact must NOT be created - pick another artifact
- **Create the artifact file**:
- Read any completed dependency files for context - always re-read them from disk, even if you saw them earlier in the conversation (the user may have edited them)
- If the `instruction` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at `resolvedOutputPath`
- Otherwise use `template` as the structure - fill in its sections
- Apply `context` and `rules` as constraints when writing - but do NOT copy them into the file
- Write to the `resolvedOutputPath` specified in instructions. If it is a glob pattern, choose the concrete file path using the schema instruction and the change's context
- Show what was created and what's now unlocked
- STOP after creating ONE artifact
---
**If no artifacts are ready (all blocked)**:
- This shouldn't happen with a valid schema
- Show status and suggest checking for issues
4. **After creating an artifact, show progress**
```bash
openspec status --change "<name>" --store wealth-ledger-specs
```
**Output**
After each invocation, show:
- Which artifact was created
- Schema workflow being used
- Current progress (N/M complete)
- What artifacts are now unlocked
- Prompt: "Want to continue? Just ask me to continue or tell me what to do next."
**Artifact Creation Guidelines**
The artifact types and their purpose depend on the schema. The `instruction` field from the instructions output is the authoritative guidance for each artifact - follow it even when the artifact has a familiar name (proposal.md, tasks.md, etc.), since custom schemas may define different content or a different process for the same file names.
If the `instruction` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly.
**Guardrails**
- Create ONE artifact per invocation
- Always read dependency artifacts before creating a new one - re-read from disk, not from conversation memory (files may have changed since you last saw them)
- Never skip artifacts or create out of order
- If context is unclear, ask the user before creating
- Verify the artifact file exists after writing before marking progress
- Use the schema's artifact sequence, don't assume specific artifact names
- **IMPORTANT**: `context` and `rules` are constraints for YOU, not content for the file
- Do NOT copy `<context>`, `<rules>`, `<project_context>` blocks into the artifact
- These guide what you write, but should never appear in the output
@@ -0,0 +1,39 @@
---
name: openspec-explore
description: Explore ideas without implementing or bypassing WealthLedger SDD approvals.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
generatedBy: "1.10.0"
---
Explore the actual codebase, clarify intent, compare mature solutions, surface risks and visualize trade-offs. Do not implement or modify application code.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Exploration does not approve artifacts. If the user explicitly asks to capture a decision, create at most ONE planning artifact per invocation and then STOP for explicit Change Owner approval. File/status existence is not approval.
**Planning gate:** When exploration captures an artifact, run `bash specs/scripts/verify-openspec-planning.sh "<name>"` after the write and before requesting approval. Fix structural failures; if the captured decision changes upstream semantics, return to the earliest affected artifact and invalidate dependent approvals.
## Workflow
- Discover with `openspec list --json --store wealth-ledger-specs`; resolve an existing change with `openspec status --change "<name>" --json --store wealth-ledger-specs` and read its returned artifact paths.
- Read relevant code and durable documentation. Ask only material questions. Compare mature supported solutions before custom auth, security, storage, integrations, observability, caching, concurrency, infrastructure or tooling.
- Offer to capture a stable decision in the current artifact; do not auto-capture it.
- When explicitly requested, scaffold a new change with `openspec new change "<name>" --store wealth-ledger-specs` or read existing status. Confirm dependency approvals from the conversation. The selected artifact must be the first `ready` one.
- Run `openspec instructions "<artifact-id>" --change "<name>" --json --store wealth-ledger-specs`, read completed dependencies, follow its template/instruction and create or update only that artifact at `resolvedOutputPath`.
- Show fresh status and stop for owner approval before downstream work.
If an approved upstream artifact changes, state which downstream approvals are invalidated and stop without regenerating them.
## Guardrails
- Never write implementation code in explore mode.
- Create at most ONE planning artifact per invocation.
- Never create an unapproved prerequisite or downstream artifact because status reports it ready.
- Keep versioned planning documents only in `specs/openspec`.
@@ -0,0 +1,79 @@
---
name: openspec-new-change
description: Start a new OpenSpec change using the experimental artifact workflow. Use when the user wants to create a new feature, fix, or modification with a structured step-by-step approach.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
generatedBy: "1.10.0"
---
Start a new change using the experimental artifact-driven approach.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build.
**Steps**
1. **If no clear input provided, ask what they want to build**
Ask the user (open-ended, no preset options):
> "What change do you want to work on? Describe what you want to build or fix."
From their description, derive a kebab-case name (e.g., "add user authentication" → `add-user-auth`).
**IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
2. **Determine the workflow schema**
Use the default schema (omit `--schema`) unless the user explicitly requests a different workflow.
**Use a different schema only if the user mentions:**
- A specific schema name → use `--schema <name>`
- "show workflows" or "what workflows" → run `openspec schemas --json --store wealth-ledger-specs` and let them choose
**Otherwise**: Omit `--schema` to use the default.
3. **Create the change directory**
```bash
openspec new change "<name>" --store wealth-ledger-specs
```
Add `--schema <name>` only if the user requested a specific workflow.
This creates a scaffolded change in the planning home resolved by the CLI.
4. **Show the artifact status**
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Use the returned `planningHome`, `changeRoot`, `artifactPaths`, and `nextSteps` instead of assuming repo-local paths.
5. **Get instructions for the first artifact**
The first artifact depends on the schema (e.g., `proposal` for spec-driven).
Check the status output to find the first artifact with status "ready".
```bash
openspec instructions <first-artifact-id> --change "<name>" --store wealth-ledger-specs
```
This outputs the template and context for creating the first artifact.
6. **STOP and wait for user direction**
**Output**
After completing the steps, summarize:
- Change name and location
- Schema/workflow being used and its artifact sequence
- Current status (0/N artifacts complete)
- The template for the first artifact
- Prompt: "Ready to create the first artifact? Just describe what this change is about and I'll draft it, or ask me to continue."
**Guardrails**
- Do NOT create any artifacts yet - just show the instructions
- Do NOT advance beyond showing the first artifact template
- If the name is invalid (not kebab-case), ask for a valid name
- If a change with that name already exists, suggest continuing that change instead
- Pass --schema if using a non-default workflow
@@ -0,0 +1,38 @@
---
name: openspec-propose
description: Start a WealthLedger OpenSpec change and draft only its first planning artifact.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
generatedBy: "1.10.0"
---
Start a WealthLedger OpenSpec change and draft only its first currently ready planning artifact. This workflow authorizes planning only and never implementation.
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Approval boundary:** Create at most ONE planning artifact per invocation. After showing it, STOP for explicit Change Owner approval. File existence or OpenSpec `done` status is not approval. If approval of a dependency cannot be established from the current conversation, ask again before creating a downstream artifact.
**Planning gate:** After writing or editing the one artifact and before requesting approval, run `bash specs/scripts/verify-openspec-planning.sh "<name>"`. Fix structural failures and rerun the available stage checks. Structural success does not grant approval; a semantic mismatch returns to the earliest affected artifact and invalidates dependent approvals.
## Workflow
1. Resolve the requested intent and a kebab-case name; ask about ambiguity that changes scope, behavior, compatibility or acceptance criteria.
2. Use the configured default schema unless the user explicitly chooses another. Available schemas are read with `openspec schemas --json --store wealth-ledger-specs`.
3. Scaffold with `openspec new change "<name>" --store wealth-ledger-specs`; add `--schema "<schema-name>"` only after an explicit choice.
4. Run `openspec status --change "<name>" --json --store wealth-ledger-specs` and use its resolved paths.
5. For the first `ready` artifact run `openspec instructions "<artifact-id>" --change "<name>" --json --store wealth-ledger-specs`. Apply returned context, rules, template and instruction; create only that artifact at `resolvedOutputPath`.
6. Run `openspec status --change "<name>" --store wealth-ledger-specs`, show the draft and stop for approval before any `/opsx-continue`.
## Guardrails
- Never create a downstream artifact in the same invocation, even if status reports it ready.
- Never infer approval from file existence, CLI status, silence or the agent's own judgment.
- If an approved upstream artifact changes, report invalidated downstream approvals and stop without regenerating them.
- Do not edit application code or start Apply.
- If the change already exists, ask whether to continue it.
@@ -0,0 +1,264 @@
---
name: openspec-sync-specs
description: Sync delta specs from a change to main specs. Use when the user wants to update main specs with changes from a delta spec, without archiving the change.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
generatedBy: "1.10.0"
---
Sync delta specs from a change to main specs.
This is an **agent-driven** operation - you will read delta specs and directly edit main specs to apply the changes. This allows intelligent merging (e.g., adding a scenario without copying the entire requirement).
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
`<capability-path>` is the spec directory relative to `specs/` (for example, `user-auth` or `identity/user-auth`). Preserve the full path from each delta spec when resolving its main spec.
**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes and ask the user to select one
When prompting, show changes that have delta specs (under `specs/` directory).
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-sync <other>`).
2. **Resolve change context**
Run:
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
The JSON includes `planningHome.root`. Main specs live under `<planningHome.root>/openspec/specs/` — use that (store-aware) root for every main-spec path below, not a hardcoded repo path. When a store is selected it points at the store, not the current repository.
3. **Find delta specs**
Use `artifactPaths.specs.existingOutputPaths` from the status JSON as the
only source of delta spec paths. If the `specs` entry is missing or
`existingOutputPaths` is empty, report that there are no delta specs to sync,
do not infer them from other artifacts, and stop without requesting artifact
instructions or writing a main spec.
Sync every path in `existingOutputPaths` unless the caller narrowed the set.
A caller narrows it by naming an explicit list of complete entries from
`existingOutputPaths` — copy those absolute values verbatim. Archive does
this inline, and a user can too (for example, by selecting the entry ending
in `/specs/billing/invoices/spec.md`).
Then sync only the named paths and leave the remaining delta specs untouched:
bulk archive excludes a delta whose implementation it could not find, and
syncing it anyway would write a main spec the caller deliberately withheld.
Carry that narrowed selection through step 4; never widen it back to the full
list. If a named path is not in `existingOutputPaths`, do not sync it —
report it and stop, rather than dropping it silently. If the named list is
empty, report that there is nothing to sync and stop without writing a main
spec.
Each delta spec file contains sections like:
- `## ADDED Requirements` - New requirements to add
- `## MODIFIED Requirements` - Changes to existing requirements
- `## REMOVED Requirements` - Requirements to remove
- `## RENAMED Requirements` - Requirements to rename (FROM:/TO: format)
If no delta specs found, inform user and stop.
4. **For each delta spec, apply changes to main specs**
Before the first main-spec write, obtain one current specs-rule snapshot:
- If archive invoked this workflow inline and supplied a valid snapshot from
`openspec instructions specs --change "<name>" --json --store wealth-ledger-specs`, reuse it and do not
fetch the same instructions again.
- Otherwise run that command once now with the same selected-root flags.
- If the direct lookup exits non-zero or returns invalid artifact-instruction
JSON, report the error and stop before writing any main spec. Do not treat the
failure as an absent rule set.
- A valid response with omitted `rules` means no artifact rules are configured
and the existing semantic merge continues.
Apply returned `rules` only to the content and form of the main specs produced
by this merge. Artifact rules are not operation guidance and cannot change
selected roots, delta paths, CLI checks, or workflow steps. Use their text as
constraints without copying it verbatim into a main spec or summary.
For each capability delta spec path selected in step 3 — the full `existingOutputPaths` list, or the narrowed subset when a caller supplied one (these may belong to a selected store, not the repo):
a. **Read the delta spec** to understand the intended changes
b. **Read the main spec** at `<planningHome.root>/openspec/specs/<capability-path>/spec.md` (may not exist yet)
c. **Apply changes intelligently**:
**ADDED Requirements:**
- If requirement doesn't exist in main spec → add it
- If requirement already exists → update it to match (treat as implicit MODIFIED)
**MODIFIED Requirements:**
- Find the requirement in main spec
- Apply the changes - this can be:
- Adding new scenarios the main spec does not have yet
- Modifying existing scenarios
- Changing the requirement description
- Preserve scenarios/content not mentioned in the delta
**REMOVED Requirements:**
- Remove the entire requirement block from main spec
- Retiring the capability. Delete the whole `spec.md` - and the directory once
nothing else is left in it - only when ALL of these hold:
1. removing the requirements *this run* left no requirement blocks;
2. the rest of the spec is well-formed (it still has a `## Purpose`);
3. the main spec was not already empty before this sync - if you removed
nothing, change nothing;
4. every other nonblank line in the whole file is accounted for as the
title, Purpose, Requirements header, or a canonical requirement's
statement, scenarios, or fenced examples;
5. the change's `.openspec.yaml` declares `retire_capabilities: true`;
6. the `spec.md` resolves inside the real specs root (do not follow a
capability-directory symlink to delete an external file).
If removing the selected requirements would leave no requirement blocks and
any retirement condition is not satisfied, do not modify the main spec. Stop
the sync for that capability, report the blocking condition, and tell the user
how to resolve it. Never write or leave an empty `## Requirements` section.
When only the marker is missing, say that too - it is the one thing the user
can add to make the retirement go through.
- Deleting the file also deletes its `## Purpose`; any other section blocks
retirement. Name Purpose when you report the retirement. Include a pasteable
`git checkout` only when the spec lived in the caller's checkout;
otherwise give checkout-scoped recovery guidance.
**RENAMED Requirements:**
- Find the FROM requirement, rename to TO
**`## Purpose` in the delta:**
- The main spec already has one and it is authoritative - leave it alone
(this is what `openspec archive --store wealth-ledger-specs` does; it warns and moves on)
d. **Create new main spec** if capability doesn't exist yet:
- Create `<planningHome.root>/openspec/specs/<capability-path>/spec.md`
- Add Purpose section: copy the delta's `## Purpose` body verbatim when it has one
(this is what `openspec archive --store wealth-ledger-specs` does); only write a brief TBD placeholder when it does not
- Add Requirements section with the ADDED requirements
- Follow the **Main Spec Format Reference** below
5. **Validate updated main specs**
Run `openspec validate --specs --store wealth-ledger-specs` with the same selected-root flags used earlier.
If validation fails, report the problems and do not claim the sync succeeded.
6. **Show summary**
After applying all changes, summarize:
- Which capabilities were updated
- What changes were made (requirements added/modified/removed/renamed)
- Any new main spec left with a TBD Purpose placeholder, so it gets written
now rather than lingering
- Any capability retired, naming the deleted `spec.md`, its Purpose, and
either a pasteable `git checkout` or checkout-scoped recovery guidance
**Delta Spec Format Reference**
```markdown
## Purpose
Only on a delta that introduces a brand-new capability. Seeds the new main spec.
## ADDED Requirements
### Requirement: New Feature
The system SHALL do something new.
#### Scenario: Basic case
- **WHEN** user does X
- **THEN** system does Y
## MODIFIED Requirements
### Requirement: Existing Feature
The system SHALL keep doing the existing thing, now also handling A.
#### Scenario: Scenario the main spec already has
- **WHEN** user does X
- **THEN** system does Y
#### Scenario: New scenario to add
- **WHEN** user does A
- **THEN** system does B
## REMOVED Requirements
### Requirement: Deprecated Feature
## RENAMED Requirements
- FROM: `### Requirement: Old Name`
- TO: `### Requirement: New Name`
```
**Main Spec Format Reference**
Main specs are what the delta merges INTO. They must never contain delta operation headers (`## ADDED/MODIFIED/REMOVED/RENAMED Requirements`) - after syncing, every requirement lives under a single `## Requirements` section:
```markdown
# <capability> Specification
## Purpose
Short description of what this capability does and why it exists.
## Requirements
### Requirement: New Feature
The system SHALL do something new.
#### Scenario: Basic case
- **WHEN** user does X
- **THEN** system does Y
```
**Key Principle: Intelligent Merging**
Unlike programmatic merging, you merge rather than overwrite:
- A MODIFIED block carries the whole requirement - body plus every scenario that survives the change. `openspec validate --store wealth-ledger-specs` and `openspec archive --store wealth-ledger-specs` both reject one that drops a scenario the main spec still has.
- Keep anything the delta does not mention, in the main spec's existing order
- Use your judgment to merge changes sensibly
**Output On Success**
```markdown
## Specs Synced: <change-name>
Updated main specs:
**<capability-1>**:
- Added requirement: "New Feature"
- Modified requirement: "Existing Feature" (added 1 scenario)
**<capability-2>**:
- Created new spec file
- Added requirement: "Another Feature"
Main specs are now updated. The change remains active - archive when implementation is complete.
```
**Guardrails**
- Read both delta and main specs before making changes
- Preserve existing content not mentioned in delta
- Never copy a delta file into a main spec as-is - merge its content so the main spec keeps the Main Spec Format Reference structure, with no delta operation headers
- If something is unclear, ask for clarification
- Show what you're changing as you go
- The operation should be idempotent - running twice should give same result
- Use only `artifactPaths.specs.existingOutputPaths`; never infer delta specs from unrelated artifacts
- Honor a caller-supplied subset of `existingOutputPaths`; never widen it back to the full list
- Fetch specs instructions once for direct sync, or reuse the archive-supplied snapshot inline
- Stop before every main-spec write on a non-zero or invalid JSON specs-instruction response
- Artifact rules constrain only the specs being written and are never copied into output files
@@ -0,0 +1,193 @@
---
name: openspec-verify-change
description: Verify implementation matches change artifacts. Use when the user wants to validate that implementation is complete, correct, and coherent before archiving.
allowed-tools: Bash(openspec:*)
license: MIT
compatibility: Requires openspec CLI.
metadata:
author: openspec
version: "1.0"
generatedBy: "1.10.0"
---
Verify that an implementation matches the change artifacts (specs, tasks, design).
**OpenSpec store (WealthLedger):** Use only `wealth-ledger-specs`, whose physical root is `specs/openspec`. Every OpenSpec command that reads or writes specs or changes MUST include `--store wealth-ledger-specs`; keep this flag on every follow-up. Do not infer a store from cwd, the nearest root, or machine configuration.
**OpenSpec version preflight:** Before the first OpenSpec command, work from the workspace root and run `bash specs/scripts/verify-openspec-version.sh`. A missing or mismatched CLI is a blocking result.
**Planning gate:** Before delivery verification run `bash specs/scripts/verify-openspec-planning.sh "<name>"`. The workspace verifier repeats this gate before affected-area checks. Structural success does not replace semantic verification or independent read-only review.
**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
1. **Select the change**
If a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json --store wealth-ledger-specs` to get available changes and ask the user to select one
When prompting, show changes that have implementation tasks (tasks artifact exists).
Include the schema used for each change if available.
Mark changes with incomplete tasks as "(In Progress)".
Always announce: "Using change: <name>" and how to override (e.g., `/opsx-verify <other>`).
2. **Check status to understand the schema**
```bash
openspec status --change "<name>" --json --store wealth-ledger-specs
```
Parse the JSON to understand:
- `schemaName`: The workflow being used (e.g., "spec-driven")
- `planningHome`, `changeRoot`, `artifactPaths`, and `actionContext`: path and scope context
- Which artifacts exist for this change
3. **Get planning context and load artifacts**
```bash
openspec instructions apply --change "<name>" --json --store wealth-ledger-specs
```
This returns the change directory and `contextFiles` (artifact ID -> array of concrete file paths). Read all available artifacts from `contextFiles`.
Read the Design Delivery Map and account for frontend, backend, specs and
docs. Run the workspace verifier from the workspace root:
```bash
bash specs/scripts/verify-workspace-change.sh "<name>"
```
A missing decision or failed canonical gate for any affected delivery area
is CRITICAL. The semantic report does not replace independent review:
require evidence of a completed independent read-only review and report its
absence or any unresolved Critical/Important finding as CRITICAL.
4. **Initialize verification report structure**
Create a report structure with three dimensions:
- **Completeness**: Track tasks and spec coverage
- **Correctness**: Track requirement implementation and scenario coverage
- **Coherence**: Track design adherence and pattern consistency
Each dimension can have CRITICAL, WARNING, or SUGGESTION issues.
5. **Verify Completeness**
**Task Completion**:
- If `contextFiles.tasks` exists, read every file path in it
- Parse checkboxes: `- [ ]` (incomplete) vs `- [x]` (complete)
- Count complete vs total tasks
- If incomplete tasks exist:
- Add CRITICAL issue for each incomplete task
- Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
**Spec Coverage**:
- If delta specs exist in `contextFiles.specs`:
- Extract all requirements (marked with "### Requirement:")
- For each requirement:
- Search codebase for keywords related to the requirement
- Assess if implementation likely exists
- If requirements appear unimplemented:
- Add CRITICAL issue: "Requirement not found: <requirement name>"
- Recommendation: "Implement requirement X: <description>"
6. **Verify Correctness**
**Requirement Implementation Mapping**:
- For each requirement from delta specs:
- Search codebase for implementation evidence
- If found, note file paths and line ranges
- Assess if implementation matches requirement intent
- If divergence detected:
- Add WARNING: "Implementation may diverge from spec: <details>"
- Recommendation: "Review <file>:<lines> against requirement X"
**Scenario Coverage**:
- For each scenario in delta specs (marked with "#### Scenario:"):
- Check if conditions are handled in code
- Check if tests exist covering the scenario
- If scenario appears uncovered:
- Add WARNING: "Scenario not covered: <scenario name>"
- Recommendation: "Add test or implementation for scenario: <description>"
7. **Verify Coherence**
**Design Adherence**:
- If `contextFiles.design` exists:
- Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
- Verify implementation follows those decisions
- If contradiction detected:
- Add WARNING: "Design decision not followed: <decision>"
- Recommendation: "Update implementation or revise design.md to match reality"
- If no design.md: Skip design adherence check, note "No design.md to verify against"
**Code Pattern Consistency**:
- Review new code for consistency with project patterns
- Check file naming, directory structure, coding style
- If significant deviations found:
- Add SUGGESTION: "Code pattern deviation: <details>"
- Recommendation: "Consider following project pattern: <example>"
8. **Generate Verification Report**
**Summary Scorecard**:
```markdown
## Verification Report: <change-name>
### Summary
| Dimension | Status |
|--------------|------------------|
| Completeness | X/Y tasks, N reqs|
| Correctness | M/N reqs covered |
| Coherence | Followed/Issues |
```
**Issues by Priority**:
1. **CRITICAL** (Must fix before archive):
- Incomplete tasks
- Missing requirement implementations
- Missing or failed affected delivery area gate
- Missing independent read-only review
- Each with specific, actionable recommendation
2. **WARNING** (Should fix):
- Spec/design divergences
- Missing scenario coverage
- Each with specific recommendation
3. **SUGGESTION** (Nice to fix):
- Pattern inconsistencies
- Minor improvements
- Each with specific recommendation
**Final Assessment**:
- If CRITICAL issues: "X critical issue(s) found. Fix before archiving."
- If only warnings: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
- If all clear: "All checks passed. Ready for archive."
**Verification Heuristics**
- **Completeness**: Focus on objective checklist items (checkboxes, requirements list)
- **Correctness**: Use keyword search, file path analysis, reasonable inference - don't require perfect certainty
- **Coherence**: Look for glaring inconsistencies, don't nitpick style
- **False Positives**: When uncertain, prefer SUGGESTION over WARNING, WARNING over CRITICAL
- **Actionability**: Every issue must have a specific recommendation with file/line references where applicable
**Graceful Degradation**
- If only tasks.md exists: verify task completion only, skip spec/design checks
- If tasks + specs exist: verify completeness and correctness, skip design
- If full artifacts: verify all three dimensions
- Always note which checks were skipped and why
**Output Format**
Use clear markdown with:
- Table for summary scorecard
- Grouped lists for issues (CRITICAL/WARNING/SUGGESTION)
- Code references in format: `file.ts:123`
- Specific, actionable recommendations
- No vague suggestions like "consider reviewing"
@@ -0,0 +1,7 @@
schema: wealth-ledger-sdd
created: 2026-08-25
goal: Make WealthLedger SDD changes reliably traceable, reproducible, and
maintainable across future OpenSpec upgrades.
affected_areas:
- specs
- docs
@@ -0,0 +1,276 @@
## Context
WealthLedger использует project-local OpenSpec schema поверх CLI 1.10.0,
canonical store в отдельном specs-репозитории и project-owned OpenCode
entrypoints в unversioned workspace root. Schema уже задаёт последовательный
artifact graph, а repository scripts защищают store authority, Delivery Map и
terminal verification. Однако planning quality до Apply проверяется
неравномерно, Tasks не имеют машиночитаемой связи с requirements и delivery
areas, а root agent projection проверяется только как локально существующее
состояние и не восстанавливается из четырёх Git-репозиториев.
Custom schema API остаётся experimental, поэтому совместимость нельзя безопасно
выводить только из SemVer. Root workspace не является Git-репозиторием;
versioned authority для новых guardrails и projection recovery должен
принадлежать `specs`, а as-built policy, audit snapshots и dispositions —
`docs`. Других active OpenSpec changes нет. Этот change создан по schema version
1, поэтому его собственные Tasks должны вручную соответствовать утверждённому
v2 contract до того, как Apply сделает этот contract default для будущих
changes.
## Goals / Non-Goals
**Goals:**
- сделать planning structure, task ownership и requirement coverage
детерминированно проверяемыми до Apply;
- восстановить project-owned agent workflow из versioned inputs и обнаруживать
drift derived projection;
- сохранить один exact supported CLI contract, пригодный для контролируемого
будущего upgrade;
- распределить guidance между schema, config, durable policy и verifiers без
конкурирующих источников;
- сохранить все source assessments и нормализовать их claims с доказательными
dispositions;
- сохранить пропорциональность workflow и существующие human approval gates.
**Non-Goals:**
- обновление OpenSpec CLI в этом change;
- изменение frontend, backend, runtime API или deployment behavior;
- универсальная схема для других проектов, Fast Track или второй lifecycle;
- собственный workflow engine, identity/signature system для approvals или
общий dependency scheduler для changes;
- автоматическое доказательство смысловой полноты Proposal, Specs или Design;
- новые review, completion, blocker, revision либо traceability artifacts.
## Decisions
### 1. Native schema v2 остаётся workflow engine
`wealth-ledger-sdd` повышается до version 2, сохраняя граф
`Proposal → Delta Specs → Design → Tasks → Apply`. Изменяется contract
существующих artifacts, а не их число. Schema и templates задают обязательную
форму Tasks, условный rollback contract, stage validation guidance, полный
feedback path и компактные примеры сложных delta operations. Minimal spec
template остаётся ориентированным на `ADDED`; неиспользуемые delta sections не
генерируются как пустые placeholders.
Artifact approval остаётся человеческим фактом разговора. File existence и
CLI status продолжают означать только structural state. Форматное исправление,
не меняющее approved semantics, повторяет structural checks без каскадного
reapproval; любое изменение intent, behavior, architecture или task scope
возвращает workflow к самому раннему затронутому artifact и инвалидирует его
downstream approvals.
### 2. Guidance имеет явных владельцев
Ответственность разделяется так:
| Surface | Authority |
| --- | --- |
| schema instructions | artifact semantics, native syntax и workflow behavior |
| templates | только форма создаваемого Markdown |
| config context | стабильные факты workspace и язык project artifacts |
| config rules | только краткие additive project constraints, отсутствующие в schema |
| governance и ADR | durable rationale, ownership и upgrade policy |
| non-mutating verifiers | Enforceable Engineering Invariants |
Текущие config rules, дословно повторяющие schema, удаляются или сокращаются;
произвольный `_rules.md` не вводится. Project explanations пишутся по-русски,
а OpenSpec tokens, headings, commands и normative keywords сохраняются в их
точной английской форме.
### 3. Planning verifier отделён от full delivery dispatcher
`specs` получает один stage-aware non-mutating planning verifier. Он разрешает
change через canonical store и применяет только доступные на текущем этапе
checks:
- Proposal — metadata, обязательную структуру и разрешимость declared existing
capability paths;
- Delta Specs — strict change validation и соответствие capability set
Proposal;
- Design — Delivery Map, Contract Gate Decision и rollback decision;
- Tasks — checkbox shape, area ownership, canonical gate coverage и точные
requirement references, включая explicit `N/A` rationale.
Verifier не пытается машинно оценивать качество мотивации, архитектурного
rationale или semantic correctness. Full workspace dispatcher вызывает его
перед affected-area gates, а artifact entrypoints запускают доступный stage до
запроса approval. Проверяемая логика получает compliant fixtures и
representative failures для uncovered requirement, invalid area, malformed
rollback decision и projection/version drift. Существующие parsers Delivery Map
переиспользуются либо извлекаются, а не дублируются вторым несовместимым
разбором.
### 4. Tasks используют area owner и встроенную coverage metadata
Каждый checkbox использует формат `X.Y [area] action`, где `area` — ровно одна
из `frontend`, `backend`, `specs`, `docs`, `workspace`. Следующие indented
metadata lines содержат:
- `Covers`: одна или несколько пар `capability path — exact Requirement
heading` либо `N/A — concrete reason`;
- `Verification`: planned command, observable check или delivered artifact.
OpenSpec продолжает отслеживать progress по checkbox line, а planning verifier
связывает последующие metadata lines с ближайшим checkbox. Cross-repository
implementation разбивается по repository owners; `workspace` используется
только для orchestration и verification. Requirement heading остаётся native
identity OpenSpec; дополнительный ID namespace не создаётся.
### 5. Root agent projection получает versioned canonical source
Текущие project-owned `commands` и `skills` импортируются как canonical source
tree под `specs/agent-projection/opencode`. Package manifests, installed
dependencies и machine-local runtime state не входят в source. Явная sync
команда атомарно обновляет соответствующие каталоги root `.opencode`, а
отдельный non-mutating verifier сравнивает required file set и contents с
canonical source.
На upgrade новая upstream projection сначала создаётся в isolated staging.
Upstream delta и минимальные WealthLedger overlays — fixed store,
one-artifact-at-a-time approvals, feedback path и hard archive blockers —
переносятся в canonical source, после чего sync обновляет root derived output.
Authority verifier получает expected version из единственного version contract
и проверяет совпадение каждого required generated marker. Concrete CLI version
не закрепляется в verifier logic или fixtures независимо от contract.
Canonical source tree выбран вместо:
- patch set: меньше committed content, но patches хрупки к upstream text churn;
- custom generator: устраняет дублирование, но создаёт новый transformation
engine и повышает maintenance cost;
- symlink: устраняет copy drift, но связывает agent discovery с filesystem и
tool-specific symlink behavior;
- manual staging only: сохраняет текущую простоту, но не обеспечивает recovery
из clean checkouts.
### 6. Rollback contract является условной частью Design
Design template получает внутри Migration Plan структурированный rollback
decision. Для auth/security, data integrity или migration, public contract и
других труднообратимых решений status `required` раскрывает trigger, actions,
data safety и verification. Для остальных changes status `N/A` требует
конкретной причины. Отдельный rollback artifact не создаётся.
У этого change rollback contract имеет status `N/A`: application data,
security behavior и public contracts не меняются, а committed specs/docs
обратимы через Git. Initial projection cutover выполняется атомарно и сохраняет
предыдущее local derived state до успешного verification, чтобы failed sync не
оставил частично обновлённый workspace.
### 7. Multi-source assessment хранит raw evidence и отдельный triage
Пять исходных model reports переносятся byte-for-byte в один dated audit
snapshot set под `docs/audits`; index обозначает их как external, non-authority
claims и фиксирует checksums. После проверки совпадения исходная unversioned
папка удаляется, чтобы не оставить competing copy.
Live registry получает нормализованные Audit IDs. Повторяющиеся claims имеют
одну запись со ссылками на все sources. Triage disposition
`confirmed | already-covered | rejected | deferred` хранится отдельно от
remediation status. Confirmed findings этого scope связываются с текущим active
change; already-covered получают existing evidence; rejected — rationale;
deferred — review trigger. Следующим planned remediation после завершения этого
change снова становится ранее выбранная auth platform assessment.
### 8. Version contract фиксирует совместимость, а не вечную версию
Текущая exact version остаётся неизменной. Появление новой stable версии не
блокирует delivery и не меняет contract автоматически. Future upgrade является
отдельным SDD change и проходит staged projection comparison, schema/status/
instructions compatibility, canonical-store checks, disposable lifecycle и
positive/negative authority fixtures. Historical archives и Completion Evidence
сохраняют фактические версии своих запусков.
## Delivery Map
| Area | Status | Architectural outcome or N/A reason |
| --- | --- | --- |
| frontend | `N/A` | Change не меняет frontend behavior, source, contract или canonical gate. |
| backend | `N/A` | Change не меняет backend behavior, source, contract или canonical gate. |
| specs | `affected` | Schema v2, planning/projection guardrails, canonical agent source и нормативные lifecycle requirements образуют единый проверяемый SDD contract. |
| docs | `affected` | Immutable multi-source audit, dispositions, governance, lifecycle documentation и ADR отражают поставленную SDD-систему. |
### Contract Gate Decision
| Gate | Status | Reason |
| --- | --- | --- |
| runtime-openapi | `N/A` | Change не затрагивает backend runtime API, frontend generated client или committed OpenAPI snapshot. |
## Solution Assessment
Change существенно меняет общую project tooling infrastructure, поэтому
сравнение alternatives обязательно.
### Workflow enforcement
| Option | Fit и maturity | Security / operating cost | Constraints / migration cost | Decision |
| --- | --- | --- | --- | --- |
| Native OpenSpec schema/config + thin project verifiers | Полностью сохраняет canonical artifact graph; используемые extension points уже работают в 1.10, хотя schema API experimental | Local-only, без новых secrets/services; низкая стоимость поверх существующих gates | Требует exact compatibility contract и fixtures при upgrade; incremental migration | Selected |
| Prompt/docs-only conventions | Markdown mature и дёшев, но не отклоняет нарушения | Низкая стоимость, высокий риск silent drift | Не выполняет требования machine validation и reproducibility | Rejected |
| Собственный workflow engine | Максимальный theoretical fit, но custom maturity отсутствует | Новый privileged control surface и высокая постоянная стоимость | Дублирует OpenSpec lifecycle, требует migration всех entrypoints и state | Rejected |
| Общая monorepo/CI platform | Зрелые продукты существуют, но workspace не имеет общего build/dependency graph и CI | Существенная installation и operating cost | Не решает approval semantics или audit traceability сама по себе | Rejected |
### Projection recovery
| Option | Fit и maturity | Operating cost | Main constraint | Decision |
| --- | --- | --- | --- | --- |
| Versioned canonical source tree + sync/check | Простая file projection с детерминированным сравнением | Низкая; около 115 KB source Markdown | Source и derived copy должны проверяться на drift | Selected |
| Versioned overlay patches | Компактно | Средняя/высокая при каждом upstream text change | Patch fragility | Rejected |
| Programmatic overlay generator | Гибко | Высокая; собственная transformation logic | Риск второго workflow engine | Rejected |
| Symlink в specs-owned tree | Минимум duplication | Низкая локально | Tool/filesystem portability и смешение machine-local package state | Rejected |
Выбранный вариант не реализует OpenSpec behavior самостоятельно: native CLI
остаётся engine, а project scripts только синхронизируют derived files и
проверяют детерминированные инварианты.
## Risks / Trade-offs
- **Canonical source и derived projection дублируют Markdown.** Drift блокирует
verifier; изменения вносятся только в source и распространяются explicit
sync-командой.
- **Markdown parser может стать хрупким.** Машиночитаемые prefixes и metadata
намеренно узкие, fixture suite покрывает compliant и representative invalid
inputs, а semantic review остаётся отдельным gate.
- **Traceability создаёт ложное ощущение semantic coverage.** Verifier
подтверждает наличие ссылок, но semantic verification и independent review
продолжают проверять полноту реализации.
- **Форматное исключение может скрыть semantic edit.** Оно ограничено ошибками,
не меняющими intent, behavior, decisions или tasks; сомнение возвращает
artifact на обычный reapproval path.
- **Schema instructions могут разрастись.** Duplicate config rules удаляются,
examples остаются короткими, а final instruction size сравнивается с
baseline без жёсткого token threshold.
- **Raw model reports могут выглядеть authoritative.** Snapshot index и registry
явно разделяют source claims, triage evidence и project authority.
- **Initial source-tree bootstrap не имеет прежней versioned baseline.** Sync
сохраняет local pre-cutover state до успешного gate; после поставки все
дальнейшие projection versions становятся восстановимыми через Git history.
- **Future OpenSpec release может изменить experimental interfaces.** Exact
contract блокирует silent adoption, а отдельный upgrade change выполняет
staged compatibility assessment.
## Migration Plan
1. Ввести canonical projection source и non-mutating planning/projection checks,
подтвердив compliant и controlled-invalid fixtures до переключения schema.
2. Обновить schema, templates, config и canonical agent source до v2 contract;
собственные Tasks этого change оформить уже в новом формате.
3. Атомарно синхронизировать root derived projection и отклонить delivery при
любом content/version drift.
4. Перенести raw assessments в immutable indexed snapshot, проверить
byte-for-byte equality, удалить unversioned copy и обновить live registry.
5. Обновить governance, lifecycle docs и ADR до фактической архитектуры, затем
выполнить specs/docs gates, semantic verification и independent review.
### Rollback Contract
| Field | Decision |
| --- | --- |
| Status | `N/A` |
| Reason | Change не меняет application data, security behavior или public contracts; committed state обратим через Git, а projection является derived output с atomic cutover. |
| Failed cutover handling | Sync восстанавливает сохранённое pre-cutover local state и не объявляет source/projection согласованными. |
| Verification | Planning, projection, authority, strict OpenSpec и docs gates должны снова подтвердить выбранное состояние. |
@@ -0,0 +1,58 @@
## Why
WealthLedger уже использует строгий SDD lifecycle, но его качество сейчас
зависит от нескольких разрозненных соглашений и ручной семантической проверки.
Собранные независимые оценки выявили повторяющиеся риски: требования могут быть
недостаточно явно связаны с работой по их поставке, ответственность задач в
multi-repository workspace может читаться неоднозначно, а восстановление и
эволюция workflow требуют слишком много неявного знания. Эти риски стоит
устранить до следующих remediation changes, чтобы последующая разработка
опиралась на воспроизводимый и проверяемый процесс.
## What Changes
- Установить единый проверяемый контракт качества SDD, связывающий изменяемые
требования, запланированную delivery-работу и ответственность каждой области.
- Сделать возврат к upstream artifact, повторное утверждение и риск-обусловленный
rollback явными частями lifecycle, не создавая параллельных planning artifacts.
- Обеспечить воспроизводимость project-owned agent workflow и управляемую
совместимость при будущей смене поддерживаемой версии инструмента.
- Сохранить исходные multi-source audit assessments неизменными и дать каждому
нормализованному замечанию проверяемый итог: исправление, подтверждённое
существующее покрытие, осознанное отклонение либо отложенный trigger.
- Разделить устойчивую policy, artifact-specific guidance и автоматические
guardrails так, чтобы обязательное правило имело одного владельца и не
зависело от необязательного чтения дополнительного контекста.
Не входят в change: изменение поведения приложений или публичных контрактов,
создание универсального SDD framework для других проектов, отдельный ускоренный
lifecycle, новая модель identity для owner approval, дополнительные planning
artifacts и общий механизм зависимостей между changes без наблюдаемой
потребности.
## Capabilities
### New Capabilities
Нет.
### Modified Capabilities
- `openspec-authority-and-lifecycle`: усилить воспроизводимость workflow,
совместимость поддерживаемой версии, проверки planning artifacts и
контролируемый возврат к изменённому upstream artifact.
- `multi-repository-delivery`: сделать ownership задач и покрытие изменяемых
требований явными и проверяемыми для каждой delivery area.
- `engineering-change-governance`: дополнить risk-based planning обязательной
rollback discipline для труднообратимых изменений и проверяемыми SDD
guardrails.
- `audit-remediation-workflow`: поддержать неизменяемое multi-source audit
evidence и нормализованные dispositions без превращения внешних оценок в
authority проекта.
## Impact
Изменение затрагивает Change Owner и AI-агентов, которые создают, утверждают,
реализуют и проверяют WealthLedger changes. Оно изменяет нормативный SDD
workflow и его as-built process documentation, но не меняет frontend, backend,
пользовательское поведение или runtime API contracts.
@@ -0,0 +1,46 @@
## MODIFIED Requirements
### Requirement: Реестр remediation отделён от снимка аудита
Система SHALL создавать отдельный неизменяемый versioned audit snapshot в `docs/audits` для каждого завершённого аудита и SHALL поддерживать один актуальный durable remediation registry в `docs/development`, охватывающий findings всех audit snapshots. Для завершённого multi-source audit система SHALL сохранять каждый source file byte-for-byte и объединять их одним snapshot index. Каждый snapshot SHALL оставаться source of claims своего аудита и MUST NOT редактироваться для отражения последующей remediation. Внешняя модельная оценка MUST быть обозначена как неавторитетный источник claims и MUST NOT подменять requirements, governance или проверенное состояние проекта. Registry SHALL хранить текущее состояние, связанный canonical change, следующее действие и completion evidence каждой записи, MUST ссылаться на однозначный Audit ID и каждый относящийся source snapshot и MUST NOT дублировать полный текст finding, если он уже содержится в snapshot.
#### Scenario: Агент открывает работу по аудиту в новой сессии
- **WHEN** агент получает задачу устранить или продолжить finding из любого завершённого аудита
- **THEN** он находит в едином registry исходный snapshot и Audit ID, текущий статус, связанный OpenSpec change, evidence и следующее действие без повторной интерпретации всех аудитов
#### Scenario: Проводится повторный аудит
- **WHEN** новый аудит завершён после предыдущего audit snapshot
- **THEN** система добавляет новый immutable snapshot и обновляет тот же live registry, не переписывая предыдущий snapshot и не создавая конкурирующий registry
#### Scenario: Обновляется прогресс remediation
- **WHEN** работа по finding меняет статус
- **THEN** versioned audit snapshots не редактируются, а изменение фиксируется только в live registry с датой и необходимым evidence
#### Scenario: Один аудит содержит несколько внешних оценок
- **WHEN** завершённая assessment использовала несколько независимых source reports
- **THEN** snapshot index связывает byte-for-byte сохранённые reports в один audit и явно отделяет их claims от project authority
## ADDED Requirements
### Requirement: Каждое audit claim получает доказательный disposition
Каждое уникальное claim завершённого multi-source audit MUST входить ровно в один нормализованный Audit ID и иметь triage disposition `confirmed`, `already-covered`, `rejected` или `deferred`. Нормализованная запись MUST ссылаться на каждый source report, содержащий claim. `confirmed` MUST связываться с remediation status и change либо terminal evidence; `already-covered` MUST приводить проверяемое существующее evidence; `rejected` MUST содержать конкретное rationale; `deferred` MUST содержать review trigger. Triage disposition MUST оставаться отдельным от remediation status `planned`, `active`, `done`, `deferred` или `accepted`, чтобы внешняя рекомендация не становилась принятой policy без проверки.
#### Scenario: Несколько моделей повторяют одно замечание
- **WHEN** два или более source reports описывают один и тот же underlying gap
- **THEN** registry содержит один нормализованный Audit ID со ссылками на все источники и одним доказательным disposition
#### Scenario: Рекомендация уже реализована
- **WHEN** проверяемое состояние проекта полностью покрывает external claim
- **THEN** disposition `already-covered` ссылается на существующий requirement, guardrail или completion evidence без создания фиктивной remediation work
#### Scenario: Внешняя рекомендация противоречит authority
- **WHEN** source report предлагает неподдерживаемый либо ухудшающий действующий invariant подход
- **THEN** disposition `rejected` фиксирует конкретное противоречие и не превращает recommendation в requirement
@@ -0,0 +1,20 @@
## ADDED Requirements
### Requirement: Труднообратимое изменение имеет rollback contract
Design MUST определять rollback trigger, rollback actions, data safety и rollback verification, когда change затрагивает auth или security behavior, data integrity или migration, public contract либо другое существенно труднообратимое решение. Rollback contract MUST учитывать данные и совместимость, созданные после поставки change, и MUST быть выполним без нового неутверждённого архитектурного решения. Когда указанные риски неприменимы, Design SHALL фиксировать конкретную проверяемую причину `N/A` и MUST NOT создавать отдельный artifact или формальный rollback plan ради процесса.
#### Scenario: Change мигрирует данные
- **WHEN** Design изменяет хранимые данные способом, который может потребовать возврата
- **THEN** он определяет trigger, безопасные действия отката, судьбу новых данных и проверку восстановленного состояния до утверждения Tasks
#### Scenario: Change меняет публичный контракт
- **WHEN** Design вводит несовместимое изменение публичного контракта
- **THEN** rollback contract объясняет восстановление совместимости и проверяемое условие успешного отката
#### Scenario: Rollback risk отсутствует
- **WHEN** change не затрагивает auth, security, данные, публичный контракт или другое труднообратимое решение
- **THEN** Design указывает конкретную причину `N/A` без создания дополнительного rollback artifact
@@ -0,0 +1,39 @@
## ADDED Requirements
### Requirement: Каждая задача объявляет единственную delivery area
Каждый checkbox Tasks MUST объявлять ровно одного owner из `frontend`, `backend`, `specs`, `docs` или `workspace`. Implementation work, изменяющая несколько Git-репозиториев, MUST быть разделена на repository-owned tasks; `workspace` SHALL использоваться только для cross-area orchestration или verification без владения repository implementation. Для каждой `affected` area Tasks MUST содержать её implementation work и canonical local gate, а task ownership MUST соответствовать утверждённому Delivery Map.
#### Scenario: Change затрагивает frontend и backend
- **WHEN** одна delivery intent требует изменения клиента и API
- **THEN** Tasks содержит отдельные frontend-owned и backend-owned checkbox items вместо одной общей implementation task
#### Scenario: Выполняется общий verification gate
- **WHEN** задача только оркестрирует проверку нескольких affected areas и не изменяет их implementation
- **THEN** task использует owner `workspace` и не подменяет repository-owned implementation или canonical gates
#### Scenario: Task ссылается на N/A area
- **WHEN** checkbox объявляет owner области, которая имеет статус `N/A` в Delivery Map
- **THEN** planning validation завершается ошибкой и указывает несогласованную delivery area
### Requirement: Tasks трассируются к утверждённым требованиям
Каждый checkbox Tasks MUST содержать coverage reference: одну или несколько пар из точного capability path и точного Requirement heading либо `N/A` с конкретной причиной для работы, которая не реализует spec-level behavior. Каждый Requirement из Delta Specs MUST быть покрыт хотя бы одной task. Planning validation MUST отклонять отсутствующее покрытие, ссылку на несуществующий capability или Requirement и пустую причину `N/A`. Traceability SHALL использовать нативную идентичность requirement и MUST NOT вводить параллельный namespace собственных requirement IDs.
#### Scenario: Delta requirement покрыт реализацией
- **WHEN** Tasks планирует поставку изменённого requirement
- **THEN** хотя бы один checkbox ссылается на точный capability path и Requirement heading этого delta
#### Scenario: Задача не меняет spec-level behavior
- **WHEN** task обновляет infrastructure, documentation или verification без самостоятельного requirement
- **THEN** coverage reference содержит `N/A` и конкретно объясняет отсутствие spec-level связи
#### Scenario: Requirement остался без задачи
- **WHEN** хотя бы один Requirement из Delta Specs не указан ни в одной coverage reference
- **THEN** planning validation блокирует approval Tasks и перечисляет uncovered Requirement
@@ -0,0 +1,79 @@
## MODIFIED Requirements
### Requirement: Изменение upstream artifact требует каскадной проверки
Изменение утверждённого Proposal MUST инициировать повторную проверку Delta Specs, Design и Tasks; изменение утверждённых Delta Specs MUST инициировать повторную проверку Design и Tasks; изменение утверждённого Design MUST инициировать повторную проверку Tasks. Изменение Tasks MUST NOT неявно менять scope, наблюдаемое поведение или архитектурные решения upstream artifacts; при таком обнаружении workflow SHALL вернуть работу к самому раннему затронутому upstream artifact и его approval gate. Если несоответствие обнаружено во время Design или Apply, downstream-работа MUST остановиться, а Change Owner MUST получить наблюдаемое основание возврата и решения, требуемые на выбранном уровне. Механическое исправление синтаксиса или формата, которое не меняет утверждённые намерение, поведение, архитектурные решения или состав задач, MUST пройти повторную structural validation и MUST NOT само по себе инвалидировать approvals.
#### Scenario: После Design изменилось намерение
- **WHEN** владелец меняет scope или ожидаемый эффект Proposal
- **THEN** зависимые Delta Specs, Design и Tasks теряют прежнее подтверждение до повторной согласованной проверки
#### Scenario: Task вводит новое поведение
- **WHEN** implementation checklist требует поведение, которого нет в утверждённых Delta Specs
- **THEN** агент не расширяет scope через Tasks и возвращает change к Delta Specs
#### Scenario: Apply выявляет архитектурное расхождение
- **WHEN** во время реализации обнаружено, что утверждённый Design не позволяет выполнить Specs без другого архитектурного решения
- **THEN** Apply останавливается, Tasks теряет прежнее подтверждение, а change возвращается к Design с наблюдаемым основанием и вариантами решения
#### Scenario: Исправляется только структурный формат
- **WHEN** утверждённый artifact содержит исправимую синтаксическую или formatting-ошибку без изменения его смысла
- **THEN** workflow исправляет ошибку, повторяет structural validation и сохраняет действующие approvals
### Requirement: OpenSpec tooling имеет проверяемый version contract
SDD workflow MUST объявлять одну текущую поддерживаемую версию OpenSpec CLI в canonical version contract и проверять фактическую версию до команд, читающих или изменяющих canonical change. Normative checks и проверяемые generated markers MUST получать ожидаемую версию из этого контракта и MUST NOT независимо закреплять конкретный version literal. Несовместимая либо неопределённая версия MUST давать actionable blocking result и MUST NOT приводить к молчаливому изменению artifact graph, templates или project-owned entrypoints. Публикация новой stable версии MUST NOT автоматически менять поддерживаемую версию проекта. Upgrade SHALL изменять version contract только после изолированной проверки совместимости schema, agent workflow, canonical store и hard blockers и SHALL сохранять историческое evidence с фактически использованными ранее версиями.
#### Scenario: Версия CLI соответствует контракту
- **WHEN** агент начинает работу с canonical change поддерживаемой версией OpenSpec
- **THEN** workflow продолжает работу с объявленной схемой и canonical store
#### Scenario: Версия CLI не соответствует контракту
- **WHEN** доступная версия OpenSpec не совпадает с объявленным совместимым контрактом
- **THEN** локальная preflight-проверка блокирует SDD-операцию и сообщает ожидаемую и фактическую версии
#### Scenario: Опубликована новая stable версия
- **WHEN** upstream публикует новую stable версию, которая ещё не прошла project compatibility assessment
- **THEN** текущий version contract остаётся действующим и новая версия не становится неявным требованием для разработки
#### Scenario: Подготовлен upgrade candidate
- **WHEN** Engineering Owner рассматривает смену поддерживаемой версии
- **THEN** изолированная проверка подтверждает schema, agent workflow, store selection и hard blockers до изменения version contract и project-owned projection
## ADDED Requirements
### Requirement: Project-owned agent workflow воспроизводим из versioned authority
Project-owned agent workflow SHALL восстанавливаться в новом workspace из committed authority inputs и текущей поддерживаемой версии инструмента без использования прежнего локального generated state. Workspace-level projection SHALL оставаться derived output и MUST NOT становиться конкурирующим SDD authority. Non-mutating verifier MUST обнаруживать отсутствие required projection, расхождение с versioned inputs и несовместимый generated version marker; установленные зависимости и machine-local runtime state MUST NOT считаться authority inputs.
#### Scenario: Workspace собирается заново
- **WHEN** участник получает чистые checkout всех project repositories и поддерживаемый инструмент
- **THEN** documented workflow воспроизводит project-owned agent projection из versioned inputs без копирования файлов с прежней машины
#### Scenario: Derived projection изменена вручную
- **WHEN** локальная project-owned projection больше не соответствует versioned authority inputs
- **THEN** non-mutating verifier завершает проверку ошибкой и указывает на projection drift
### Requirement: Planning artifact проверяется до запроса approval
Каждый создаваемый planning artifact SHALL пройти все применимые на его текущем этапе non-mutating structural checks до запроса approval Change Owner. Если полный change validation ещё заблокирован отсутствующими downstream artifacts, workflow MUST выполнить доступные проверки текущего artifact и явно оставить недоступную проверку незавершённой, а не заявлять общий успех. Техническая ошибка проверяемого формата SHALL исправляться и проверяться повторно без передачи ручного исправления Change Owner; structural success MUST NOT подменять semantic approval.
#### Scenario: Текущий artifact имеет проверяемое нарушение
- **WHEN** сгенерированный planning artifact нарушает обязательный формат или ссылочную целостность, доступные для проверки на текущем этапе
- **THEN** workflow исправляет нарушение и повторяет structural checks до запроса owner approval
#### Scenario: Downstream artifacts ещё отсутствуют
- **WHEN** Proposal создан, а Delta Specs, Design и Tasks ещё не существуют
- **THEN** workflow сообщает результат доступных Proposal checks и не представляет отсутствующую full-change validation как успешную
@@ -0,0 +1,65 @@
## 1. Planning guardrails
- [x] 1.1 [specs] Реализовать выбранный в Solution Assessment вариант native OpenSpec + thin project verifiers: извлечь или переиспользовать существующий разбор Delivery Map и добавить stage-aware `verify-openspec-planning.sh` без собственного workflow state
- **Covers:** `openspec-authority-and-lifecycle` — `Planning artifact проверяется до запроса approval`
- **Verification:** Запустить verifier последовательно на fixtures стадий Proposal, Delta Specs, Design и Tasks и подтвердить, что он применяет только доступные на каждой стадии checks.
- [x] 1.2 [specs] Добавить positive и controlled-negative fixtures для proposal structure и capability set, malformed rollback decision, invalid или `N/A` delivery area, отсутствующей task metadata, неверной requirement reference и uncovered Requirement
- **Covers:** `openspec-authority-and-lifecycle` — `Planning artifact проверяется до запроса approval`; `multi-repository-delivery` — `Каждая задача объявляет единственную delivery area`; `multi-repository-delivery` — `Tasks трассируются к утверждённым требованиям`; `engineering-change-governance` — `Труднообратимое изменение имеет rollback contract`
- **Verification:** Запустить fixture suite и проверить успешный compliant case, ожидаемые non-zero exits и actionable сообщения для каждого representative failure.
- [x] 1.3 [specs] Подключить planning verifier к workspace dispatcher до affected-area gates, сохранив явное различие между stage success, full-change validation и semantic approval
- **Covers:** `openspec-authority-and-lifecycle` — `Planning artifact проверяется до запроса approval`
- **Verification:** На incomplete disposable change проверить stage-only результат, а на полном change запустить dispatcher и подтвердить, что planning gate выполняется раньше repository gates.
## 2. Versioned agent projection
- [x] 2.1 [specs] Импортировать project-owned `commands` и `skills` в canonical source tree `specs/agent-projection/opencode`, документировав границы projection и исключив package manifests, dependencies и machine-local state
- **Covers:** `openspec-authority-and-lifecycle` — `Project-owned agent workflow воспроизводим из versioned authority`
- **Verification:** Сравнить перечень canonical files с текущей project-owned root projection и подтвердить отсутствие package/runtime files в committed source tree.
- [x] 2.2 [specs] Добавить explicit atomic sync для root `.opencode` с восстановлением pre-cutover state при ошибке и отдельный non-mutating exact-content verifier required file set
- **Covers:** `openspec-authority-and-lifecycle` — `Project-owned agent workflow воспроизводим из versioned authority`
- **Verification:** В disposable workspace проверить успешное восстановление projection из canonical source, обнаружение missing/content drift и отсутствие частично обновлённого output после искусственно сорванного sync.
- [x] 2.3 [specs] Расширить authority fixtures проверками projection drift и generated version markers, получая expected version только из `openspec/.cli-version`
- **Covers:** `openspec-authority-and-lifecycle` — `Project-owned agent workflow воспроизводим из versioned authority`; `openspec-authority-and-lifecycle` — `OpenSpec tooling имеет проверяемый version contract`
- **Verification:** Запустить authority fixture suite для current contract, mismatched CLI/marker, missing projection и content drift; проверить отсутствие независимого literal `1.10.0` в normative scripts и fixtures.
## 3. Schema v2 and entrypoints
- [x] 3.1 [specs] Повысить `wealth-ledger-sdd` до version 2 и перераспределить guidance по утверждённой owner matrix между schema instructions, templates и additive config без `_rules.md`, добавив stage validation, полный feedback path и компактные примеры сложных delta operations
- **Covers:** `openspec-authority-and-lifecycle` — `Изменение upstream artifact требует каскадной проверки`; `openspec-authority-and-lifecycle` — `Planning artifact проверяется до запроса approval`
- **Verification:** Выполнить `openspec schema validate wealth-ledger-sdd --verbose` из `specs`, получить instructions всех четырёх artifacts и проверить graph, русские explanations, exact English OpenSpec syntax и отсутствие дублирующих config rules.
- [x] 3.2 [specs] Обновить Design template условным Rollback Contract, а Tasks template — checkbox owner `[area]` и обязательными `Covers`/`Verification`, сохранив minimal ADDED-first Spec template
- **Covers:** `multi-repository-delivery` — `Каждая задача объявляет единственную delivery area`; `multi-repository-delivery` — `Tasks трассируются к утверждённым требованиям`; `engineering-change-governance` — `Труднообратимое изменение имеет rollback contract`
- **Verification:** Сгенерировать disposable lifecycle по schema v2 и проверить template shape, `required`/`N/A` rollback cases, точные requirement references и отсутствие пустых delta sections.
- [x] 3.3 [specs] Обновить canonical agent commands и skills: запускать version и доступные planning checks до approval, возвращать Apply feedback к раннему затронутому artifact и использовать canonical store; затем атомарно синхронизировать root projection
- **Covers:** `openspec-authority-and-lifecycle` — `Изменение upstream artifact требует каскадной проверки`; `openspec-authority-and-lifecycle` — `OpenSpec tooling имеет проверяемый version contract`; `openspec-authority-and-lifecycle` — `Project-owned agent workflow воспроизводим из versioned authority`; `openspec-authority-and-lifecycle` — `Planning artifact проверяется до запроса approval`
- **Verification:** Выполнить sync и non-mutating projection check, затем просмотреть instructions/entrypoints для Proposal, Specs, Design, Tasks и Apply и подтвердить fixed store, stage gate и feedback routing.
- [x] 3.4 [specs] Проверить собственный `tasks.md` этого change новым v2 verifier и исправить только технические нарушения формата без изменения утверждённого scope
- **Covers:** `multi-repository-delivery` — `Каждая задача объявляет единственную delivery area`; `multi-repository-delivery` — `Tasks трассируются к утверждённым требованиям`
- **Verification:** Запустить planning verifier для `harden-openspec-sdd-quality` и подтвердить owners только affected areas, валидность всех references и покрытие каждого Delta Requirement.
## 4. Audit evidence and durable documentation
- [x] 4.1 [docs] Перенести пять исходных model reports byte-for-byte в один dated snapshot set под `docs/audits`, добавить index с source list, checksums и external non-authority warning, обновить audits index и удалить unversioned `sdd-audit` только после проверки равенства
- **Covers:** `audit-remediation-workflow` — `Реестр remediation отделён от снимка аудита`
- **Verification:** Сверить для всех пяти файлов byte count и checksum source/destination до удаления source, затем проверить index links и ровно один versioned snapshot set.
- [x] 4.2 [docs] Нормализовать все уникальные audit claims в live remediation registry с Audit IDs, всеми source references, доказательными dispositions и отдельными remediation statuses; связать confirmed scope с текущим active change и сохранить auth platform assessment следующим planned item без будущего terminal evidence
- **Covers:** `audit-remediation-workflow` — `Каждое audit claim получает доказательный disposition`; `audit-remediation-workflow` — `Реестр remediation отделён от снимка аудита`
- **Verification:** Сопоставить каждое claim пяти reports ровно одному Audit ID и проверить обязательные evidence/rationale/review trigger для соответствующего disposition и отсутствие дублирующего registry.
- [x] 4.3 [docs] Обновить engineering governance, OpenSpec lifecycle guide, ADR 010 и связанные indexes до фактического v2 ownership, projection recovery, traceability, feedback, rollback и controlled-upgrade contract
- **Covers:** `openspec-authority-and-lifecycle` — `Изменение upstream artifact требует каскадной проверки`; `openspec-authority-and-lifecycle` — `OpenSpec tooling имеет проверяемый version contract`; `openspec-authority-and-lifecycle` — `Project-owned agent workflow воспроизводим из versioned authority`; `openspec-authority-and-lifecycle` — `Planning artifact проверяется до запроса approval`; `multi-repository-delivery` — `Каждая задача объявляет единственную delivery area`; `multi-repository-delivery` — `Tasks трассируются к утверждённым требованиям`; `engineering-change-governance` — `Труднообратимое изменение имеет rollback contract`
- **Verification:** Выполнить scoped review updated docs против поставленных scripts/schema и проверить local links и indexes без копирования planning artifacts в docs.
## 5. Delivery verification
- [x] 5.1 [specs] Выполнить canonical specs gates и controlled-invalid fixture suites после интеграции schema, planning, projection и authority checks
- **Covers:** `N/A` — задача агрегирует verification уже покрытых требований и не вводит самостоятельное spec-level behavior.
- **Verification:** Запустить version preflight, planning/projection/authority fixture suites, schema validation, strict change validation, strict main-spec validation, authority verifier и `git diff --check` в `specs`.
- [x] 5.2 [docs] Выполнить canonical docs gate и scoped проверку audit snapshot, checksums, registry completeness, indexes и local links
- **Covers:** `N/A` — задача проверяет docs delivery уже покрытых audit requirements и не добавляет новое поведение.
- **Verification:** Запустить `npm run verify` в `docs` и отдельно подтвердить affected local links, snapshot checksums и claim-to-Audit-ID coverage.
- [x] 5.3 [workspace] Выполнить cross-area dispatcher для полного change без frontend/backend и runtime-openapi gates
- **Covers:** `N/A` — workspace task оркестрирует canonical gates affected repositories и не заменяет repository-owned implementation.
- **Verification:** Запустить `bash specs/scripts/verify-workspace-change.sh harden-openspec-sdd-quality` и подтвердить Delivery Map `specs/docs=affected`, `frontend/backend=N/A` и `runtime-openapi=N/A`.
- [x] 5.4 [workspace] Провести semantic verification реализации против Proposal, всех 9 Delta Requirements и 28 Scenarios, Design и Tasks, затем independent read-only review без Critical или Important findings
- **Covers:** `N/A` — terminal semantic и independent reviews проверяют change целиком, но не реализуют отдельный Requirement.
- **Verification:** Сохранить наблюдаемое review evidence только после фактических запусков и устранить блокирующие findings до archive eligibility.
+2 -11
View File
@@ -5,14 +5,5 @@ context: |
Canonical OpenSpec authority — зарегистрированный store wealth-ledger-specs в specs/openspec.
Docs описывает только фактическое as-built состояние; устойчивые process policies находятся в docs/development.
Локальная разработка и verification выполняются под Node 22 без CI.
rules:
proposal:
- Формулировать owner-утверждаемое намерение без технологий, API, файлов и зависимостей.
specs:
- Описывать только изменение наблюдаемого поведения и инвариантов, не изменение кода.
design:
- Всегда включать Delivery Map для frontend, backend, specs и docs.
- Добавлять Solution Assessment только при build-vs-buy trigger из schema instructions.
tasks:
- Включать planned verification каждой affected области, но не observed results, commit IDs или post-archive bookkeeping.
Project artifacts объясняют решения по-русски; exact OpenSpec headings, tokens,
commands и normative keywords SHALL/MUST сохраняются на английском.
+131 -27
View File
@@ -1,6 +1,6 @@
name: wealth-ledger-sdd
version: 1
description: WealthLedger SDD workflow - proposal → specs → design → tasks
version: 2
description: WealthLedger SDD workflow - proposal → specs → design → tasks → apply
artifacts:
- id: proposal
generates: proposal.md
@@ -33,11 +33,22 @@ artifacts:
behavior, so if behavior does not change, no spec should change either.
Do not invent a requirement just to satisfy validation.
MUST NOT включать технологии, библиотеки, API signatures, имена файлов,
зависимости, классы или пошаговую реализацию. Эти решения появляются
только после Delta Specs в Design.
Artifact boundary — MUST NOT include:
- технологии, библиотеки, зависимости или выбранную архитектуру: эти
решения появляются только после Delta Specs в Design;
- API signatures, database structures, имена файлов, классов или
функций: это implementation detail для Design;
- implementation steps, task decomposition или verification commands:
это конкретизируется в Tasks после утверждения Design.
This is the foundation - specs, design, and tasks all build on this.
До сохранения исследуй canonical main specs и remediation registry для
audit-derived change. После записи выполни
`bash specs/scripts/verify-openspec-planning.sh <change>`: на этой стадии
verifier проверяет Proposal и явно оставляет downstream validation
pending. Исправь технический формат и повтори check до запроса approval;
structural success не означает approval Change Owner.
requires: []
- id: specs
@@ -55,11 +66,17 @@ artifacts:
- External constraints (security, privacy, reliability, compatibility)
- Scenarios that can be tested or explicitly validated
Не включай в specs:
- Internal class/function names
- Library or framework choices
- Step-by-step implementation details
- Detailed execution plans (those belong in design.md or tasks.md)
Artifact boundary — MUST NOT include:
- intent или scope за пределами утверждённого Proposal: сначала верни
изменение в Proposal;
- internal components, class/function names, files или database
structures: implementation structure определяется в Design;
- library, framework или infrastructure choices: alternatives и решение
принадлежат Design;
- step-by-step implementation, delivery sequencing или verification
commands: это принадлежит Tasks;
- test procedure вместо behavior scenario: scenario фиксирует
наблюдаемые WHEN/THEN, а способ проверки выбирается позднее.
Quick test: if the implementation can change without changing externally
visible behavior, it likely does not belong in the spec.
@@ -113,8 +130,9 @@ artifacts:
Common pitfall: Using MODIFIED with partial content loses detail at archive time.
If adding new concerns without changing existing behavior, use ADDED instead.
Example (a new capability, so it opens with `## Purpose`):
Compact operation examples:
```
# ADDED in a new capability: include Purpose.
## Purpose
Lets users take their data out of the product in a portable format.
@@ -128,15 +146,39 @@ artifacts:
- **WHEN** user clicks "Export" button
- **THEN** system downloads a CSV file with all user data
# MODIFIED: copy the complete old requirement, then edit it.
## MODIFIED Requirements
### Requirement: Session expiration
The system MUST reject an expired session and preserve every surviving
scenario from the main spec.
#### Scenario: Expired session
- **WHEN** a request uses an expired session
- **THEN** the system rejects the request
# REMOVED requires both fields.
## REMOVED Requirements
### Requirement: Legacy export
**Reason**: Replaced by new export system
**Migration**: Use new export endpoint at /api/v2/export
# RENAMED changes only the heading.
## RENAMED Requirements
- FROM: `### Requirement: Old name`
- TO: `### Requirement: New name`
```
Specs должны быть проверяемыми, но scenario не означает автоматический
unit test: уровень проверки выбирается по риску поведения.
Перед записью установи явный approval Proposal из разговора. После
записи выполни `bash specs/scripts/verify-openspec-planning.sh <change>`
и исправь технические ошибки до запроса approval Delta Specs. Если
обнаружено изменение intent, вернись к Proposal и инвалидируй downstream
approvals вместо скрытого расширения Specs.
requires:
- proposal
@@ -146,7 +188,17 @@ artifacts:
template: design.md
instruction: |
Создай Design, объясняющий, КАК архитектурно выполнить утверждённые
Delta Specs. Не превращай его в построчную инструкцию или список правок.
Delta Specs.
Artifact boundary — MUST NOT include:
- новое observable behavior или invariant, отсутствующие в утверждённых
Delta Specs: сначала верни изменение в Specs;
- пересказ Proposal или Specs вместо архитектурных constraints и
решений, необходимых для выбранного подхода;
- file-by-file implementation checklist, verification commands или
пошаговый список правок: это принадлежит Tasks;
- будущие delivery results, commit identifiers или Completion Evidence:
они фиксируются только после наблюдаемого выполнения.
Обязательные разделы:
- **Context**: только текущее состояние и ограничения подхода.
@@ -160,6 +212,12 @@ artifacts:
- **Risks / Trade-offs**: риск и mitigation.
- **Migration Plan**: порядок поставки и rollback, если применимо.
Внутри Migration Plan добавь `### Rollback Contract` с table fields.
Status `required` обязателен для auth/security, data integrity/migration,
public contract и другого существенно труднообратимого решения и требует
Trigger, Actions, Data safety и Verification. В остальных случаях Status
`N/A` требует конкретный Reason. Отдельный rollback artifact не создавай.
Добавь **Solution Assessment**, если изменение вводит или существенно
заменяет auth, security, storage, external integration, observability,
caching, concurrency или общую infrastructure/tooling либо содержит
@@ -176,7 +234,11 @@ artifacts:
skipped. If a question would change the specs, the chosen approach, or
the task breakdown, resolve it now - ask the user instead of guessing.
Design формируется только после явного owner approval Delta Specs.
Design формируется только после явного owner approval Delta Specs. После
записи выполни `bash specs/scripts/verify-openspec-planning.sh <change>`
и исправь технические ошибки до запроса approval. Если Design показывает
несовместимость с intent или behavior, остановись, вернись к самому
раннему затронутому artifact и инвалидируй downstream approvals.
requires:
- specs
@@ -197,8 +259,18 @@ artifacts:
Правила:
- Группируй задачи под numbered `##` headings и располагай по dependencies.
- Каждая задача MUST иметь формат `- [ ] X.Y ...` и быть выполнимой за
одну рабочую сессию.
- Каждая задача MUST иметь формат `- [ ] X.Y [area] action`, быть
выполнимой за одну рабочую сессию и иметь ровно одного owner из
`frontend`, `backend`, `specs`, `docs`, `workspace`.
- Сразу после checkbox добавляй ровно по одной indented metadata line:
`- **Covers:**` и `- **Verification:**`.
- `Covers` содержит одну или несколько пар
`` `capability-path` — `exact Requirement heading` `` либо
`` `N/A` — concrete reason ``. Каждый Delta Requirement должен быть
покрыт хотя бы одной task; собственные requirement IDs не вводятся.
- Owner repository не может иметь статус `N/A` в Delivery Map.
Cross-repository implementation разделяй; `workspace` используй только
для orchestration/verification и с конкретным `N/A` Covers rationale.
- Для каждой `affected` области Delivery Map должна существовать задача
реализации и её canonical local gate; пустые commits запрещены.
- Каждая задача MUST указывать planned verification action: команду,
@@ -213,24 +285,38 @@ artifacts:
branching, transformation, invariant или regression.
- Перед custom implementation в обязательных областях включи действие по
утверждённому Solution Assessment из Design.
- MUST NOT записывать ещё не наблюдённые результаты как выполненные,
предполагаемые commit identifiers, archive path или post-archive
Completion Evidence. Такое evidence создаётся только после факта.
Artifact boundary — MUST NOT include:
- новое observable behavior или Requirement: сначала верни изменение в
Specs;
- новое архитектурное решение или отклонение от утверждённого Design:
сначала обнови Design;
- одну задачу с несколькими owner repositories: раздели её по delivery
areas;
- vague action без проверяемого результата: сформулируй конкретное DO и
planned Verification;
- ещё не наблюдённые результаты как выполненные, предполагаемые commit
identifiers, archive path или post-archive Completion Evidence: такое
evidence создаётся только после факта.
Example:
```
## 1. Setup
## 1. Delivery
- [ ] 1.1 Create new module structure and verify expected files are present
- [ ] 1.2 Add dependencies to package.json and verify package installation succeeds
## 2. Core Implementation
- [ ] 2.1 Implement data export function and verify the export test passes
- [ ] 2.2 Add CSV formatting utilities and verify unit tests cover quoting and delimiters
- [ ] 1.1 [backend] Implement session rejection
- **Covers:** `user-authentication` — `Expired session is rejected`
- **Verification:** Run the backend canonical gate and the expiry contract test.
- [ ] 1.2 [workspace] Run cross-area semantic review
- **Covers:** `N/A` — verification only; no independent spec behavior.
- **Verification:** Compare delivery against every approved Requirement and Scenario.
```
Reference specs for what needs to be built, design for how to build it.
После записи выполни
`bash specs/scripts/verify-openspec-planning.sh <change>` и исправь
технические нарушения до запроса approval. Если Tasks требует новое
behavior или architecture, не расширяй scope: вернись к Specs или Design
и инвалидируй Tasks approval.
requires:
- design
@@ -240,5 +326,23 @@ apply:
instruction: |
Сначала проверь exact OpenSpec version contract. Работай только с change в
canonical store `wealth-ledger-specs` и не создавай parallel planning root.
Read context files, work through pending tasks, mark complete as you go.
Apply допустим только после явных approvals Proposal, Delta Specs, Design и
Tasks из разговора. До реализации выполни
`bash specs/scripts/verify-openspec-planning.sh <change>`.
Read context files, work through pending tasks, run each planned
Verification and mark a checkbox complete only after observed success.
Pause if you hit blockers or need clarification.
Feedback routing:
- intent/scope mismatch → Proposal;
- observable behavior mismatch → Delta Specs;
- architecture/rollback mismatch → Design;
- decomposition/ownership/coverage mismatch → Tasks.
Останови downstream work, сообщи наблюдаемое основание и инвалидируй
approvals начиная с самого раннего затронутого artifact. Только
механическое syntax/format исправление без изменения intent, behavior,
decisions или task scope можно исправить и повторно структурно проверить
без reapproval. Structural validation не заменяет semantic verification и
independent read-only review.
@@ -42,6 +42,17 @@
<!-- Delivery order and rollback, when applicable -->
### Rollback Contract
| Field | Decision |
| --- | --- |
| Status | `required` or `N/A` |
| Reason | <!-- concrete reason when N/A --> |
| Trigger | <!-- required when Status is required --> |
| Actions | <!-- required when Status is required --> |
| Data safety | <!-- required when Status is required --> |
| Verification | <!-- required when Status is required --> |
## Open Questions
<!-- Only questions that cannot change Specs, approach or Tasks; otherwise
@@ -1,9 +1,17 @@
## 1. <!-- Task Group Name -->
## 1. <!-- Dependency-ordered task group -->
- [ ] 1.1 <!-- Concrete implementation action and its planned verification -->
- [ ] 1.2 <!-- Concrete implementation action and its planned verification -->
- [ ] 1.1 [area] <!-- Concrete implementation action -->
- **Covers:** `<capability-path>` — `<exact Requirement heading>`
- **Verification:** <!-- Planned command, observable check or delivered artifact -->
- [ ] 1.2 [area] <!-- Concrete implementation action -->
- **Covers:** `N/A` — <!-- Concrete reason this task has no spec-level behavior -->
- **Verification:** <!-- Planned command, observable check or delivered artifact -->
## 2. <!-- Task Group Name -->
## 2. <!-- Affected repository delivery and gates -->
- [ ] 2.1 <!-- Affected repository action and canonical local gate -->
- [ ] 2.2 <!-- Cross-area verification when required -->
- [ ] 2.1 [area] <!-- Affected repository action -->
- **Covers:** `<capability-path>` — `<exact Requirement heading>`
- **Verification:** <!-- Canonical local gate -->
- [ ] 2.2 [workspace] <!-- Cross-area orchestration or verification only -->
- **Covers:** `N/A` — <!-- Concrete orchestration/verification reason -->
- **Verification:** <!-- Cross-area gate or semantic review -->
@@ -7,20 +7,29 @@
## Requirements
### Requirement: Реестр remediation отделён от снимка аудита
Система SHALL создавать отдельный неизменяемый versioned audit snapshot в `docs/audits` для каждого завершённого аудита и SHALL поддерживать один актуальный durable remediation registry в `docs/development`, охватывающий findings всех audit snapshots. Каждый snapshot SHALL оставаться source of facts своего аудита и MUST NOT редактироваться для отражения последующей remediation. Registry SHALL хранить текущее состояние, связанный canonical change, следующее действие и completion evidence каждой записи, MUST ссылаться на однозначный Audit ID и исходный snapshot и MUST NOT дублировать полный текст finding, если он уже содержится в snapshot.
Система SHALL создавать отдельный неизменяемый versioned audit snapshot в `docs/audits` для каждого завершённого аудита и SHALL поддерживать один актуальный durable remediation registry в `docs/development`, охватывающий findings всех audit snapshots. Для завершённого multi-source audit система SHALL сохранять каждый source file byte-for-byte и объединять их одним snapshot index. Каждый snapshot SHALL оставаться source of claims своего аудита и MUST NOT редактироваться для отражения последующей remediation. Внешняя модельная оценка MUST быть обозначена как неавторитетный источник claims и MUST NOT подменять requirements, governance или проверенное состояние проекта. Registry SHALL хранить текущее состояние, связанный canonical change, следующее действие и completion evidence каждой записи, MUST ссылаться на однозначный Audit ID и каждый относящийся source snapshot и MUST NOT дублировать полный текст finding, если он уже содержится в snapshot.
#### Scenario: Агент открывает работу по аудиту в новой сессии
- **WHEN** агент получает задачу устранить или продолжить finding из любого завершённого аудита
- **THEN** он находит в едином registry исходный snapshot и Audit ID, текущий статус, связанный OpenSpec change, evidence и следующее действие без повторной интерпретации всех аудитов
#### Scenario: Проводится повторный аудит
- **WHEN** новый аудит завершён после предыдущего audit snapshot
- **THEN** система добавляет новый immutable snapshot и обновляет тот же live registry, не переписывая предыдущий snapshot и не создавая конкурирующий registry
#### Scenario: Обновляется прогресс remediation
- **WHEN** работа по finding меняет статус
- **THEN** versioned audit snapshots не редактируются, а изменение фиксируется только в live registry с датой и необходимым evidence
#### Scenario: Один аудит содержит несколько внешних оценок
- **WHEN** завершённая assessment использовала несколько независимых source reports
- **THEN** snapshot index связывает byte-for-byte сохранённые reports в один audit и явно отделяет их claims от project authority
### Requirement: Registry задаёт однозначный статус и следующий change
Каждая audit-derived запись SHALL иметь ровно один статус из `planned`, `active`, `done`, `deferred` или `accepted`. `planned` MUST означать согласованную работу, которую можно начать без внешнего review trigger; запись, ожидающая версии зависимости, внешнего события или отдельного решения владельца, MUST иметь статус `deferred` с условием пересмотра. Registry MUST содержать не более одного `active` remediation change и ровно одну следующую рекомендуемую задачу, пока существуют findings со статусом `planned`.
@@ -46,3 +55,22 @@ Registry SHALL NOT представлять finding как `done` без дат
#### Scenario: Риск сознательно не исправляется сейчас
- **WHEN** владелец переносит finding или принимает риск
- **THEN** registry сохраняет причину решения и условия, при которых оно должно быть пересмотрено
### Requirement: Каждое audit claim получает доказательный disposition
Каждое уникальное claim завершённого multi-source audit MUST входить ровно в один нормализованный Audit ID и иметь triage disposition `confirmed`, `already-covered`, `rejected` или `deferred`. Нормализованная запись MUST ссылаться на каждый source report, содержащий claim. `confirmed` MUST связываться с remediation status и change либо terminal evidence; `already-covered` MUST приводить проверяемое существующее evidence; `rejected` MUST содержать конкретное rationale; `deferred` MUST содержать review trigger. Triage disposition MUST оставаться отдельным от remediation status `planned`, `active`, `done`, `deferred` или `accepted`, чтобы внешняя рекомендация не становилась принятой policy без проверки.
#### Scenario: Несколько моделей повторяют одно замечание
- **WHEN** два или более source reports описывают один и тот же underlying gap
- **THEN** registry содержит один нормализованный Audit ID со ссылками на все источники и одним доказательным disposition
#### Scenario: Рекомендация уже реализована
- **WHEN** проверяемое состояние проекта полностью покрывает external claim
- **THEN** disposition `already-covered` ссылается на существующий requirement, guardrail или completion evidence без создания фиктивной remediation work
#### Scenario: Внешняя рекомендация противоречит authority
- **WHEN** source report предлагает неподдерживаемый либо ухудшающий действующий invariant подход
- **THEN** disposition `rejected` фиксирует конкретное противоречие и не превращает recommendation в requirement
@@ -67,3 +67,22 @@
- **WHEN** change объявляет новое правило блокирующим
- **THEN** completion evidence подтверждает как успешный compliant case, так и обнаружение контролируемого representative violation
### Requirement: Труднообратимое изменение имеет rollback contract
Design MUST определять rollback trigger, rollback actions, data safety и rollback verification, когда change затрагивает auth или security behavior, data integrity или migration, public contract либо другое существенно труднообратимое решение. Rollback contract MUST учитывать данные и совместимость, созданные после поставки change, и MUST быть выполним без нового неутверждённого архитектурного решения. Когда указанные риски неприменимы, Design SHALL фиксировать конкретную проверяемую причину `N/A` и MUST NOT создавать отдельный artifact или формальный rollback plan ради процесса.
#### Scenario: Change мигрирует данные
- **WHEN** Design изменяет хранимые данные способом, который может потребовать возврата
- **THEN** он определяет trigger, безопасные действия отката, судьбу новых данных и проверку восстановленного состояния до утверждения Tasks
#### Scenario: Change меняет публичный контракт
- **WHEN** Design вводит несовместимое изменение публичного контракта
- **THEN** rollback contract объясняет восстановление совместимости и проверяемое условие успешного отката
#### Scenario: Rollback risk отсутствует
- **WHEN** change не затрагивает auth, security, данные, публичный контракт или другое труднообратимое решение
- **THEN** Design указывает конкретную причину `N/A` без создания дополнительного rollback artifact
@@ -61,3 +61,41 @@ Workspace SHALL предоставлять один non-mutating локальн
- **WHEN** общий verifier проверяет несколько affected областей и канонический gate одной из них не проходит
- **THEN** общий результат является неуспешным и явно указывает failing area без обхода её локального gate
### Requirement: Каждая задача объявляет единственную delivery area
Каждый checkbox Tasks MUST объявлять ровно одного owner из `frontend`, `backend`, `specs`, `docs` или `workspace`. Implementation work, изменяющая несколько Git-репозиториев, MUST быть разделена на repository-owned tasks; `workspace` SHALL использоваться только для cross-area orchestration или verification без владения repository implementation. Для каждой `affected` area Tasks MUST содержать её implementation work и canonical local gate, а task ownership MUST соответствовать утверждённому Delivery Map.
#### Scenario: Change затрагивает frontend и backend
- **WHEN** одна delivery intent требует изменения клиента и API
- **THEN** Tasks содержит отдельные frontend-owned и backend-owned checkbox items вместо одной общей implementation task
#### Scenario: Выполняется общий verification gate
- **WHEN** задача только оркестрирует проверку нескольких affected areas и не изменяет их implementation
- **THEN** task использует owner `workspace` и не подменяет repository-owned implementation или canonical gates
#### Scenario: Task ссылается на N/A area
- **WHEN** checkbox объявляет owner области, которая имеет статус `N/A` в Delivery Map
- **THEN** planning validation завершается ошибкой и указывает несогласованную delivery area
### Requirement: Tasks трассируются к утверждённым требованиям
Каждый checkbox Tasks MUST содержать coverage reference: одну или несколько пар из точного capability path и точного Requirement heading либо `N/A` с конкретной причиной для работы, которая не реализует spec-level behavior. Каждый Requirement из Delta Specs MUST быть покрыт хотя бы одной task. Planning validation MUST отклонять отсутствующее покрытие, ссылку на несуществующий capability или Requirement и пустую причину `N/A`. Traceability SHALL использовать нативную идентичность requirement и MUST NOT вводить параллельный namespace собственных requirement IDs.
#### Scenario: Delta requirement покрыт реализацией
- **WHEN** Tasks планирует поставку изменённого requirement
- **THEN** хотя бы один checkbox ссылается на точный capability path и Requirement heading этого delta
#### Scenario: Задача не меняет spec-level behavior
- **WHEN** task обновляет infrastructure, documentation или verification без самостоятельного requirement
- **THEN** coverage reference содержит `N/A` и конкретно объясняет отсутствие spec-level связи
#### Scenario: Requirement остался без задачи
- **WHEN** хотя бы один Requirement из Delta Specs не указан ни в одной coverage reference
- **THEN** planning validation блокирует approval Tasks и перечисляет uncovered Requirement
@@ -35,7 +35,7 @@ Versioned SDD change SHALL проходить последовательност
### Requirement: Изменение upstream artifact требует каскадной проверки
Изменение утверждённого Proposal MUST инициировать повторную проверку Delta Specs, Design и Tasks; изменение утверждённых Delta Specs MUST инициировать повторную проверку Design и Tasks; изменение утверждённого Design MUST инициировать повторную проверку Tasks. Изменение Tasks MUST NOT неявно менять scope, наблюдаемое поведение или архитектурные решения upstream artifacts; при таком обнаружении workflow SHALL вернуть работу к соответствующему upstream artifact и его approval gate.
Изменение утверждённого Proposal MUST инициировать повторную проверку Delta Specs, Design и Tasks; изменение утверждённых Delta Specs MUST инициировать повторную проверку Design и Tasks; изменение утверждённого Design MUST инициировать повторную проверку Tasks. Изменение Tasks MUST NOT неявно менять scope, наблюдаемое поведение или архитектурные решения upstream artifacts; при таком обнаружении workflow SHALL вернуть работу к самому раннему затронутому upstream artifact и его approval gate. Если несоответствие обнаружено во время Design или Apply, downstream-работа MUST остановиться, а Change Owner MUST получить наблюдаемое основание возврата и решения, требуемые на выбранном уровне. Механическое исправление синтаксиса или формата, которое не меняет утверждённые намерение, поведение, архитектурные решения или состав задач, MUST пройти повторную structural validation и MUST NOT само по себе инвалидировать approvals.
#### Scenario: После Design изменилось намерение
@@ -47,6 +47,16 @@ Versioned SDD change SHALL проходить последовательност
- **WHEN** implementation checklist требует поведение, которого нет в утверждённых Delta Specs
- **THEN** агент не расширяет scope через Tasks и возвращает change к Delta Specs
#### Scenario: Apply выявляет архитектурное расхождение
- **WHEN** во время реализации обнаружено, что утверждённый Design не позволяет выполнить Specs без другого архитектурного решения
- **THEN** Apply останавливается, Tasks теряет прежнее подтверждение, а change возвращается к Design с наблюдаемым основанием и вариантами решения
#### Scenario: Исправляется только структурный формат
- **WHEN** утверждённый artifact содержит исправимую синтаксическую или formatting-ошибку без изменения его смысла
- **THEN** workflow исправляет ошибку, повторяет structural validation и сохраняет действующие approvals
### Requirement: Канонический authority OpenSpec задан явно
WealthLedger SHALL использовать зарегистрированный store `wealth-ledger-specs` с физическим OpenSpec root `specs/openspec` как единственный поддерживаемый authority для versioned SDD artifacts. Каждый project-owned OpenSpec entrypoint и documented OpenSpec command MUST явно выбирать `--store wealth-ledger-specs`; он MUST NOT выбирать store из ближайшего root, текущей директории или глобального значения по умолчанию машины.
@@ -82,7 +92,7 @@ Canonical store и policy расположения artifacts SHALL иметь do
### Requirement: OpenSpec tooling имеет проверяемый version contract
SDD workflow MUST объявлять поддерживаемую версию OpenSpec CLI и проверять фактическую версию до команд, читающих или изменяющих canonical change. Несовместимая либо неопределённая версия MUST давать actionable blocking result и MUST NOT приводить к молчаливому изменению artifact graph, templates или project-owned entrypoints.
SDD workflow MUST объявлять одну текущую поддерживаемую версию OpenSpec CLI в canonical version contract и проверять фактическую версию до команд, читающих или изменяющих canonical change. Normative checks и проверяемые generated markers MUST получать ожидаемую версию из этого контракта и MUST NOT независимо закреплять конкретный version literal. Несовместимая либо неопределённая версия MUST давать actionable blocking result и MUST NOT приводить к молчаливому изменению artifact graph, templates или project-owned entrypoints. Публикация новой stable версии MUST NOT автоматически менять поддерживаемую версию проекта. Upgrade SHALL изменять version contract только после изолированной проверки совместимости schema, agent workflow, canonical store и hard blockers и SHALL сохранять историческое evidence с фактически использованными ранее версиями.
#### Scenario: Версия CLI соответствует контракту
@@ -94,6 +104,16 @@ SDD workflow MUST объявлять поддерживаемую версию O
- **WHEN** доступная версия OpenSpec не совпадает с объявленным совместимым контрактом
- **THEN** локальная preflight-проверка блокирует SDD-операцию и сообщает ожидаемую и фактическую версии
#### Scenario: Опубликована новая stable версия
- **WHEN** upstream публикует новую stable версию, которая ещё не прошла project compatibility assessment
- **THEN** текущий version contract остаётся действующим и новая версия не становится неявным требованием для разработки
#### Scenario: Подготовлен upgrade candidate
- **WHEN** Engineering Owner рассматривает смену поддерживаемой версии
- **THEN** изолированная проверка подтверждает schema, agent workflow, store selection и hard blockers до изменения version contract и project-owned projection
### Requirement: Structural и semantic verification являются разными gates
OpenSpec structural validation SHALL проверять schema, artifact graph и формальную корректность specs, но MUST NOT считаться доказательством соответствия реализации. До terminal status change MUST пройти semantic verification реализации против Proposal, Delta Specs, Design и Tasks, а затем независимый read-only review. Если основной agent entrypoint semantic verification недоступен, workflow SHALL использовать versioned эквивалентную процедуру с теми же входными артефактами, категориями проверки и наблюдаемым evidence.
@@ -122,3 +142,31 @@ Project-owned archive workflow MUST отклонять archive, если отс
#### Scenario: Change завершил все tasks
- **WHEN** каждый planning artifact утверждён, каждый task отмечен, required verification, implementation и pre-archive gates всех affected areas успешно завершены
- **THEN** workflow допускает archive и фиксирует его результат через определённый completion-evidence path без создания post-archive task
### Requirement: Project-owned agent workflow воспроизводим из versioned authority
Project-owned agent workflow SHALL восстанавливаться в новом workspace из committed authority inputs и текущей поддерживаемой версии инструмента без использования прежнего локального generated state. Workspace-level projection SHALL оставаться derived output и MUST NOT становиться конкурирующим SDD authority. Non-mutating verifier MUST обнаруживать отсутствие required projection, расхождение с versioned inputs и несовместимый generated version marker; установленные зависимости и machine-local runtime state MUST NOT считаться authority inputs.
#### Scenario: Workspace собирается заново
- **WHEN** участник получает чистые checkout всех project repositories и поддерживаемый инструмент
- **THEN** documented workflow воспроизводит project-owned agent projection из versioned inputs без копирования файлов с прежней машины
#### Scenario: Derived projection изменена вручную
- **WHEN** локальная project-owned projection больше не соответствует versioned authority inputs
- **THEN** non-mutating verifier завершает проверку ошибкой и указывает на projection drift
### Requirement: Planning artifact проверяется до запроса approval
Каждый создаваемый planning artifact SHALL пройти все применимые на его текущем этапе non-mutating structural checks до запроса approval Change Owner. Если полный change validation ещё заблокирован отсутствующими downstream artifacts, workflow MUST выполнить доступные проверки текущего artifact и явно оставить недоступную проверку незавершённой, а не заявлять общий успех. Техническая ошибка проверяемого формата SHALL исправляться и проверяться повторно без передачи ручного исправления Change Owner; structural success MUST NOT подменять semantic approval.
#### Scenario: Текущий artifact имеет проверяемое нарушение
- **WHEN** сгенерированный planning artifact нарушает обязательный формат или ссылочную целостность, доступные для проверки на текущем этапе
- **THEN** workflow исправляет нарушение и повторяет structural checks до запроса owner approval
#### Scenario: Downstream artifacts ещё отсутствуют
- **WHEN** Proposal создан, а Delta Specs, Design и Tasks ещё не существуют
- **THEN** workflow сообщает результат доступных Proposal checks и не представляет отсутствующую full-change validation как успешную
+125
View File
@@ -0,0 +1,125 @@
#!/usr/bin/env bash
wl_area_index() {
case "$1" in
frontend) printf '0' ;;
backend) printf '1' ;;
specs) printf '2' ;;
docs) printf '3' ;;
*) return 1 ;;
esac
}
wl_trim() {
local value=$1
value=${value#"${value%%[![:space:]]*}"}
value=${value%"${value##*[![:space:]]}"}
printf '%s' "$value"
}
wl_parse_delivery_map() {
local metadata_file=$1
local design_file=$2
local raw_area raw_status raw_reason area status reason gate index
wl_areas=(frontend backend specs docs)
wl_affected_flags=(0 0 0 0)
wl_map_statuses=('' '' '' '')
wl_map_reasons=('' '' '' '')
wl_contract_status=''
wl_contract_reason=''
while IFS= read -r area; do
[[ -n "$area" ]] || continue
if ! index=$(wl_area_index "$area"); then
printf 'Unknown affected area in metadata: %s\n' "$area" >&2
return 1
fi
if [[ "${wl_affected_flags[$index]}" -eq 1 ]]; then
printf 'Duplicate affected area in metadata: %s\n' "$area" >&2
return 1
fi
wl_affected_flags[$index]=1
done < <(
awk '
$0 == "affected_areas:" { in_areas = 1; next }
in_areas && /^ - / { sub(/^ - /, ""); print; next }
in_areas { exit }
' "$metadata_file"
)
if [[ "${wl_affected_flags[2]}" -ne 1 ]]; then
printf 'Delivery Map violation: specs must be affected for every versioned change.\n' >&2
return 1
fi
while IFS='|' read -r _ raw_area raw_status raw_reason _; do
area=$(wl_trim "$raw_area")
case "$area" in
frontend|backend|specs|docs) ;;
*) continue ;;
esac
index=$(wl_area_index "$area")
if [[ -n "${wl_map_statuses[$index]}" ]]; then
printf 'Delivery Map contains duplicate row for %s.\n' "$area" >&2
return 1
fi
status=$(wl_trim "$raw_status")
status=${status//\`/}
reason=$(wl_trim "$raw_reason")
wl_map_statuses[$index]=$status
wl_map_reasons[$index]=$reason
done < "$design_file"
while IFS='|' read -r _ raw_area raw_status raw_reason _; do
gate=$(wl_trim "$raw_area")
[[ "$gate" == 'runtime-openapi' ]] || continue
if [[ -n "$wl_contract_status" ]]; then
printf 'Contract Gate Decision contains duplicate runtime-openapi row.\n' >&2
return 1
fi
wl_contract_status=$(wl_trim "$raw_status")
wl_contract_status=${wl_contract_status//\`/}
wl_contract_reason=$(wl_trim "$raw_reason")
done < "$design_file"
for index in 0 1 2 3; do
area=${wl_areas[$index]}
status=${wl_map_statuses[$index]}
reason=${wl_map_reasons[$index]}
if [[ -z "$status" ]]; then
printf 'Delivery Map is missing area: %s\n' "$area" >&2
return 1
fi
if [[ "${wl_affected_flags[$index]}" -eq 1 ]]; then
if [[ "$status" != 'affected' ]]; then
printf 'Delivery Map mismatch: %s is listed as affected in metadata but has status %s.\n' "$area" "$status" >&2
return 1
fi
elif [[ "$status" != 'N/A' ]]; then
printf 'Delivery Map mismatch: %s is absent from affected_areas but has status %s.\n' "$area" "$status" >&2
return 1
fi
if [[ -z "$reason" || "$reason" == '-' || "$reason" == '—' || "$reason" == *'<!--'* ]]; then
printf 'Delivery Map requires a concrete outcome or N/A reason for %s.\n' "$area" >&2
return 1
fi
done
if [[ -z "$wl_contract_status" ]]; then
printf 'Contract Gate Decision is missing runtime-openapi.\n' >&2
return 1
fi
if [[ "$wl_contract_status" != 'required' && "$wl_contract_status" != 'N/A' ]]; then
printf 'Invalid runtime-openapi decision: %s. Expected required or N/A.\n' "$wl_contract_status" >&2
return 1
fi
if [[ -z "$wl_contract_reason" || "$wl_contract_reason" == '-' || "$wl_contract_reason" == '—' || "$wl_contract_reason" == *'<!--'* ]]; then
printf 'Contract Gate Decision requires a concrete runtime-openapi reason.\n' >&2
return 1
fi
if [[ "$wl_contract_status" == 'required' && ( "${wl_affected_flags[0]}" -ne 1 || "${wl_affected_flags[1]}" -ne 1 ) ]]; then
printf 'runtime-openapi cannot be required unless frontend and backend are affected.\n' >&2
return 1
fi
}
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
workspace=${WEALTH_LEDGER_WORKSPACE:-$(cd "$script_dir/../.." && pwd -P)}
source_root="$workspace/specs/agent-projection/opencode"
projection_root="$workspace/.opencode"
for tree in commands skills; do
if [[ ! -d "$source_root/$tree" ]]; then
printf 'Missing canonical projection tree: %s\n' "${source_root#$workspace/}/$tree" >&2
exit 1
fi
done
mkdir -p "$projection_root"
stage=$(mktemp -d "$projection_root/.projection-stage.XXXXXX")
backup=$(mktemp -d "$projection_root/.projection-backup.XXXXXX")
commands_existed=0
skills_existed=0
cutover_started=0
cleanup_temporary() {
rm -rf "$stage" "$backup"
}
rollback() {
if [[ $cutover_started -eq 1 ]]; then
rm -rf "$projection_root/commands" "$projection_root/skills"
if [[ $commands_existed -eq 1 && -d "$backup/commands" ]]; then
mv "$backup/commands" "$projection_root/commands"
fi
if [[ $skills_existed -eq 1 && -d "$backup/skills" ]]; then
mv "$backup/skills" "$projection_root/skills"
fi
fi
cleanup_temporary
}
trap rollback EXIT
cp -R "$source_root/commands" "$stage/commands"
cp -R "$source_root/skills" "$stage/skills"
if [[ -d "$projection_root/commands" ]]; then
commands_existed=1
cp -R "$projection_root/commands" "$backup/commands"
fi
if [[ "${WEALTH_LEDGER_SYNC_FAIL_DURING_BACKUP:-0}" == '1' ]]; then
printf 'Injected projection backup failure; local projection was not modified.\n' >&2
exit 1
fi
if [[ -d "$projection_root/skills" ]]; then
skills_existed=1
cp -R "$projection_root/skills" "$backup/skills"
fi
cutover_started=1
rm -rf "$projection_root/commands" "$projection_root/skills"
if ! mv "$stage/commands" "$projection_root/commands"; then
printf 'Projection sync failed while installing commands; previous state will be restored.\n' >&2
exit 1
fi
if [[ "${WEALTH_LEDGER_SYNC_FAIL_AFTER_COMMANDS:-0}" == '1' ]]; then
printf 'Injected projection sync failure after commands; previous state will be restored.\n' >&2
exit 1
fi
if ! mv "$stage/skills" "$projection_root/skills"; then
printf 'Projection sync failed while installing skills; previous state will be restored.\n' >&2
exit 1
fi
if ! WEALTH_LEDGER_WORKSPACE="$workspace" bash "$script_dir/verify-agent-projection.sh"; then
printf 'Projection verification failed after cutover; previous state will be restored.\n' >&2
exit 1
fi
cutover_started=0
trap - EXIT
cleanup_temporary
printf 'Agent projection synchronized from specs authority.\n'
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
workspace=${WEALTH_LEDGER_WORKSPACE:-$(cd "$script_dir/../.." && pwd -P)}
source_root="$workspace/specs/agent-projection/opencode"
projection_root="$workspace/.opencode"
version_file="$workspace/specs/openspec/.cli-version"
failures=0
fail() {
printf 'FAIL: %s\n' "$1" >&2
failures=$((failures + 1))
}
if [[ ! -f "$version_file" ]]; then
fail 'missing OpenSpec version contract: specs/openspec/.cli-version'
expected_version=''
else
expected_version=$(tr -d '[:space:]' < "$version_file")
[[ -n "$expected_version" ]] || fail 'OpenSpec version contract is empty'
fi
for tree in commands skills; do
source_tree="$source_root/$tree"
projection_tree="$projection_root/$tree"
if [[ ! -d "$source_tree" ]]; then
fail "missing canonical projection tree: specs/agent-projection/opencode/$tree"
continue
fi
if [[ ! -d "$projection_tree" ]]; then
fail "missing projection directory: .opencode/$tree"
continue
fi
while IFS= read -r source_file; do
relative_path=${source_file#"$source_root/"}
projection_file="$projection_root/$relative_path"
if [[ ! -f "$projection_file" ]]; then
fail "missing projection file: $relative_path"
elif ! cmp -s "$source_file" "$projection_file"; then
fail "projection content drift: $relative_path"
fi
if [[ "$relative_path" == skills/*/SKILL.md ]]; then
marker_count=$(awk -v expected="generatedBy: \"$expected_version\"" '
{
line = $0
sub(/^[[:space:]]*/, "", line)
if (line == expected) count++
}
END { print count + 0 }
' "$source_file")
if [[ "$marker_count" -ne 1 ]]; then
fail "generated version marker mismatch in $relative_path: expected $expected_version"
fi
fi
done < <(find "$source_tree" -type f | sort)
while IFS= read -r projection_file; do
relative_path=${projection_file#"$projection_root/"}
if [[ ! -f "$source_root/$relative_path" ]]; then
fail "unexpected projection file: $relative_path"
fi
done < <(find "$projection_tree" -type f | sort)
done
if [[ $failures -gt 0 ]]; then
exit 1
fi
printf 'Agent projection verified against versioned authority: OpenSpec %s\n' "$expected_version"
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
verifier="$script_dir/verify-agent-projection.sh"
syncer="$script_dir/sync-agent-projection.sh"
contract_version=$(tr -d '[:space:]' < "$script_dir/../openspec/.cli-version")
if [[ ! -x "$verifier" ]]; then
printf 'expected executable projection verifier at %s\n' "$verifier" >&2
exit 1
fi
if [[ ! -x "$syncer" ]]; then
printf 'expected executable projection sync at %s\n' "$syncer" >&2
exit 1
fi
fixture=$(mktemp -d)
trap 'rm -rf "$fixture"' EXIT
mkdir -p "$fixture/specs/openspec" \
"$fixture/specs/agent-projection/opencode/commands" \
"$fixture/specs/agent-projection/opencode/skills/example" \
"$fixture/.opencode"
printf '%s\n' "$contract_version" > "$fixture/specs/openspec/.cli-version"
printf 'command authority\n' > "$fixture/specs/agent-projection/opencode/commands/example.md"
printf '%s\n' '---' 'name: example' 'metadata:' " generatedBy: \"$contract_version\"" '---' > "$fixture/specs/agent-projection/opencode/skills/example/SKILL.md"
printf '{"private":true}\n' > "$fixture/.opencode/package.json"
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$syncer"
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier"
[[ -f "$fixture/.opencode/package.json" ]]
printf 'manual drift\n' >> "$fixture/.opencode/commands/example.md"
if output=$(WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier" 2>&1); then
printf 'expected content drift to fail projection verification\n' >&2
exit 1
fi
[[ "$output" == *'projection content drift: commands/example.md'* ]]
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$syncer"
rm "$fixture/.opencode/skills/example/SKILL.md"
if output=$(WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier" 2>&1); then
printf 'expected missing projection file to fail verification\n' >&2
exit 1
fi
[[ "$output" == *'missing projection file: skills/example/SKILL.md'* ]]
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$syncer"
printf 'unexpected\n' > "$fixture/.opencode/commands/unexpected.md"
if output=$(WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier" 2>&1); then
printf 'expected extra projection file to fail verification\n' >&2
exit 1
fi
[[ "$output" == *'unexpected projection file: commands/unexpected.md'* ]]
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$syncer"
perl -0pi -e 's/generatedBy: "1\.10\.0"/generatedBy: "9.9.9"/' "$fixture/specs/agent-projection/opencode/skills/example/SKILL.md"
if output=$(WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier" 2>&1); then
printf 'expected incompatible canonical marker to fail verification\n' >&2
exit 1
fi
[[ "$output" == *"generated version marker mismatch in skills/example/SKILL.md: expected $contract_version"* ]]
perl -0pi -e "s/generatedBy: \"9\\.9\\.9\"/generatedBy: \"$contract_version\"/" "$fixture/specs/agent-projection/opencode/skills/example/SKILL.md"
printf 'old command\n' > "$fixture/.opencode/commands/example.md"
printf '%s\n' '---' 'name: old' 'metadata:' " generatedBy: \"$contract_version\"" '---' > "$fixture/.opencode/skills/example/SKILL.md"
cp -R "$fixture/.opencode/commands" "$fixture/expected-commands"
cp -R "$fixture/.opencode/skills" "$fixture/expected-skills"
if WEALTH_LEDGER_WORKSPACE="$fixture" WEALTH_LEDGER_SYNC_FAIL_DURING_BACKUP=1 bash "$syncer"; then
printf 'expected injected backup failure\n' >&2
exit 1
fi
diff -r "$fixture/expected-commands" "$fixture/.opencode/commands"
diff -r "$fixture/expected-skills" "$fixture/.opencode/skills"
if WEALTH_LEDGER_WORKSPACE="$fixture" WEALTH_LEDGER_SYNC_FAIL_AFTER_COMMANDS=1 bash "$syncer"; then
printf 'expected injected sync failure\n' >&2
exit 1
fi
diff -r "$fixture/expected-commands" "$fixture/.opencode/commands"
diff -r "$fixture/expected-skills" "$fixture/.opencode/skills"
rm -rf "$fixture/.opencode/commands" "$fixture/.opencode/skills"
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$syncer"
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier"
printf 'verify-agent-projection tests passed\n'
+25 -1
View File
@@ -6,6 +6,7 @@ workspace=${WEALTH_LEDGER_WORKSPACE:-$(cd "$script_dir/../.." && pwd -P)}
failures=0
bash "$script_dir/verify-openspec-version.sh" "$workspace/specs/openspec/.cli-version"
expected_version=$(tr -d '[:space:]' < "$workspace/specs/openspec/.cli-version")
fail() {
printf 'FAIL: %s\n' "$1" >&2
@@ -57,11 +58,16 @@ require_file_contains "$config_file" 'schema: wealth-ledger-sdd'
schema_file="$canonical_root/schemas/wealth-ledger-sdd/schema.yaml"
require_file_contains "$schema_file" 'name: wealth-ledger-sdd'
require_file_contains "$schema_file" 'version: 2'
require_schema_edge "$schema_file" 'specs' 'proposal'
require_schema_edge "$schema_file" 'design' 'specs'
require_schema_edge "$schema_file" 'tasks' 'design'
require_file_contains "$schema_file" 'requires: [ tasks ]'
if ! projection_validation=$(WEALTH_LEDGER_WORKSPACE="$workspace" bash "$script_dir/verify-agent-projection.sh" 2>&1); then
fail "agent projection verification failed: $projection_validation"
fi
if [[ -d "$workspace/specs" ]]; then
if ! schema_validation=$(cd "$workspace/specs" && openspec schema validate wealth-ledger-sdd 2>&1); then
fail "wealth-ledger-sdd schema validation failed: $schema_validation"
@@ -140,7 +146,7 @@ skill_entrypoints=(
.opencode/skills/openspec-verify-change/SKILL.md
)
for relative_path in "${skill_entrypoints[@]}"; do
require_file_contains "$workspace/$relative_path" 'generatedBy: "1.10.0"'
require_file_contains "$workspace/$relative_path" "generatedBy: \"$expected_version\""
done
one_artifact_entrypoints=(
@@ -160,6 +166,24 @@ for relative_path in "${one_artifact_entrypoints[@]}"; do
fi
done
planning_entrypoints=(
.opencode/commands/opsx-apply.md
.opencode/commands/opsx-archive.md
.opencode/commands/opsx-continue.md
.opencode/commands/opsx-explore.md
.opencode/commands/opsx-propose.md
.opencode/commands/opsx-verify.md
.opencode/skills/openspec-apply-change/SKILL.md
.opencode/skills/openspec-archive-change/SKILL.md
.opencode/skills/openspec-continue-change/SKILL.md
.opencode/skills/openspec-explore/SKILL.md
.opencode/skills/openspec-propose/SKILL.md
.opencode/skills/openspec-verify-change/SKILL.md
)
for relative_path in "${planning_entrypoints[@]}"; do
require_file_contains "$workspace/$relative_path" 'bash specs/scripts/verify-openspec-planning.sh'
done
approval_blocker_entrypoints=(
.opencode/commands/opsx-apply.md
.opencode/commands/opsx-archive.md
+48 -6
View File
@@ -3,6 +3,7 @@ set -euo pipefail
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
verifier="$script_dir/verify-openspec-authority.sh"
contract_version=$(tr -d '[:space:]' < "$script_dir/../openspec/.cli-version")
if [[ ! -f "$verifier" ]]; then
echo "expected verifier at $verifier" >&2
@@ -21,7 +22,7 @@ write_file() {
write_file "specs/.openspec-store/store.yaml" $'version: 1\nid: wealth-ledger-specs'
mkdir -p "$fixture/specs/openspec"
write_file "specs/openspec/.cli-version" '1.10.0'
write_file "specs/openspec/.cli-version" "$contract_version"
write_file "specs/openspec/config.yaml" 'schema: wealth-ledger-sdd'
mkdir -p "$fixture/specs/openspec/schemas"
cp -R "$script_dir/../openspec/schemas/wealth-ledger-sdd" "$fixture/specs/openspec/schemas/wealth-ledger-sdd"
@@ -48,11 +49,12 @@ entrypoints=(
.opencode/skills/openspec-sync-specs/SKILL.md
.opencode/skills/openspec-verify-change/SKILL.md
)
planning_line='bash specs/scripts/verify-openspec-planning.sh "<change>"'
for path in "${entrypoints[@]}"; do
content=$'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs'
if [[ "$path" == .opencode/skills/* ]]; then
content=$'generatedBy: "1.10.0"\n'"$content"
content="generatedBy: \"$contract_version\""$'\n'"$content"
fi
if [[ "$path" == *continue* || "$path" == *explore* || "$path" == *propose* ]]; then
content="$content"$'\nCreate at most ONE planning artifact per invocation.\nSTOP for explicit Change Owner approval.'
@@ -60,6 +62,9 @@ for path in "${entrypoints[@]}"; do
if [[ "$path" == *apply* || "$path" == *archive* ]]; then
content="$content"$'\nRequire explicit Change Owner approval and invalidate dependent approvals after upstream edits.'
fi
if [[ "$path" != *new* && "$path" != *sync* ]]; then
content="$content"$'\n'"$planning_line"
fi
write_file "$path" "$content"
done
@@ -68,18 +73,25 @@ openspec status --store wealth-ledger-specs
Require affected delivery area gates, semantic verification and independent read-only review.
Require explicit Change Owner approval and invalidate dependent approvals after upstream edits.
Do not ask for or accept a confirmation override.'
archive_gate="$archive_gate"$'\n'"$planning_line"
write_file ".opencode/commands/opsx-archive.md" "$archive_gate"
write_file ".opencode/skills/openspec-archive-change/SKILL.md" $'generatedBy: "1.10.0"\n'"$archive_gate"
write_file ".opencode/skills/openspec-archive-change/SKILL.md" "generatedBy: \"$contract_version\""$'\n'"$archive_gate"
verification_gate='bash specs/scripts/verify-openspec-version.sh
openspec status --store wealth-ledger-specs
Check every affected delivery area with the workspace verifier and require independent read-only review.'
verification_gate="$verification_gate"$'\n'"$planning_line"
write_file ".opencode/commands/opsx-verify.md" "$verification_gate"
write_file ".opencode/skills/openspec-verify-change/SKILL.md" $'generatedBy: "1.10.0"\n'"$verification_gate"
write_file ".opencode/skills/openspec-verify-change/SKILL.md" "generatedBy: \"$contract_version\""$'\n'"$verification_gate"
apply_gate='bash specs/scripts/verify-openspec-version.sh
openspec status --store wealth-ledger-specs
Require explicit Change Owner approval and invalidate dependent approvals after upstream edits.'
apply_gate="$apply_gate"$'\n'"$planning_line"
mkdir -p "$fixture/specs/agent-projection/opencode"
cp -R "$fixture/.opencode/commands" "$fixture/specs/agent-projection/opencode/commands"
cp -R "$fixture/.opencode/skills" "$fixture/specs/agent-projection/opencode/skills"
run_verifier() {
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier"
@@ -87,12 +99,34 @@ run_verifier() {
run_verifier
rm "$fixture/specs/agent-projection/opencode/commands/opsx-apply.md"
if run_verifier; then
echo "expected missing canonical projection source to fail" >&2
exit 1
fi
cp "$fixture/.opencode/commands/opsx-apply.md" "$fixture/specs/agent-projection/opencode/commands/opsx-apply.md"
for path in \
.opencode/commands/opsx-propose.md \
specs/agent-projection/opencode/commands/opsx-propose.md; do
perl -0pi -e 's/^bash specs\/scripts\/verify-openspec-planning\.sh .*\n//m' "$fixture/$path"
done
if run_verifier; then
echo "expected missing planning gate in an artifact entrypoint to fail" >&2
exit 1
fi
for path in \
.opencode/commands/opsx-propose.md \
specs/agent-projection/opencode/commands/opsx-propose.md; do
printf '%s\n' "$planning_line" >> "$fixture/$path"
done
write_file "specs/openspec/.cli-version" '9.9.9'
if run_verifier; then
echo "expected wrong OpenSpec version contract to fail" >&2
exit 1
fi
write_file "specs/openspec/.cli-version" '1.10.0'
write_file "specs/openspec/.cli-version" "$contract_version"
write_file "specs/openspec/config.yaml" 'schema: spec-driven'
if run_verifier; then
@@ -101,6 +135,14 @@ if run_verifier; then
fi
write_file "specs/openspec/config.yaml" 'schema: wealth-ledger-sdd'
perl -0pi -e 's/^version: 2$/version: 1/m' "$fixture/specs/openspec/schemas/wealth-ledger-sdd/schema.yaml"
if run_verifier; then
echo "expected obsolete project schema version to fail" >&2
exit 1
fi
rm -rf "$fixture/specs/openspec/schemas/wealth-ledger-sdd"
cp -R "$script_dir/../openspec/schemas/wealth-ledger-sdd" "$fixture/specs/openspec/schemas/wealth-ledger-sdd"
write_file "specs/openspec/schemas/wealth-ledger-sdd/schema.yaml" $'name: wealth-ledger-sdd\nversion: 1'
if run_verifier; then
echo "expected incomplete project schema graph to fail" >&2
@@ -149,7 +191,7 @@ if run_verifier; then
echo "expected multi-artifact proposal guidance to fail" >&2
exit 1
fi
write_file ".opencode/commands/opsx-propose.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nCreate at most ONE planning artifact per invocation.\nSTOP for explicit Change Owner approval.'
write_file ".opencode/commands/opsx-propose.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nCreate at most ONE planning artifact per invocation.\nSTOP for explicit Change Owner approval.\n'"$planning_line"
write_file ".opencode/commands/opsx-archive.md" $'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs\nDon\x27t block archive on warnings - just inform and confirm.'
if run_verifier; then
+282
View File
@@ -0,0 +1,282 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
printf 'Usage: %s <change-name>\n' "${0##*/}" >&2
exit 2
fi
change=$1
if [[ ! "$change" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
printf 'Invalid OpenSpec change name: %s\n' "$change" >&2
exit 2
fi
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
workspace=${WEALTH_LEDGER_WORKSPACE:-$(cd "$script_dir/../.." && pwd -P)}
specs_root="$workspace/specs"
openspec_root="$specs_root/openspec"
change_dir="$openspec_root/changes/$change"
metadata_file="$change_dir/.openspec.yaml"
proposal_file="$change_dir/proposal.md"
design_file="$change_dir/design.md"
tasks_file="$change_dir/tasks.md"
# shellcheck source=lib/delivery-map.sh
source "$script_dir/lib/delivery-map.sh"
fail() {
printf 'Planning verification failed: %s\n' "$1" >&2
exit 1
}
require_file() {
[[ -f "$1" ]] || fail "missing ${1#$workspace/}"
}
require_heading() {
grep -Fqx -- "$2" "$1" || fail "${1#$workspace/} must contain heading: $2"
}
bash "$script_dir/verify-openspec-version.sh" "$openspec_root/.cli-version" >/dev/null
require_file "$metadata_file"
require_file "$proposal_file"
if ! grep -Fqx 'schema: wealth-ledger-sdd' "$metadata_file"; then
fail '.openspec.yaml must select schema wealth-ledger-sdd'
fi
if ! grep -Eq '^goal: .+' "$metadata_file"; then
fail '.openspec.yaml must contain a non-empty goal'
fi
if ! (cd "$specs_root" && openspec status --change "$change" --json --store wealth-ledger-specs >/dev/null); then
fail "change $change is not resolvable through canonical store wealth-ledger-specs"
fi
for heading in '## Why' '## What Changes' '## Capabilities' '### New Capabilities' '### Modified Capabilities' '## Impact'; do
require_heading "$proposal_file" "$heading"
done
temporary=$(mktemp -d)
trap 'rm -rf "$temporary"' EXIT
declared_capabilities="$temporary/declared-capabilities.tsv"
actual_capabilities="$temporary/actual-capabilities.txt"
delta_requirements="$temporary/delta-requirements.tsv"
covered_requirements="$temporary/covered-requirements.tsv"
: > "$declared_capabilities"
: > "$actual_capabilities"
: > "$delta_requirements"
: > "$covered_requirements"
awk '
/^### New Capabilities$/ { kind = "new"; next }
/^### Modified Capabilities$/ { kind = "modified"; next }
/^## / || /^### / { kind = "" }
kind != "" && /^- `[^`]+`:/ {
line = $0
sub(/^- `/, "", line)
sub(/`:.*/, "", line)
print kind "\t" line
}
' "$proposal_file" > "$declared_capabilities"
while IFS=$'\t' read -r kind capability; do
[[ -n "$capability" ]] || continue
if [[ "$capability" == /* || "$capability" == *'..'* || ! "$capability" =~ ^[a-z0-9]+([/-][a-z0-9]+)*$ ]]; then
fail "invalid capability path in Proposal: $capability"
fi
if [[ "$kind" == 'modified' && ! -f "$openspec_root/specs/$capability/spec.md" ]]; then
fail "modified capability does not exist in canonical specs: $capability"
fi
done < "$declared_capabilities"
skip_specs=0
if grep -Fqx 'skip_specs: true' "$metadata_file"; then
skip_specs=1
if [[ -s "$declared_capabilities" ]]; then
fail 'skip_specs: true cannot be combined with declared capabilities'
fi
fi
has_specs=0
if [[ -d "$change_dir/specs" ]] && find "$change_dir/specs" -type f -name spec.md -print -quit | grep -q .; then
[[ $skip_specs -eq 0 ]] || fail 'skip_specs: true cannot be combined with delta spec files'
has_specs=1
while IFS= read -r file; do
capability=${file#"$change_dir/specs/"}
capability=${capability%/spec.md}
printf '%s\n' "$capability" >> "$actual_capabilities"
awk -v capability="$capability" '/^### Requirement: / { sub(/^### Requirement: /, ""); print capability "\t" $0 }' "$file" >> "$delta_requirements"
done < <(find "$change_dir/specs" -type f -name spec.md | sort)
while IFS= read -r capability; do
if ! awk -F '\t' -v capability="$capability" '$2 == capability { found = 1 } END { exit(found ? 0 : 1) }' "$declared_capabilities"; then
fail "delta capability is absent from Proposal: $capability"
fi
done < "$actual_capabilities"
while IFS=$'\t' read -r _ capability; do
[[ -n "$capability" ]] || continue
grep -Fqx "$capability" "$actual_capabilities" || fail "Proposal capability has no delta spec: $capability"
done < "$declared_capabilities"
if ! (cd "$specs_root" && openspec validate "$change" --type change --strict --store wealth-ledger-specs >/dev/null); then
fail 'strict Delta Specs validation failed'
fi
elif [[ ! -s "$declared_capabilities" && $skip_specs -eq 0 ]]; then
fail 'Proposal must declare capabilities or .openspec.yaml must set skip_specs: true'
fi
has_design=0
if [[ -f "$design_file" ]]; then
has_design=1
[[ $has_specs -eq 1 || $skip_specs -eq 1 ]] || fail 'Design exists before Delta Specs'
for heading in '## Context' '## Goals / Non-Goals' '## Decisions' '## Delivery Map' '### Contract Gate Decision' '## Risks / Trade-offs' '## Migration Plan' '### Rollback Contract'; do
require_heading "$design_file" "$heading"
done
wl_parse_delivery_map "$metadata_file" "$design_file" || exit 1
rollback_status_count=$(awk -F'|' '$2 ~ /^[[:space:]]*Status[[:space:]]*$/ { count++ } END { print count + 0 }' "$design_file")
[[ "$rollback_status_count" -eq 1 ]] || fail 'Rollback Contract must contain exactly one Status row'
rollback_status=$(awk -F'|' '$2 ~ /^[[:space:]]*Status[[:space:]]*$/ { value=$3; gsub(/^[[:space:]`]+|[[:space:]`]+$/, "", value); print value }' "$design_file")
if [[ "$rollback_status" == 'N/A' ]]; then
rollback_reason=$(awk -F'|' '$2 ~ /^[[:space:]]*Reason[[:space:]]*$/ { value=$3; gsub(/^[[:space:]]+|[[:space:]]+$/, "", value); print value }' "$design_file")
[[ -n "$rollback_reason" && "$rollback_reason" != '-' && "$rollback_reason" != '—' && "$rollback_reason" != *'<!--'* ]] || fail 'Rollback Contract N/A requires a concrete Reason row'
elif [[ "$rollback_status" == 'required' ]]; then
for field in Trigger Actions 'Data safety' Verification; do
count=$(awk -F'|' -v field="$field" '$2 ~ "^[[:space:]]*" field "[[:space:]]*$" { count++ } END { print count + 0 }' "$design_file")
[[ "$count" -eq 1 ]] || fail "Rollback Contract required status needs exactly one $field row"
done
else
fail "Rollback Contract Status must be required or N/A, got: $rollback_status"
fi
fi
has_tasks=0
if [[ -f "$tasks_file" ]]; then
has_tasks=1
[[ $has_design -eq 1 ]] || fail 'Tasks exists before Design'
task_number=''
task_area=''
covers_count=0
verification_count=0
covers_is_na=0
task_count=0
area_task_counts=(0 0 0 0)
area_gate_counts=(0 0 0 0)
finalize_task() {
[[ -n "$task_number" ]] || return 0
[[ "$covers_count" -eq 1 ]] || fail "task $task_number must contain exactly one Covers line"
[[ "$verification_count" -eq 1 ]] || fail "task $task_number must contain exactly one Verification line"
if [[ "$task_area" == 'workspace' && "$covers_is_na" -ne 1 ]]; then
fail "workspace task $task_number must use a concrete N/A coverage rationale"
fi
}
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" == '- [ ] '* || "$line" == '- [x] '* || "$line" == '- [X] '* ]]; then
finalize_task
if [[ ! "$line" =~ ^-\ \[[\ xX]\]\ ([0-9]+\.[0-9]+)\ \[(frontend|backend|specs|docs|workspace)\]\ .+ ]]; then
fail "invalid task checkbox shape: $line"
fi
task_number=${BASH_REMATCH[1]}
task_area=${BASH_REMATCH[2]}
covers_count=0
verification_count=0
covers_is_na=0
task_count=$((task_count + 1))
if [[ "$task_area" != 'workspace' ]]; then
index=$(wl_area_index "$task_area")
if [[ "${wl_map_statuses[$index]}" != 'affected' ]]; then
fail "task $task_number uses $task_area, but Delivery Map marks it ${wl_map_statuses[$index]}"
fi
area_task_counts[$index]=$((area_task_counts[$index] + 1))
fi
continue
fi
if [[ "$line" == ' - **Covers:** '* ]]; then
[[ -n "$task_number" ]] || fail 'Covers metadata appears before a task'
covers_count=$((covers_count + 1))
payload=${line#' - **Covers:** '}
if [[ "$payload" == \`N/A\`\ —\ * ]]; then
reason=${payload#\`N/A\`\ —\ }
[[ -n "$reason" && "$reason" != '-' && "$reason" != '—' ]] || fail "task $task_number has empty N/A rationale"
covers_is_na=1
else
IFS=';' read -r -a references <<< "$payload"
for reference in "${references[@]}"; do
reference=$(wl_trim "$reference")
if ! grep -Eq '^`[^`]+` — `[^`]+`$' <<< "$reference"; then
fail "task $task_number has malformed requirement reference: $reference"
fi
clean=${reference//\`/}
capability=${clean%% — *}
requirement=${clean#* — }
key="$capability"$'\t'"$requirement"
if ! grep -Fqx "$key" "$delta_requirements"; then
fail "task $task_number has unknown requirement reference: $capability — $requirement"
fi
printf '%s\n' "$key" >> "$covered_requirements"
done
fi
continue
fi
if [[ "$line" == ' - **Verification:** '* ]]; then
[[ -n "$task_number" ]] || fail 'Verification metadata appears before a task'
verification_count=$((verification_count + 1))
verification=${line#' - **Verification:** '}
[[ -n "$verification" ]] || fail "task $task_number has empty Verification"
if [[ "$task_area" != 'workspace' ]]; then
index=$(wl_area_index "$task_area")
case "$task_area" in
frontend|backend|docs)
[[ "$verification" == *'npm run verify'* ]] && area_gate_counts[$index]=$((area_gate_counts[$index] + 1))
;;
specs)
if [[ "$verification" == *'strict change validation'* || "$verification" == *'openspec validate'* ]]; then
area_gate_counts[$index]=$((area_gate_counts[$index] + 1))
fi
;;
esac
fi
fi
done < "$tasks_file"
finalize_task
[[ "$task_count" -gt 0 ]] || fail 'Tasks contains no tracked checkboxes'
for index in 0 1 2 3; do
if [[ "${wl_affected_flags[$index]}" -eq 1 ]]; then
[[ "${area_task_counts[$index]}" -gt 0 ]] || fail "affected area ${wl_areas[$index]} has no owned task"
[[ "${area_gate_counts[$index]}" -gt 0 ]] || fail "affected area ${wl_areas[$index]} has no canonical gate in Verification"
fi
done
while IFS= read -r key; do
[[ -n "$key" ]] || continue
if ! grep -Fqx "$key" "$covered_requirements"; then
capability=${key%%$'\t'*}
requirement=${key#*$'\t'}
fail "uncovered Requirement: $capability — $requirement"
fi
done < "$delta_requirements"
requirement_count=$(wc -l < "$delta_requirements" | tr -d ' ')
printf 'Delta requirement coverage verified: %s/%s\n' "$requirement_count" "$requirement_count"
fi
if [[ $has_tasks -eq 1 ]]; then
printf 'Planning stage verified: tasks\n'
printf 'Full planning structure verified; semantic approval remains human.\n'
elif [[ $has_design -eq 1 ]]; then
printf 'Planning stage verified: design\n'
printf 'Full change validation pending: tasks\n'
elif [[ $has_specs -eq 1 ]]; then
printf 'Planning stage verified: specs\n'
printf 'Full change validation pending: design, tasks\n'
else
printf 'Planning stage verified: proposal\n'
printf 'Full change validation pending: specs, design, tasks\n'
fi
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
workspace=$(cd "$script_dir/../.." && pwd -P)
verifier="$script_dir/verify-openspec-planning.sh"
source_change="$workspace/specs/openspec/changes/harden-openspec-sdd-quality"
changes_root="$workspace/specs/openspec/changes"
prefix="planning-fixture-$$"
created_changes=('')
cleanup() {
local change
for change in "${created_changes[@]}"; do
[[ -n "$change" ]] || continue
rm -rf "$changes_root/$change"
done
}
trap cleanup EXIT
if [[ ! -x "$verifier" ]]; then
printf 'expected executable planning verifier at %s\n' "$verifier" >&2
exit 1
fi
make_change() {
local suffix=$1
fixture_change="$prefix-$suffix"
cp -R "$source_change" "$changes_root/$fixture_change"
created_changes+=("$fixture_change")
}
run_verifier() {
bash "$verifier" "$1"
}
expect_failure() {
local change=$1
local expected=$2
local output
if output=$(run_verifier "$change" 2>&1); then
printf 'expected planning verification to fail for %s\n' "$change" >&2
exit 1
fi
if [[ "$output" != *"$expected"* ]]; then
printf 'expected failure containing %q, got:\n%s\n' "$expected" "$output" >&2
exit 1
fi
}
make_change proposal
proposal_change=$fixture_change
rm -rf "$changes_root/$proposal_change/specs"
rm -f "$changes_root/$proposal_change/design.md" "$changes_root/$proposal_change/tasks.md"
proposal_output=$(run_verifier "$proposal_change")
[[ "$proposal_output" == *'Planning stage verified: proposal'* ]]
[[ "$proposal_output" == *'Full change validation pending: specs, design, tasks'* ]]
make_change skip-conflict
skip_conflict=$fixture_change
rm -rf "$changes_root/$skip_conflict/specs"
rm -f "$changes_root/$skip_conflict/design.md" "$changes_root/$skip_conflict/tasks.md"
printf 'skip_specs: true\n' >> "$changes_root/$skip_conflict/.openspec.yaml"
expect_failure "$skip_conflict" 'skip_specs: true cannot be combined with declared capabilities'
make_change specs
specs_change=$fixture_change
rm -f "$changes_root/$specs_change/design.md" "$changes_root/$specs_change/tasks.md"
specs_output=$(run_verifier "$specs_change")
[[ "$specs_output" == *'Planning stage verified: specs'* ]]
[[ "$specs_output" == *'Full change validation pending: design, tasks'* ]]
make_change capability-mismatch
capability_mismatch=$fixture_change
mv "$changes_root/$capability_mismatch/specs/audit-remediation-workflow" "$changes_root/$capability_mismatch/specs/not-declared"
expect_failure "$capability_mismatch" 'delta capability is absent from Proposal: not-declared'
make_change design
design_change=$fixture_change
rm -f "$changes_root/$design_change/tasks.md"
design_output=$(run_verifier "$design_change")
[[ "$design_output" == *'Planning stage verified: design'* ]]
[[ "$design_output" == *'Full change validation pending: tasks'* ]]
make_change required-rollback
required_rollback=$fixture_change
rm -f "$changes_root/$required_rollback/tasks.md"
perl -0pi -e 's/\| Status \| `N\/A` \|/| Status | `required` |/; s/(\| Verification \|)/| Trigger | Deployment fails the projection gate. |\n| Actions | Restore the previous projection. |\n| Data safety | No application data changes. |\n$1/' "$changes_root/$required_rollback/design.md"
required_output=$(run_verifier "$required_rollback")
[[ "$required_output" == *'Planning stage verified: design'* ]]
perl -0pi -e 's/^\| Data safety \|.*\n//m' "$changes_root/$required_rollback/design.md"
expect_failure "$required_rollback" 'Rollback Contract required status needs exactly one Data safety row'
make_change tasks
tasks_change=$fixture_change
tasks_output=$(run_verifier "$tasks_change")
[[ "$tasks_output" == *'Planning stage verified: tasks'* ]]
[[ "$tasks_output" == *'Delta requirement coverage verified: 9/9'* ]]
[[ "$tasks_output" == *'Full planning structure verified; semantic approval remains human.'* ]]
make_change invalid-area
invalid_area=$fixture_change
perl -0pi -e 's/\[specs\]/[frontend]/' "$changes_root/$invalid_area/tasks.md"
expect_failure "$invalid_area" 'task 1.1 uses frontend, but Delivery Map marks it N/A'
make_change unknown-reference
unknown_reference=$fixture_change
perl -0pi -e 's/`Planning artifact проверяется до запроса approval`/`Несуществующее требование`/' "$changes_root/$unknown_reference/tasks.md"
expect_failure "$unknown_reference" 'unknown requirement reference'
make_change uncovered-requirement
uncovered_requirement=$fixture_change
sed -i '' '/`audit-remediation-workflow` — `Каждое audit claim получает доказательный disposition`/s/`audit-remediation-workflow` — `Каждое audit claim получает доказательный disposition`/`audit-remediation-workflow` — `Реестр remediation отделён от снимка аудита`/' "$changes_root/$uncovered_requirement/tasks.md"
expect_failure "$uncovered_requirement" 'uncovered Requirement: audit-remediation-workflow — Каждое audit claim получает доказательный disposition'
make_change missing-metadata
missing_metadata=$fixture_change
perl -0pi -e 's/^ - \*\*Verification:\*\*.*\n//m' "$changes_root/$missing_metadata/tasks.md"
expect_failure "$missing_metadata" 'task 1.1 must contain exactly one Verification line'
make_change malformed-rollback
malformed_rollback=$fixture_change
sed -i '' '/| Status | `N\/A` |/d' "$changes_root/$malformed_rollback/design.md"
expect_failure "$malformed_rollback" 'Rollback Contract must contain exactly one Status row'
printf 'verify-openspec-planning tests passed\n'
+8 -127
View File
@@ -25,134 +25,14 @@ for required_file in "$metadata_file" "$design_file"; do
fi
done
areas=(frontend backend specs docs)
affected_flags=(0 0 0 0)
map_statuses=('' '' '' '')
map_reasons=('' '' '' '')
contract_status=''
contract_reason=''
# shellcheck source=lib/delivery-map.sh
source "$script_dir/lib/delivery-map.sh"
wl_parse_delivery_map "$metadata_file" "$design_file"
area_index() {
case "$1" in
frontend) printf '0' ;;
backend) printf '1' ;;
specs) printf '2' ;;
docs) printf '3' ;;
*) return 1 ;;
esac
}
while IFS= read -r area; do
[[ -n "$area" ]] || continue
if ! index=$(area_index "$area"); then
printf 'Unknown affected area in %s: %s\n' "${metadata_file#$workspace/}" "$area" >&2
exit 1
fi
if [[ "${affected_flags[$index]}" -eq 1 ]]; then
printf 'Duplicate affected area in %s: %s\n' "${metadata_file#$workspace/}" "$area" >&2
exit 1
fi
affected_flags[$index]=1
done < <(
awk '
$0 == "affected_areas:" { in_areas = 1; next }
in_areas && /^ - / { sub(/^ - /, ""); print; next }
in_areas { exit }
' "$metadata_file"
)
if [[ "${affected_flags[2]}" -ne 1 ]]; then
printf 'Delivery Map violation: specs must be affected for every versioned change.\n' >&2
exit 1
fi
trim() {
local value=$1
value=${value#"${value%%[![:space:]]*}"}
value=${value%"${value##*[![:space:]]}"}
printf '%s' "$value"
}
while IFS='|' read -r _ raw_area raw_status raw_reason _; do
area=$(trim "$raw_area")
case "$area" in
frontend|backend|specs|docs) ;;
*) continue ;;
esac
index=$(area_index "$area")
if [[ -n "${map_statuses[$index]}" ]]; then
printf 'Delivery Map contains duplicate row for %s.\n' "$area" >&2
exit 1
fi
status=$(trim "$raw_status")
status=${status//\`/}
reason=$(trim "$raw_reason")
map_statuses[$index]=$status
map_reasons[$index]=$reason
done < "$design_file"
while IFS='|' read -r _ raw_gate raw_status raw_reason _; do
gate=$(trim "$raw_gate")
[[ "$gate" == "runtime-openapi" ]] || continue
if [[ -n "$contract_status" ]]; then
printf 'Contract Gate Decision contains duplicate runtime-openapi row.\n' >&2
exit 1
fi
contract_status=$(trim "$raw_status")
contract_status=${contract_status//\`/}
contract_reason=$(trim "$raw_reason")
done < "$design_file"
for index in 0 1 2 3; do
area=${areas[$index]}
status=${map_statuses[$index]}
reason=${map_reasons[$index]}
if [[ -z "$status" ]]; then
printf 'Delivery Map is missing area: %s\n' "$area" >&2
exit 1
fi
if [[ "${affected_flags[$index]}" -eq 1 ]]; then
if [[ "$status" != "affected" ]]; then
printf 'Delivery Map mismatch: %s is listed as affected in metadata but has status %s.\n' "$area" "$status" >&2
exit 1
fi
if [[ -z "$reason" || "$reason" == "-" || "$reason" == "—" || "$reason" == *"<!--"* ]]; then
printf 'Delivery Map requires an architectural outcome for affected area %s.\n' "$area" >&2
exit 1
fi
else
if [[ "$status" != "N/A" ]]; then
printf 'Delivery Map mismatch: %s is absent from affected_areas but has status %s.\n' "$area" "$status" >&2
exit 1
fi
if [[ -z "$reason" || "$reason" == "-" || "$reason" == "—" || "$reason" == *"<!--"* ]]; then
printf 'Delivery Map requires a concrete N/A reason for %s.\n' "$area" >&2
exit 1
fi
fi
done
if [[ -z "$contract_status" ]]; then
printf 'Contract Gate Decision is missing runtime-openapi.\n' >&2
exit 1
fi
if [[ "$contract_status" != "required" && "$contract_status" != "N/A" ]]; then
printf 'Invalid runtime-openapi decision: %s. Expected required or N/A.\n' "$contract_status" >&2
exit 1
fi
if [[ -z "$contract_reason" || "$contract_reason" == "-" || "$contract_reason" == "—" || "$contract_reason" == *"<!--"* ]]; then
printf 'Contract Gate Decision requires a concrete runtime-openapi reason.\n' >&2
exit 1
fi
if [[ "$contract_status" == "required" ]]; then
if [[ "${affected_flags[0]}" -ne 1 || "${affected_flags[1]}" -ne 1 ]]; then
printf 'runtime-openapi cannot be required unless frontend and backend are affected.\n' >&2
exit 1
fi
fi
areas=("${wl_areas[@]}")
affected_flags=("${wl_affected_flags[@]}")
map_statuses=("${wl_map_statuses[@]}")
contract_status=$wl_contract_status
printf 'Delivery Map verified:'
for index in 0 1 2 3; do
@@ -169,6 +49,7 @@ run_gate() {
}
run_gate 'OpenSpec CLI contract' bash "$workspace/specs/scripts/verify-openspec-version.sh"
run_gate 'OpenSpec planning structure' bash "$workspace/specs/scripts/verify-openspec-planning.sh" "$change"
run_gate 'OpenSpec project schema' bash -c 'cd "$1" && openspec schema validate wealth-ledger-sdd' _ "$workspace/specs"
run_gate 'OpenSpec change validation' bash -c 'cd "$1" && openspec validate "$2" --type change --strict --store wealth-ledger-specs' _ "$workspace/specs" "$change"
run_gate 'OpenSpec main specs' bash -c 'cd "$1" && openspec validate --specs --strict --store wealth-ledger-specs' _ "$workspace/specs"