feat: harden OpenSpec SDD workflow
This commit is contained in:
@@ -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.
|
||||||
+46
@@ -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
|
||||||
+20
@@ -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
|
||||||
+39
@@ -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
|
||||||
+79
@@ -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
@@ -5,14 +5,5 @@ context: |
|
|||||||
Canonical OpenSpec authority — зарегистрированный store wealth-ledger-specs в specs/openspec.
|
Canonical OpenSpec authority — зарегистрированный store wealth-ledger-specs в specs/openspec.
|
||||||
Docs описывает только фактическое as-built состояние; устойчивые process policies находятся в docs/development.
|
Docs описывает только фактическое as-built состояние; устойчивые process policies находятся в docs/development.
|
||||||
Локальная разработка и verification выполняются под Node 22 без CI.
|
Локальная разработка и verification выполняются под Node 22 без CI.
|
||||||
|
Project artifacts объясняют решения по-русски; exact OpenSpec headings, tokens,
|
||||||
rules:
|
commands и normative keywords SHALL/MUST сохраняются на английском.
|
||||||
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.
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: wealth-ledger-sdd
|
name: wealth-ledger-sdd
|
||||||
version: 1
|
version: 2
|
||||||
description: WealthLedger SDD workflow - proposal → specs → design → tasks
|
description: WealthLedger SDD workflow - proposal → specs → design → tasks → apply
|
||||||
artifacts:
|
artifacts:
|
||||||
- id: proposal
|
- id: proposal
|
||||||
generates: proposal.md
|
generates: proposal.md
|
||||||
@@ -33,11 +33,22 @@ artifacts:
|
|||||||
behavior, so if behavior does not change, no spec should change either.
|
behavior, so if behavior does not change, no spec should change either.
|
||||||
Do not invent a requirement just to satisfy validation.
|
Do not invent a requirement just to satisfy validation.
|
||||||
|
|
||||||
MUST NOT включать технологии, библиотеки, API signatures, имена файлов,
|
Artifact boundary — MUST NOT include:
|
||||||
зависимости, классы или пошаговую реализацию. Эти решения появляются
|
- технологии, библиотеки, зависимости или выбранную архитектуру: эти
|
||||||
только после Delta Specs в Design.
|
решения появляются только после 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.
|
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: []
|
requires: []
|
||||||
|
|
||||||
- id: specs
|
- id: specs
|
||||||
@@ -55,11 +66,17 @@ artifacts:
|
|||||||
- External constraints (security, privacy, reliability, compatibility)
|
- External constraints (security, privacy, reliability, compatibility)
|
||||||
- Scenarios that can be tested or explicitly validated
|
- Scenarios that can be tested or explicitly validated
|
||||||
|
|
||||||
Не включай в specs:
|
Artifact boundary — MUST NOT include:
|
||||||
- Internal class/function names
|
- intent или scope за пределами утверждённого Proposal: сначала верни
|
||||||
- Library or framework choices
|
изменение в Proposal;
|
||||||
- Step-by-step implementation details
|
- internal components, class/function names, files или database
|
||||||
- Detailed execution plans (those belong in design.md or tasks.md)
|
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
|
Quick test: if the implementation can change without changing externally
|
||||||
visible behavior, it likely does not belong in the spec.
|
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.
|
Common pitfall: Using MODIFIED with partial content loses detail at archive time.
|
||||||
If adding new concerns without changing existing behavior, use ADDED instead.
|
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
|
## Purpose
|
||||||
|
|
||||||
Lets users take their data out of the product in a portable format.
|
Lets users take their data out of the product in a portable format.
|
||||||
@@ -128,15 +146,39 @@ artifacts:
|
|||||||
- **WHEN** user clicks "Export" button
|
- **WHEN** user clicks "Export" button
|
||||||
- **THEN** system downloads a CSV file with all user data
|
- **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
|
## REMOVED Requirements
|
||||||
|
|
||||||
### Requirement: Legacy export
|
### Requirement: Legacy export
|
||||||
**Reason**: Replaced by new export system
|
**Reason**: Replaced by new export system
|
||||||
**Migration**: Use new export endpoint at /api/v2/export
|
**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 не означает автоматический
|
Specs должны быть проверяемыми, но scenario не означает автоматический
|
||||||
unit test: уровень проверки выбирается по риску поведения.
|
unit test: уровень проверки выбирается по риску поведения.
|
||||||
|
|
||||||
|
Перед записью установи явный approval Proposal из разговора. После
|
||||||
|
записи выполни `bash specs/scripts/verify-openspec-planning.sh <change>`
|
||||||
|
и исправь технические ошибки до запроса approval Delta Specs. Если
|
||||||
|
обнаружено изменение intent, вернись к Proposal и инвалидируй downstream
|
||||||
|
approvals вместо скрытого расширения Specs.
|
||||||
requires:
|
requires:
|
||||||
- proposal
|
- proposal
|
||||||
|
|
||||||
@@ -146,7 +188,17 @@ artifacts:
|
|||||||
template: design.md
|
template: design.md
|
||||||
instruction: |
|
instruction: |
|
||||||
Создай Design, объясняющий, КАК архитектурно выполнить утверждённые
|
Создай 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**: только текущее состояние и ограничения подхода.
|
- **Context**: только текущее состояние и ограничения подхода.
|
||||||
@@ -160,6 +212,12 @@ artifacts:
|
|||||||
- **Risks / Trade-offs**: риск и mitigation.
|
- **Risks / Trade-offs**: риск и mitigation.
|
||||||
- **Migration Plan**: порядок поставки и rollback, если применимо.
|
- **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**, если изменение вводит или существенно
|
Добавь **Solution Assessment**, если изменение вводит или существенно
|
||||||
заменяет auth, security, storage, external integration, observability,
|
заменяет auth, security, storage, external integration, observability,
|
||||||
caching, concurrency или общую infrastructure/tooling либо содержит
|
caching, concurrency или общую infrastructure/tooling либо содержит
|
||||||
@@ -176,7 +234,11 @@ artifacts:
|
|||||||
skipped. If a question would change the specs, the chosen approach, or
|
skipped. If a question would change the specs, the chosen approach, or
|
||||||
the task breakdown, resolve it now - ask the user instead of guessing.
|
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:
|
requires:
|
||||||
- specs
|
- specs
|
||||||
|
|
||||||
@@ -197,8 +259,18 @@ artifacts:
|
|||||||
|
|
||||||
Правила:
|
Правила:
|
||||||
- Группируй задачи под numbered `##` headings и располагай по dependencies.
|
- Группируй задачи под 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 должна существовать задача
|
- Для каждой `affected` области Delivery Map должна существовать задача
|
||||||
реализации и её canonical local gate; пустые commits запрещены.
|
реализации и её canonical local gate; пустые commits запрещены.
|
||||||
- Каждая задача MUST указывать planned verification action: команду,
|
- Каждая задача MUST указывать planned verification action: команду,
|
||||||
@@ -213,24 +285,38 @@ artifacts:
|
|||||||
branching, transformation, invariant или regression.
|
branching, transformation, invariant или regression.
|
||||||
- Перед custom implementation в обязательных областях включи действие по
|
- Перед custom implementation в обязательных областях включи действие по
|
||||||
утверждённому Solution Assessment из Design.
|
утверждённому Solution Assessment из Design.
|
||||||
- MUST NOT записывать ещё не наблюдённые результаты как выполненные,
|
|
||||||
предполагаемые commit identifiers, archive path или post-archive
|
Artifact boundary — MUST NOT include:
|
||||||
Completion Evidence. Такое evidence создаётся только после факта.
|
- новое 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:
|
Example:
|
||||||
```
|
```
|
||||||
## 1. Setup
|
## 1. Delivery
|
||||||
|
|
||||||
- [ ] 1.1 Create new module structure and verify expected files are present
|
- [ ] 1.1 [backend] Implement session rejection
|
||||||
- [ ] 1.2 Add dependencies to package.json and verify package installation succeeds
|
- **Covers:** `user-authentication` — `Expired session is rejected`
|
||||||
|
- **Verification:** Run the backend canonical gate and the expiry contract test.
|
||||||
## 2. Core Implementation
|
- [ ] 1.2 [workspace] Run cross-area semantic review
|
||||||
|
- **Covers:** `N/A` — verification only; no independent spec behavior.
|
||||||
- [ ] 2.1 Implement data export function and verify the export test passes
|
- **Verification:** Compare delivery against every approved Requirement and Scenario.
|
||||||
- [ ] 2.2 Add CSV formatting utilities and verify unit tests cover quoting and delimiters
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Reference specs for what needs to be built, design for how to build it.
|
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:
|
requires:
|
||||||
- design
|
- design
|
||||||
|
|
||||||
@@ -240,5 +326,23 @@ apply:
|
|||||||
instruction: |
|
instruction: |
|
||||||
Сначала проверь exact OpenSpec version contract. Работай только с change в
|
Сначала проверь exact OpenSpec version contract. Работай только с change в
|
||||||
canonical store `wealth-ledger-specs` и не создавай parallel planning root.
|
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.
|
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 -->
|
<!-- 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
|
## Open Questions
|
||||||
|
|
||||||
<!-- Only questions that cannot change Specs, approach or Tasks; otherwise
|
<!-- 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.1 [area] <!-- Concrete implementation action -->
|
||||||
- [ ] 1.2 <!-- Concrete implementation action and its planned verification -->
|
- **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.1 [area] <!-- Affected repository action -->
|
||||||
- [ ] 2.2 <!-- Cross-area verification when required -->
|
- **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
|
## Requirements
|
||||||
|
|
||||||
### Requirement: Реестр remediation отделён от снимка аудита
|
### 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: Агент открывает работу по аудиту в новой сессии
|
#### Scenario: Агент открывает работу по аудиту в новой сессии
|
||||||
|
|
||||||
- **WHEN** агент получает задачу устранить или продолжить finding из любого завершённого аудита
|
- **WHEN** агент получает задачу устранить или продолжить finding из любого завершённого аудита
|
||||||
- **THEN** он находит в едином registry исходный snapshot и Audit ID, текущий статус, связанный OpenSpec change, evidence и следующее действие без повторной интерпретации всех аудитов
|
- **THEN** он находит в едином registry исходный snapshot и Audit ID, текущий статус, связанный OpenSpec change, evidence и следующее действие без повторной интерпретации всех аудитов
|
||||||
|
|
||||||
#### Scenario: Проводится повторный аудит
|
#### Scenario: Проводится повторный аудит
|
||||||
|
|
||||||
- **WHEN** новый аудит завершён после предыдущего audit snapshot
|
- **WHEN** новый аудит завершён после предыдущего audit snapshot
|
||||||
- **THEN** система добавляет новый immutable snapshot и обновляет тот же live registry, не переписывая предыдущий snapshot и не создавая конкурирующий registry
|
- **THEN** система добавляет новый immutable snapshot и обновляет тот же live registry, не переписывая предыдущий snapshot и не создавая конкурирующий registry
|
||||||
|
|
||||||
#### Scenario: Обновляется прогресс remediation
|
#### Scenario: Обновляется прогресс remediation
|
||||||
|
|
||||||
- **WHEN** работа по finding меняет статус
|
- **WHEN** работа по finding меняет статус
|
||||||
- **THEN** versioned audit snapshots не редактируются, а изменение фиксируется только в live registry с датой и необходимым evidence
|
- **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
|
### Requirement: Registry задаёт однозначный статус и следующий change
|
||||||
Каждая audit-derived запись SHALL иметь ровно один статус из `planned`, `active`, `done`, `deferred` или `accepted`. `planned` MUST означать согласованную работу, которую можно начать без внешнего review trigger; запись, ожидающая версии зависимости, внешнего события или отдельного решения владельца, MUST иметь статус `deferred` с условием пересмотра. Registry MUST содержать не более одного `active` remediation change и ровно одну следующую рекомендуемую задачу, пока существуют findings со статусом `planned`.
|
Каждая 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: Риск сознательно не исправляется сейчас
|
#### Scenario: Риск сознательно не исправляется сейчас
|
||||||
- **WHEN** владелец переносит finding или принимает риск
|
- **WHEN** владелец переносит finding или принимает риск
|
||||||
- **THEN** registry сохраняет причину решения и условия, при которых оно должно быть пересмотрено
|
- **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 объявляет новое правило блокирующим
|
- **WHEN** change объявляет новое правило блокирующим
|
||||||
- **THEN** completion evidence подтверждает как успешный compliant case, так и обнаружение контролируемого representative violation
|
- **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 одной из них не проходит
|
- **WHEN** общий verifier проверяет несколько affected областей и канонический gate одной из них не проходит
|
||||||
- **THEN** общий результат является неуспешным и явно указывает failing area без обхода её локального 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 требует каскадной проверки
|
### 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 изменилось намерение
|
#### Scenario: После Design изменилось намерение
|
||||||
|
|
||||||
@@ -47,6 +47,16 @@ Versioned SDD change SHALL проходить последовательност
|
|||||||
- **WHEN** implementation checklist требует поведение, которого нет в утверждённых Delta Specs
|
- **WHEN** implementation checklist требует поведение, которого нет в утверждённых Delta Specs
|
||||||
- **THEN** агент не расширяет scope через Tasks и возвращает change к 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 задан явно
|
### 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, текущей директории или глобального значения по умолчанию машины.
|
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
|
### 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 соответствует контракту
|
#### Scenario: Версия CLI соответствует контракту
|
||||||
|
|
||||||
@@ -94,6 +104,16 @@ SDD workflow MUST объявлять поддерживаемую версию O
|
|||||||
- **WHEN** доступная версия OpenSpec не совпадает с объявленным совместимым контрактом
|
- **WHEN** доступная версия OpenSpec не совпадает с объявленным совместимым контрактом
|
||||||
- **THEN** локальная preflight-проверка блокирует SDD-операцию и сообщает ожидаемую и фактическую версии
|
- **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
|
### 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.
|
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
|
#### Scenario: Change завершил все tasks
|
||||||
- **WHEN** каждый planning artifact утверждён, каждый task отмечен, required verification, implementation и pre-archive gates всех affected areas успешно завершены
|
- **WHEN** каждый planning artifact утверждён, каждый task отмечен, required verification, implementation и pre-archive gates всех affected areas успешно завершены
|
||||||
- **THEN** workflow допускает archive и фиксирует его результат через определённый completion-evidence path без создания post-archive task
|
- **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 как успешную
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
Executable
+80
@@ -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'
|
||||||
Executable
+72
@@ -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"
|
||||||
Executable
+88
@@ -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'
|
||||||
@@ -6,6 +6,7 @@ workspace=${WEALTH_LEDGER_WORKSPACE:-$(cd "$script_dir/../.." && pwd -P)}
|
|||||||
failures=0
|
failures=0
|
||||||
|
|
||||||
bash "$script_dir/verify-openspec-version.sh" "$workspace/specs/openspec/.cli-version"
|
bash "$script_dir/verify-openspec-version.sh" "$workspace/specs/openspec/.cli-version"
|
||||||
|
expected_version=$(tr -d '[:space:]' < "$workspace/specs/openspec/.cli-version")
|
||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
printf 'FAIL: %s\n' "$1" >&2
|
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"
|
schema_file="$canonical_root/schemas/wealth-ledger-sdd/schema.yaml"
|
||||||
require_file_contains "$schema_file" 'name: wealth-ledger-sdd'
|
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" 'specs' 'proposal'
|
||||||
require_schema_edge "$schema_file" 'design' 'specs'
|
require_schema_edge "$schema_file" 'design' 'specs'
|
||||||
require_schema_edge "$schema_file" 'tasks' 'design'
|
require_schema_edge "$schema_file" 'tasks' 'design'
|
||||||
require_file_contains "$schema_file" 'requires: [ tasks ]'
|
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 [[ -d "$workspace/specs" ]]; then
|
||||||
if ! schema_validation=$(cd "$workspace/specs" && openspec schema validate wealth-ledger-sdd 2>&1); 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"
|
fail "wealth-ledger-sdd schema validation failed: $schema_validation"
|
||||||
@@ -140,7 +146,7 @@ skill_entrypoints=(
|
|||||||
.opencode/skills/openspec-verify-change/SKILL.md
|
.opencode/skills/openspec-verify-change/SKILL.md
|
||||||
)
|
)
|
||||||
for relative_path in "${skill_entrypoints[@]}"; do
|
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
|
done
|
||||||
|
|
||||||
one_artifact_entrypoints=(
|
one_artifact_entrypoints=(
|
||||||
@@ -160,6 +166,24 @@ for relative_path in "${one_artifact_entrypoints[@]}"; do
|
|||||||
fi
|
fi
|
||||||
done
|
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=(
|
approval_blocker_entrypoints=(
|
||||||
.opencode/commands/opsx-apply.md
|
.opencode/commands/opsx-apply.md
|
||||||
.opencode/commands/opsx-archive.md
|
.opencode/commands/opsx-archive.md
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
|
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
|
||||||
verifier="$script_dir/verify-openspec-authority.sh"
|
verifier="$script_dir/verify-openspec-authority.sh"
|
||||||
|
contract_version=$(tr -d '[:space:]' < "$script_dir/../openspec/.cli-version")
|
||||||
|
|
||||||
if [[ ! -f "$verifier" ]]; then
|
if [[ ! -f "$verifier" ]]; then
|
||||||
echo "expected verifier at $verifier" >&2
|
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'
|
write_file "specs/.openspec-store/store.yaml" $'version: 1\nid: wealth-ledger-specs'
|
||||||
mkdir -p "$fixture/specs/openspec"
|
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'
|
write_file "specs/openspec/config.yaml" 'schema: wealth-ledger-sdd'
|
||||||
mkdir -p "$fixture/specs/openspec/schemas"
|
mkdir -p "$fixture/specs/openspec/schemas"
|
||||||
cp -R "$script_dir/../openspec/schemas/wealth-ledger-sdd" "$fixture/specs/openspec/schemas/wealth-ledger-sdd"
|
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-sync-specs/SKILL.md
|
||||||
.opencode/skills/openspec-verify-change/SKILL.md
|
.opencode/skills/openspec-verify-change/SKILL.md
|
||||||
)
|
)
|
||||||
|
planning_line='bash specs/scripts/verify-openspec-planning.sh "<change>"'
|
||||||
|
|
||||||
for path in "${entrypoints[@]}"; do
|
for path in "${entrypoints[@]}"; do
|
||||||
content=$'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs'
|
content=$'bash specs/scripts/verify-openspec-version.sh\nopenspec status --store wealth-ledger-specs'
|
||||||
if [[ "$path" == .opencode/skills/* ]]; then
|
if [[ "$path" == .opencode/skills/* ]]; then
|
||||||
content=$'generatedBy: "1.10.0"\n'"$content"
|
content="generatedBy: \"$contract_version\""$'\n'"$content"
|
||||||
fi
|
fi
|
||||||
if [[ "$path" == *continue* || "$path" == *explore* || "$path" == *propose* ]]; then
|
if [[ "$path" == *continue* || "$path" == *explore* || "$path" == *propose* ]]; then
|
||||||
content="$content"$'\nCreate at most ONE planning artifact per invocation.\nSTOP for explicit Change Owner approval.'
|
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
|
if [[ "$path" == *apply* || "$path" == *archive* ]]; then
|
||||||
content="$content"$'\nRequire explicit Change Owner approval and invalidate dependent approvals after upstream edits.'
|
content="$content"$'\nRequire explicit Change Owner approval and invalidate dependent approvals after upstream edits.'
|
||||||
fi
|
fi
|
||||||
|
if [[ "$path" != *new* && "$path" != *sync* ]]; then
|
||||||
|
content="$content"$'\n'"$planning_line"
|
||||||
|
fi
|
||||||
write_file "$path" "$content"
|
write_file "$path" "$content"
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -68,18 +73,25 @@ openspec status --store wealth-ledger-specs
|
|||||||
Require affected delivery area gates, semantic verification and independent read-only review.
|
Require affected delivery area gates, semantic verification and independent read-only review.
|
||||||
Require explicit Change Owner approval and invalidate dependent approvals after upstream edits.
|
Require explicit Change Owner approval and invalidate dependent approvals after upstream edits.
|
||||||
Do not ask for or accept a confirmation override.'
|
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/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
|
verification_gate='bash specs/scripts/verify-openspec-version.sh
|
||||||
openspec status --store wealth-ledger-specs
|
openspec status --store wealth-ledger-specs
|
||||||
Check every affected delivery area with the workspace verifier and require independent read-only review.'
|
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/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
|
apply_gate='bash specs/scripts/verify-openspec-version.sh
|
||||||
openspec status --store wealth-ledger-specs
|
openspec status --store wealth-ledger-specs
|
||||||
Require explicit Change Owner approval and invalidate dependent approvals after upstream edits.'
|
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() {
|
run_verifier() {
|
||||||
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier"
|
WEALTH_LEDGER_WORKSPACE="$fixture" bash "$verifier"
|
||||||
@@ -87,12 +99,34 @@ run_verifier() {
|
|||||||
|
|
||||||
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'
|
write_file "specs/openspec/.cli-version" '9.9.9'
|
||||||
if run_verifier; then
|
if run_verifier; then
|
||||||
echo "expected wrong OpenSpec version contract to fail" >&2
|
echo "expected wrong OpenSpec version contract to fail" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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'
|
write_file "specs/openspec/config.yaml" 'schema: spec-driven'
|
||||||
if run_verifier; then
|
if run_verifier; then
|
||||||
@@ -101,6 +135,14 @@ if run_verifier; then
|
|||||||
fi
|
fi
|
||||||
write_file "specs/openspec/config.yaml" 'schema: wealth-ledger-sdd'
|
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'
|
write_file "specs/openspec/schemas/wealth-ledger-sdd/schema.yaml" $'name: wealth-ledger-sdd\nversion: 1'
|
||||||
if run_verifier; then
|
if run_verifier; then
|
||||||
echo "expected incomplete project schema graph to fail" >&2
|
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
|
echo "expected multi-artifact proposal guidance to fail" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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.'
|
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
|
if run_verifier; then
|
||||||
|
|||||||
Executable
+282
@@ -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
|
||||||
Executable
+128
@@ -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'
|
||||||
@@ -25,134 +25,14 @@ for required_file in "$metadata_file" "$design_file"; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
areas=(frontend backend specs docs)
|
# shellcheck source=lib/delivery-map.sh
|
||||||
affected_flags=(0 0 0 0)
|
source "$script_dir/lib/delivery-map.sh"
|
||||||
map_statuses=('' '' '' '')
|
wl_parse_delivery_map "$metadata_file" "$design_file"
|
||||||
map_reasons=('' '' '' '')
|
|
||||||
contract_status=''
|
|
||||||
contract_reason=''
|
|
||||||
|
|
||||||
area_index() {
|
areas=("${wl_areas[@]}")
|
||||||
case "$1" in
|
affected_flags=("${wl_affected_flags[@]}")
|
||||||
frontend) printf '0' ;;
|
map_statuses=("${wl_map_statuses[@]}")
|
||||||
backend) printf '1' ;;
|
contract_status=$wl_contract_status
|
||||||
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
|
|
||||||
|
|
||||||
printf 'Delivery Map verified:'
|
printf 'Delivery Map verified:'
|
||||||
for index in 0 1 2 3; do
|
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 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 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 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"
|
run_gate 'OpenSpec main specs' bash -c 'cd "$1" && openspec validate --specs --strict --store wealth-ledger-specs' _ "$workspace/specs"
|
||||||
|
|||||||
Reference in New Issue
Block a user