@prodshape/integration-openspec 0.6.0-alpha.0 → 0.6.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -8
- package/assets/{openspec-product-schema → openspec-product-change-schema}/schema.yaml +41 -10
- package/assets/{openspec-product-schema → openspec-product-change-schema}/scripts/product-apply.mjs +2 -2
- package/assets/{openspec-product-schema → openspec-product-change-schema}/scripts/product-validate.mjs +2 -2
- package/assets/openspec-product-change-schema/templates/change.md +51 -0
- package/assets/{openspec-product-schema → openspec-product-change-schema}/templates/proposal.md +12 -0
- package/assets/openspec-product-recovery-schema/schema.yaml +40 -0
- package/assets/openspec-product-recovery-schema/templates/brief.md +22 -0
- package/assets/openspec-product-recovery-schema/templates/report.md +15 -0
- package/dist/index.d.ts +21 -11
- package/dist/index.js +210 -64
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +207 -40
- package/src/{product-schema.ts → product-change-schema.ts} +29 -9
- package/src/product-workflow.ts +33 -38
- package/assets/openspec-product-schema/templates/change.md +0 -49
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
OpenSpec integration for Product Definition as Code (PDaC), in two lanes: a citation lane that grounds OpenSpec's spec-driven delivery workflow in the accepted product model, and a product lane that hosts the PDaC product workflow inside OpenSpec itself.
|
|
4
4
|
|
|
5
|
-
Both lanes write only official OpenSpec surfaces (`openspec/config.yaml`, `openspec/schemas/product/`) plus ProductShape's own integration metadata (`.product/integrations/openspec.json`). The integration never patches OpenSpec-generated commands or skills, never modifies OpenSpec's built-in schemas, and never writes into a native spec-driven change's documents. Every write is byte-gated and ownership-proven per file
|
|
5
|
+
Both lanes write only official OpenSpec surfaces (`openspec/config.yaml`, `openspec/schemas/product-change/`, and `openspec/schemas/product-recovery/`) plus ProductShape's own integration metadata (`.product/integrations/openspec.json`). The integration never patches OpenSpec-generated commands or skills, never modifies OpenSpec's built-in schemas, and never writes into a native spec-driven change's documents. Every write is byte-gated and ownership-proven per file; `update` replaces or removes only content whose recorded digest still proves ownership, while `remove` preserves unrecorded or hand-edited files. Dry runs report exactly what the real operation would do.
|
|
6
6
|
|
|
7
7
|
## The citation lane (delivery)
|
|
8
8
|
|
|
@@ -10,16 +10,18 @@ The integration merges PDaC authority context and citation rules into `openspec/
|
|
|
10
10
|
|
|
11
11
|
## The product lane (the hosted product workflow)
|
|
12
12
|
|
|
13
|
-
The integration installs a project-local OpenSpec schema named `product` at `openspec/schemas/product/`. An OpenSpec change created with that schema hosts a PDaC Product Change: the normative semantic delta (`product/change.md` plus `product/proposed/**`) against the accepted model in `docs/product/model`, which stays the only source of product truth.
|
|
13
|
+
The integration installs a project-local OpenSpec schema named `product-change` at `openspec/schemas/product-change/`. An OpenSpec change created with that schema hosts a PDaC Product Change: the normative semantic delta (`product-change/change.md` plus `product-change/proposed/**`) against the accepted model in `docs/product/model`, which stays the only source of product truth.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
For brownfield systems without an accepted baseline, the integration also installs the independent `product-recovery` schema at `openspec/schemas/product-recovery/`. Use `/opsx:new <name> --schema product-recovery`, confirm `recovery/brief.md`, and repeat `/opsx:continue` for bounded evidence rounds. Recovery state and the draft `CHG-INITIAL` remain inside the OpenSpec change container; they never write `.product/generated/recovery/` or `docs/product/changes/active/`. A completed recovery may produce a candidate baseline or an honest insufficient-evidence outcome. Only a human-approved candidate baseline can delegate to the existing Product Change apply rail, and archive remains separate.
|
|
16
|
+
|
|
17
|
+
The schema pin is a load-bearing, enforced invariant: the rail accepts only one folder-safe OpenSpec 1.11 change name and validates the complete OpenSpec 1.11 metadata shape in `.openspec.yaml`, not merely the presence of a schema string. It treats a change as a product change only when that valid metadata pins `schema: product-change`. A change pinned to another schema never lists, validates, applies or enters concurrency, however product-shaped its contents look. A product-shaped container with missing or malformed metadata stops listing and concurrency with a clear error instead of disappearing from the live-change set.
|
|
16
18
|
|
|
17
19
|
The primary workflow is OpenSpec's own:
|
|
18
20
|
|
|
19
21
|
```text
|
|
20
|
-
/opsx:new <change> --schema product
|
|
22
|
+
/opsx:new <change> --schema product-change
|
|
21
23
|
|
|
|
22
|
-
/opsx:continue (or /opsx:ff) authors proposal.md, then product/change.md + product/proposed/**
|
|
24
|
+
/opsx:continue (or /opsx:ff) authors proposal.md, then product-change/change.md + product-change/proposed/**
|
|
23
25
|
|
|
|
24
26
|
/opsx:apply <change> follows the schema's apply instruction
|
|
25
27
|
|
|
|
@@ -29,14 +31,14 @@ The primary workflow is OpenSpec's own:
|
|
|
29
31
|
Apply and archive are separate lifecycle operations. The schema's apply instruction delegates the deterministic write to this package's apply rail through the installed bridge script:
|
|
30
32
|
|
|
31
33
|
```text
|
|
32
|
-
node openspec/schemas/product/scripts/product-apply.mjs --change <name> [--dry-run]
|
|
34
|
+
node openspec/schemas/product-change/scripts/product-apply.mjs --change <name> [--dry-run]
|
|
33
35
|
```
|
|
34
36
|
|
|
35
37
|
The bridge resolves the locally installed `@prodshape/integration-openspec` and calls `applyOpenSpecProductChange`, which re-reads the accepted model and revalidates everything at apply time: the configuration, the baseline itself (including per-document load diagnostics of artifacts the change never touches) and the hosted delta as an overlay; a prior validate call is never trusted. Any blocking diagnostic refuses before any write, with the model and the change container byte-identical. It enforces base-revision drift (PRODUCT027) and the apply-authorised state (PRODUCT028, whose hosted message states the protocol requirement without pretending to verify the actor), writes the delta into the model named by lowercase id, reports the product diff computed from the result, and flips the hosted change.md status to applied in place. It never commits and never archives; `openspec archive` moves the change container afterwards and never touches the model. A preflight bridge exists beside it (`product-validate.mjs`) for explicit overlay validation at any point.
|
|
36
38
|
|
|
37
39
|
Validation is mandatory; authorisation policy is outside the deterministic rail. `status: approved` in the hosted change.md is the apply-authorised protocol state. ProductShape's accepted policy requires human product approval before that state is recorded; the integration verifies the state but cannot identify or judge the actor, and it never performs the transition. Merging the resulting baseline also remains a human decision.
|
|
38
40
|
|
|
39
|
-
Product-semantic clarification happens before the delta. While authoring the intent, the schema asks the agent to identify wording that admits materially different observable outcomes, present those alternatives to the user and stop. An unresolved decision must remain visible under `Open Questions for the Product Owner`; the agent must not choose an outcome, author the delta or seek approval merely to advance the artifact graph. The deterministic rail validates structure and semantics it can prove, but it cannot infer that a human-facing request was ambiguous. `proposal.md` cites the accepted model it consumes; `product/change.md` and `product/proposed/**` carry no citations or scope declarations, and only the proposed artifacts can be materialized into the accepted model.
|
|
41
|
+
Product-semantic clarification happens before the delta. While authoring the intent, the schema asks the agent to identify wording that admits materially different observable outcomes, present those alternatives to the user and stop. An unresolved decision must remain visible under `Open Questions for the Product Owner`; the agent must not choose an outcome, author the delta or seek approval merely to advance the artifact graph. The deterministic rail validates structure and semantics it can prove, but it cannot infer that a human-facing request was ambiguous. `proposal.md` cites the accepted model it consumes; `product-change/change.md` and `product-change/proposed/**` carry no citations or scope declarations, and only the proposed artifacts can be materialized into the accepted model.
|
|
40
42
|
|
|
41
43
|
### Requirements
|
|
42
44
|
|
|
@@ -51,7 +53,7 @@ The deterministic rails are exported for wrappers, tests and custom callers; the
|
|
|
51
53
|
```ts
|
|
52
54
|
import {
|
|
53
55
|
inspectProductModel, // accepted model + in-memory graph + diagnostics
|
|
54
|
-
listOpenSpecProductChanges, // OpenSpec changes hosting product/change.md
|
|
56
|
+
listOpenSpecProductChanges, // OpenSpec changes hosting product-change/change.md
|
|
55
57
|
loadOpenSpecProductChange,
|
|
56
58
|
validateOpenSpecProductChange, // overlay validation; concurrency spans both containers
|
|
57
59
|
applyOpenSpecProductChange, // revalidates at apply time; fail closed; never archives
|
|
@@ -62,3 +64,5 @@ import {
|
|
|
62
64
|
Concurrency (PRODUCT025) spans both change containers: a hosted OpenSpec product change and a native change under `docs/product/changes/active` touching the same artifact report against each other.
|
|
63
65
|
|
|
64
66
|
The citation-lane surface (`addOpenSpecIntegration`, `updateOpenSpecIntegration`, `checkOpenSpecIntegration`, `removeOpenSpecIntegration`, `bootstrapOpenSpecWorkspace`, the population provider) is unchanged and documented in the module source.
|
|
67
|
+
|
|
68
|
+
`addOpenSpecIntegration` and `checkOpenSpecIntegration` detect the OpenSpec CLI because they establish or verify the recorded compatibility verdict. `updateOpenSpecIntegration` uses that verdict from `.product/integrations/openspec.json`, so managed configuration and schema ownership reconciliation remains available when OpenSpec is not on `PATH`; an update without existing integration metadata follows the same detection requirement as a first installation.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# MANAGED FILE. Installed by `prodshape integration add openspec` and regenerated by
|
|
2
2
|
# `prodshape integration update`. Hand edits are reported by `prodshape doctor` and replaced
|
|
3
3
|
# on the next update; remove the integration to take the schema out.
|
|
4
|
-
name: product
|
|
4
|
+
name: product-change
|
|
5
5
|
version: 1
|
|
6
6
|
description: >-
|
|
7
7
|
PDaC product workflow hosted in OpenSpec: requested product intent becomes a Product Change delta against the accepted model in docs/product/model, deterministically validated as an overlay, then applied by the PDaC integration only for a change in the apply-authorised state. Requires OpenSpec >= 1.7.0. This schema changes product meaning only; implementation work belongs to a separate spec-driven change.
|
|
@@ -13,6 +13,13 @@ artifacts:
|
|
|
13
13
|
instruction: |
|
|
14
14
|
Capture WHY the product definition should change, before any delta exists.
|
|
15
15
|
|
|
16
|
+
Run a proportional integrity pass before authoring the first delta. Show a small prioritised
|
|
17
|
+
report: for each changed or proposed node, name the neighbouring candidate, relationship,
|
|
18
|
+
impact polarity and the mechanical reason it merits review. Classify each candidate as
|
|
19
|
+
affected, checked and unaffected, or uncertain. This graph evidence is assistance, never
|
|
20
|
+
authority: it must not expand scope or modify an artifact. Explain why relevant categories
|
|
21
|
+
and neighbours were left unchanged.
|
|
22
|
+
|
|
16
23
|
Ground the intent in the accepted model:
|
|
17
24
|
1. Read the accepted Product Definition (docs/product/model unless .product/config.yaml moves product-root).
|
|
18
25
|
Never treat proposals, archived changes or OpenSpec documents as product truth.
|
|
@@ -39,20 +46,33 @@ artifacts:
|
|
|
39
46
|
delivery-only work), record that verdict under the "No product delta" heading and STOP: do not
|
|
40
47
|
author a delta artifact and do not invent product change to satisfy the workflow. Otherwise state
|
|
41
48
|
the intended product outcome in product language, not implementation language.
|
|
49
|
+
|
|
50
|
+
Keep proposal.md as resumable working memory: record the current queue, checked-and-excluded
|
|
51
|
+
candidates, recommendations, parked items, parked questions and verbatim human answers. Ask exactly one
|
|
52
|
+
question at a time, highest product risk first. A user may stop, park a question, or place a
|
|
53
|
+
possible gap explicitly out of scope. The readiness conclusion must say whether no material
|
|
54
|
+
product decisions remain unresolved, named decisions are required, or named possible gaps
|
|
55
|
+
remain and may be refined now or consciously placed out of scope.
|
|
56
|
+
Record checked and excluded candidates in the proposal even when they need no artifact.
|
|
42
57
|
requires: []
|
|
43
58
|
|
|
44
59
|
- id: delta
|
|
45
|
-
generates: 'product/**/*.md'
|
|
60
|
+
generates: 'product-change/**/*.md'
|
|
46
61
|
description: The PDaC Product Change delta, change.md plus the complete proposed future state
|
|
47
62
|
template: change.md
|
|
48
63
|
instruction: |
|
|
49
|
-
Author the PDaC Product Change under product/ in this change directory: product/change.md plus
|
|
50
|
-
product/proposed/** holding the COMPLETE future state of every artifact the change adds or
|
|
64
|
+
Author the PDaC Product Change under product/ in this change directory: product-change/change.md plus
|
|
65
|
+
product-change/proposed/** holding the COMPLETE future state of every artifact the change adds or
|
|
51
66
|
modifies, laid out exactly as it will live in the model (actors/, journeys/, use-cases/,
|
|
52
67
|
business-rules/, behaviours/, domain/terms/, domain/bounded-contexts/, requirements/functional/,
|
|
53
68
|
requirements/quality/, requirements/constraints/), each file named <lowercase-id>.md.
|
|
54
69
|
|
|
55
70
|
Rules that make the delta valid:
|
|
71
|
+
- Perform the proportional integrity pass again before the first delta, after a material
|
|
72
|
+
widening of intent, when the delta begins to modify additional graph nodes, whenever the
|
|
73
|
+
user explicitly requests another refinement pass, and immediately before approval.
|
|
74
|
+
Editorial corrections do not require a new whole pass. Recompute the explained graph
|
|
75
|
+
candidates; do not expand scope or modify a neighbour automatically.
|
|
56
76
|
- Re-read the intent's "Open Questions for the Product Owner" before writing. Do not author or
|
|
57
77
|
complete the delta while any product-semantic question remains unresolved: ask the user and stop.
|
|
58
78
|
Never choose a product outcome on the user's behalf. Carry the user's answer into one unambiguous
|
|
@@ -62,14 +82,14 @@ artifacts:
|
|
|
62
82
|
and operations with all three keys add, modify and remove. The body carries seven sections in
|
|
63
83
|
order: Problem, Intended Product Outcome, Rationale, Affected Product Areas, Open Questions,
|
|
64
84
|
Product Acceptance, Out of Scope.
|
|
65
|
-
- product/change.md is a change manifest, not a consumer document. Never add PDaC citations or a
|
|
66
|
-
pdac-scope declaration to it or to product/proposed/**. Citations belong in proposal.md and other
|
|
85
|
+
- product-change/change.md is a change manifest, not a consumer document. Never add PDaC citations or a
|
|
86
|
+
pdac-scope declaration to it or to product-change/proposed/**. Citations belong in proposal.md and other
|
|
67
87
|
documents that consume the accepted model; proposed artifacts use typed PDaC relationships.
|
|
68
88
|
- Preserve stable IDs: evolve an existing artifact by listing its EXISTING id under
|
|
69
89
|
operations.modify, never by adding a near duplicate under a new id. Create only the artifacts
|
|
70
90
|
the intent requires.
|
|
71
91
|
- Every id in operations.add and operations.modify has a complete proposed artifact under
|
|
72
|
-
product/proposed/; nothing else appears there. Removals list existing ids and ship no files.
|
|
92
|
+
product-change/proposed/; nothing else appears there. Removals list existing ids and ship no files.
|
|
73
93
|
- Use the exact current PDaC formats. `prodshape template <kind>` prints the authoring template
|
|
74
94
|
for every kind (actor, journey, use-case, business-rule, domain-term, bounded-context,
|
|
75
95
|
functional-requirement, quality-requirement, constraint, structured-behaviour); it resolves the
|
|
@@ -87,8 +107,16 @@ artifacts:
|
|
|
87
107
|
deterministic apply of this change.
|
|
88
108
|
|
|
89
109
|
Preflight is available at any time:
|
|
90
|
-
`node openspec/schemas/product/scripts/product-validate.mjs --change <change-name>` validates the
|
|
110
|
+
`node openspec/schemas/product-change/scripts/product-validate.mjs --change <change-name>` validates the
|
|
91
111
|
accepted baseline plus this delta as an overlay without touching either.
|
|
112
|
+
|
|
113
|
+
The semantic requests "refine", "review" and "challenge this product change", and the
|
|
114
|
+
explicit `/product:refine <change>` command, resume this same OpenSpec product-change
|
|
115
|
+
container. The refine adapter may update proposal.md, change.md and proposed artifacts, but
|
|
116
|
+
it must never approve, apply or archive. If no change is identifiable, ask the user to select
|
|
117
|
+
one or create one through the normal OpenSpec workflow; do not create a second lifecycle.
|
|
118
|
+
This is the same OpenSpec change, not a new refinement workflow.
|
|
119
|
+
This is the same OpenSpec change, not a new refinement workflow.
|
|
92
120
|
requires:
|
|
93
121
|
- intent
|
|
94
122
|
|
|
@@ -99,14 +127,17 @@ apply:
|
|
|
99
127
|
Apply materializes the approved delta into docs/product/model. It is never implicit, never a
|
|
100
128
|
commit and never an archive.
|
|
101
129
|
|
|
102
|
-
1. Confirm the change is in the apply-authorised state: product/change.md carries
|
|
130
|
+
1. Confirm the change is in the apply-authorised state: product-change/change.md carries
|
|
103
131
|
status: approved. That protocol state is required for apply (PRODUCT028 otherwise); the
|
|
104
132
|
integration checks only that protocol state. ProductShape's accepted policy requires human
|
|
105
133
|
product approval; neither this workflow nor the integration grants, infers or judges it.
|
|
106
134
|
Before asking for or recording that state, confirm there are no unresolved product-semantic questions
|
|
107
135
|
in either the intent or the delta. `status: approved` must not be recorded merely to make apply proceed.
|
|
136
|
+
Immediately before asking for approval, run the proportional integrity pass again, record
|
|
137
|
+
the report and distinguish unresolved decisions from optional further depth. Parked decisions
|
|
138
|
+
keep the change unready; consciously excluded gaps must be named under Out of Scope.
|
|
108
139
|
2. Run the deterministic apply through the PDaC integration, dry run first:
|
|
109
|
-
`node openspec/schemas/product/scripts/product-apply.mjs --change <change-name> --dry-run`
|
|
140
|
+
`node openspec/schemas/product-change/scripts/product-apply.mjs --change <change-name> --dry-run`
|
|
110
141
|
then without --dry-run. The script resolves the locally installed
|
|
111
142
|
@prodshape/integration-openspec and calls its apply rail, which re-reads the accepted model,
|
|
112
143
|
revalidates this delta as an overlay at apply time, refuses on any blocking diagnostic with
|
package/assets/{openspec-product-schema → openspec-product-change-schema}/scripts/product-apply.mjs
RENAMED
|
@@ -10,13 +10,13 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
10
10
|
import process from 'node:process';
|
|
11
11
|
|
|
12
12
|
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
// openspec/schemas/product/scripts sits four levels below the repository root.
|
|
13
|
+
// openspec/schemas/product-change/scripts sits four levels below the repository root.
|
|
14
14
|
const defaultRoot = resolve(scriptDir, '..', '..', '..', '..');
|
|
15
15
|
|
|
16
16
|
function usage(message) {
|
|
17
17
|
console.error(message);
|
|
18
18
|
console.error(
|
|
19
|
-
'Usage: node openspec/schemas/product/scripts/product-apply.mjs --change <name> [--dry-run] [--root <dir>]',
|
|
19
|
+
'Usage: node openspec/schemas/product-change/scripts/product-apply.mjs --change <name> [--dry-run] [--root <dir>]',
|
|
20
20
|
);
|
|
21
21
|
process.exit(2);
|
|
22
22
|
}
|
|
@@ -8,13 +8,13 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
8
8
|
import process from 'node:process';
|
|
9
9
|
|
|
10
10
|
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
// openspec/schemas/product/scripts sits four levels below the repository root.
|
|
11
|
+
// openspec/schemas/product-change/scripts sits four levels below the repository root.
|
|
12
12
|
const defaultRoot = resolve(scriptDir, '..', '..', '..', '..');
|
|
13
13
|
|
|
14
14
|
function usage(message) {
|
|
15
15
|
console.error(message);
|
|
16
16
|
console.error(
|
|
17
|
-
'Usage: node openspec/schemas/product/scripts/product-validate.mjs --change <name> [--root <dir>]',
|
|
17
|
+
'Usage: node openspec/schemas/product-change/scripts/product-validate.mjs --change <name> [--root <dir>]',
|
|
18
18
|
);
|
|
19
19
|
process.exit(2);
|
|
20
20
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: CHG-EXAMPLE-001
|
|
3
|
+
type: product-change
|
|
4
|
+
title: Example product change
|
|
5
|
+
status: draft
|
|
6
|
+
base-revision: '3f2a91c'
|
|
7
|
+
operations:
|
|
8
|
+
add:
|
|
9
|
+
- FR-EXAMPLE-001
|
|
10
|
+
modify:
|
|
11
|
+
- UC-EXAMPLE-001
|
|
12
|
+
remove: []
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
This file lives at `product-change/change.md` inside the OpenSpec change directory, and the proposed future state lives beside it under `product-change/proposed/**`, laid out exactly as it will live in `docs/product/model` with files named by lowercase id.
|
|
16
|
+
|
|
17
|
+
This manifest and every artifact under `product-change/proposed/**` are Product Definition content, not consumer documents. Do not add `pdac-scope` declarations or PDaC citations here. Proposed artifacts express their internal connections through typed PDaC relationships; citations remain in `proposal.md` and other documents that consume the accepted model.
|
|
18
|
+
|
|
19
|
+
Every ID under `operations.add` and `operations.modify` needs a complete proposed artifact under `product-change/proposed/`. Author each artifact from its current PDaC template (`prodshape template <kind>`). Set `base-revision` to the baseline commit this change was authored against, quoted so YAML reads an all-digit revision as a string.
|
|
20
|
+
|
|
21
|
+
Leave `status: draft` while authoring; `status: approved` is the apply-authorised protocol state and setting it is the caller's authorisation act, outside this workflow. Apply materializes the proposal into the accepted model on a working branch; it never archives this change, and a pull-request merge accepts the resulting baseline. Product Change status never records implementation, verification, release or deployment.
|
|
22
|
+
|
|
23
|
+
## Problem
|
|
24
|
+
|
|
25
|
+
What is wrong or missing in the current Product Definition? State the problem, not the solution.
|
|
26
|
+
|
|
27
|
+
## Intended Product Outcome
|
|
28
|
+
|
|
29
|
+
What the Product Definition says once this change is accepted. Describe the destination, not the steps.
|
|
30
|
+
|
|
31
|
+
## Rationale
|
|
32
|
+
|
|
33
|
+
Why this outcome, and why now. Record the reasoning a future reader would otherwise have to reconstruct.
|
|
34
|
+
|
|
35
|
+
Distil each accepted decision that explains the delta here, next to the relevant edit. Preserve the human's answer verbatim; do not replace it with an interpretation.
|
|
36
|
+
|
|
37
|
+
## Affected Product Areas
|
|
38
|
+
|
|
39
|
+
Which parts of the product this change touches, in product language rather than file paths.
|
|
40
|
+
|
|
41
|
+
## Open Questions
|
|
42
|
+
|
|
43
|
+
Only genuinely unresolved decisions remain here. Include parked questions and why they are parked. If answering a question could produce materially different product behaviour, ask exactly one question at a time and stop: do not complete this delta or select an answer on the user's behalf. Write `None.` only after every product-semantic question in both the intent and this manifest has been resolved.
|
|
44
|
+
|
|
45
|
+
## Product Acceptance
|
|
46
|
+
|
|
47
|
+
How a reviewer recognises that the accepted definition expresses the intended outcome.
|
|
48
|
+
|
|
49
|
+
## Out of Scope
|
|
50
|
+
|
|
51
|
+
What this change explicitly does not touch, including consciously excluded gaps, delivery, technical design and implementation. A graph neighbour checked and found unaffected belongs here as an explained exclusion, not as a silent omission.
|
package/assets/{openspec-product-schema → openspec-product-change-schema}/templates/proposal.md
RENAMED
|
@@ -20,6 +20,18 @@ Every accepted artifact this intent depends on, alters or contradicts. One line
|
|
|
20
20
|
|
|
21
21
|
Artifacts inspected through the graph (impact, relationships) and judged out of scope, each with the one-line reason. Write `None.` when the impact list already covers everything inspected.
|
|
22
22
|
|
|
23
|
+
## Clarification Report
|
|
24
|
+
|
|
25
|
+
Before interviewing, record a small, prioritised integrity pass. For each changed or proposed node, list the neighbouring candidate, relationship, impact polarity and the mechanical reason it merits review. Classify each candidate as affected, checked and unaffected, or uncertain. The graph is evidence for review, never authority: it must not expand scope or modify an artifact. Explain why relevant categories and neighbours were left unchanged.
|
|
26
|
+
|
|
27
|
+
Repeat the pass before the first delta, after a material widening, when new graph nodes enter the delta, after an explicit `/product:refine` request, and immediately before approval. Editorial corrections do not require a new whole pass. A small clear change may have no questions; a large coherent outcome may remain one change.
|
|
28
|
+
|
|
29
|
+
## Refinement pass
|
|
30
|
+
|
|
31
|
+
Read the existing OpenSpec change before each sitting and reconstruct its state without chat history. Keep this proposal as working memory across sittings. Record the current queue, evidence, checked and excluded candidates, recommendations, parked questions and verbatim human answers. Ask exactly one question at a time, highest product risk first. A user may stop, park a question, or explicitly place a gap out of scope. Do not present the change as ready while a parked decision remains unresolved.
|
|
32
|
+
|
|
33
|
+
The readiness conclusion must distinguish one of: no material product decisions remain unresolved; named decisions are required before completion or approval; or named possible gaps remain and may be refined now or consciously placed out of scope.
|
|
34
|
+
|
|
23
35
|
## No Product Delta
|
|
24
36
|
|
|
25
37
|
Only when the honest verdict is that this request changes no product meaning: state that verdict and the reason, and stop the workflow here (no delta artifact follows). Delete this section otherwise.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# MANAGED FILE. Installed by `prodshape integration add openspec`.
|
|
2
|
+
name: product-recovery
|
|
3
|
+
version: 1
|
|
4
|
+
description: >-
|
|
5
|
+
PDaC brownfield recovery hosted in OpenSpec. Evidence is processed in bounded, resumable rounds and converges on a draft CHG-INITIAL Product Change.
|
|
6
|
+
artifacts:
|
|
7
|
+
- id: brief
|
|
8
|
+
generates: recovery/brief.md
|
|
9
|
+
description: Confirmed recovery scope, evidence authority and batch policy
|
|
10
|
+
template: brief.md
|
|
11
|
+
instruction: |
|
|
12
|
+
Agree this brief with the human before reading evidence. The brief is the
|
|
13
|
+
authority for roots, include/exclude/forbidden patterns, ordered tiers,
|
|
14
|
+
batch size and explicitly authorised external sources.
|
|
15
|
+
requires: []
|
|
16
|
+
- id: recovery-outcome
|
|
17
|
+
generates: recovery/report.md
|
|
18
|
+
description: Iterative evidence recovery report and hosted CHG-INITIAL draft
|
|
19
|
+
template: report.md
|
|
20
|
+
instruction: |
|
|
21
|
+
Repeat `/opsx:continue` for one bounded round at a time. Re-inventory and
|
|
22
|
+
re-hash first, stop on drift, then process at most the configured batch.
|
|
23
|
+
Use the deterministic ProductShape recovery capabilities for state changes;
|
|
24
|
+
never edit state files manually. Keep recovery/** and product-change/**
|
|
25
|
+
inside this OpenSpec change container. Distinguish observed evidence from
|
|
26
|
+
inference, preserve provenance and confidence, record contradictions as
|
|
27
|
+
questions, and finish either with a defensible candidate baseline or an
|
|
28
|
+
explicit insufficient-evidence report. Do not approve or apply.
|
|
29
|
+
requires:
|
|
30
|
+
- brief
|
|
31
|
+
apply:
|
|
32
|
+
requires:
|
|
33
|
+
- recovery-outcome
|
|
34
|
+
instruction: |
|
|
35
|
+
Apply is available only for a complete candidate-baseline outcome with a
|
|
36
|
+
human-approved CHG-INITIAL in product-change/change.md. Revalidate fresh
|
|
37
|
+
evidence, recovery completion, model drift and the complete overlay, then
|
|
38
|
+
delegate to the existing Product Change apply rail. An insufficient-evidence
|
|
39
|
+
outcome reports that there is nothing to apply. Never commit or archive;
|
|
40
|
+
`/opsx:archive` remains a separate action.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Recovery brief
|
|
2
|
+
|
|
3
|
+
```yaml
|
|
4
|
+
schema: product-definition-as-code/recovery-brief/v1alpha1
|
|
5
|
+
roots: [.]
|
|
6
|
+
include: ['**/*']
|
|
7
|
+
exclude: []
|
|
8
|
+
forbidden: ['**/.env', '**/.env.*', '**/*.pem', '**/*.key', '**/secrets/**']
|
|
9
|
+
ignore: []
|
|
10
|
+
languages: []
|
|
11
|
+
tiers: []
|
|
12
|
+
batch-size: 10
|
|
13
|
+
external-sources: []
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Product scope
|
|
17
|
+
|
|
18
|
+
## Evidence authority and secondary-evidence policy
|
|
19
|
+
|
|
20
|
+
## Known vocabulary, actors and contradictions
|
|
21
|
+
|
|
22
|
+
## Areas requiring human confirmation
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Recovery outcome
|
|
2
|
+
|
|
3
|
+
This artifact is resumable working memory. It is not accepted product truth.
|
|
4
|
+
|
|
5
|
+
## Progress and next bounded batch
|
|
6
|
+
|
|
7
|
+
## Observed evidence and inferred intent
|
|
8
|
+
|
|
9
|
+
## Candidates and provenance
|
|
10
|
+
|
|
11
|
+
## Questions, contradictions and leads
|
|
12
|
+
|
|
13
|
+
## Outcome
|
|
14
|
+
|
|
15
|
+
State either `Candidate baseline produced` or `Insufficient evidence`. A candidate baseline must reference `product-change/change.md` and its proposed artifacts. An insufficient outcome must contain no invented or empty delta.
|
package/dist/index.d.ts
CHANGED
|
@@ -32,9 +32,9 @@ declare function enumerateOpenSpecDocuments(repoRoot: string, options?: Enumerat
|
|
|
32
32
|
declare const openSpecProvider: SddIntegrationProvider;
|
|
33
33
|
|
|
34
34
|
/** The OpenSpec schema name (the directory key OpenSpec resolves). */
|
|
35
|
-
declare const
|
|
35
|
+
declare const OPENSPEC_PRODUCT_CHANGE_SCHEMA_NAME = "product-change";
|
|
36
36
|
/** The repository-relative directory the product schema is installed into. */
|
|
37
|
-
declare const
|
|
37
|
+
declare const OPENSPEC_PRODUCT_CHANGE_SCHEMA_RELATIVE = "openspec/schemas/product-change";
|
|
38
38
|
/**
|
|
39
39
|
* The minimum OpenSpec CLI version the product workflow needs. Project-local schemas are far
|
|
40
40
|
* older, but three 1.7.0 behaviours are load-bearing: `openspec new change` records
|
|
@@ -44,9 +44,12 @@ declare const OPENSPEC_PRODUCT_SCHEMA_RELATIVE = "openspec/schemas/product";
|
|
|
44
44
|
* files are inert data: the citation lane keeps working and the product workflow is reported
|
|
45
45
|
* unavailable, never broken.
|
|
46
46
|
*/
|
|
47
|
-
declare const
|
|
47
|
+
declare const PRODUCT_CHANGE_SCHEMA_MIN_OPENSPEC = "1.7.0";
|
|
48
|
+
/** The separate hosted brownfield recovery workload. */
|
|
49
|
+
declare const OPENSPEC_PRODUCT_RECOVERY_SCHEMA_NAME = "product-recovery";
|
|
50
|
+
declare const OPENSPEC_PRODUCT_RECOVERY_SCHEMA_RELATIVE = "openspec/schemas/product-recovery";
|
|
48
51
|
/** One bundled product-schema file: its path relative to the installed schema directory. */
|
|
49
|
-
interface
|
|
52
|
+
interface ProductChangeSchemaAsset {
|
|
50
53
|
relative: string;
|
|
51
54
|
content: string;
|
|
52
55
|
}
|
|
@@ -54,10 +57,12 @@ interface ProductSchemaAsset {
|
|
|
54
57
|
* Load the bundled product-schema assets, sorted by relative path so installation, metadata and
|
|
55
58
|
* comparison all see one deterministic order.
|
|
56
59
|
*/
|
|
57
|
-
declare function
|
|
60
|
+
declare function loadProductChangeSchemaAssets(): Promise<ProductChangeSchemaAsset[]>;
|
|
61
|
+
/** Load the bundled recovery schema assets using the same deterministic asset contract. */
|
|
62
|
+
declare function loadProductRecoverySchemaAssets(): Promise<ProductChangeSchemaAsset[]>;
|
|
58
63
|
|
|
59
64
|
/** The subdirectory of an OpenSpec change that hosts the PDaC Product Change delta. */
|
|
60
|
-
declare const OPENSPEC_PRODUCT_SUBDIR = "product";
|
|
65
|
+
declare const OPENSPEC_PRODUCT_SUBDIR = "product-change";
|
|
61
66
|
/** The accepted product model, read directly from disk and validated, with its in-memory graph. */
|
|
62
67
|
interface ProductModelInspection {
|
|
63
68
|
repo: ProductRepository;
|
|
@@ -76,14 +81,14 @@ declare function inspectProductModel(root: string): Promise<ProductModelInspecti
|
|
|
76
81
|
interface OpenSpecProductChangeRef {
|
|
77
82
|
/** The OpenSpec change name (the directory under openspec/changes/). */
|
|
78
83
|
name: string;
|
|
79
|
-
/** Absolute path of the hosted PDaC change directory (…/<name>/product). */
|
|
84
|
+
/** Absolute path of the hosted PDaC change directory (…/<name>/product-change). */
|
|
80
85
|
dir: string;
|
|
81
86
|
/** Repository-relative POSIX path of the hosted change.md. */
|
|
82
87
|
file: string;
|
|
83
88
|
}
|
|
84
89
|
/**
|
|
85
|
-
* List the OpenSpec changes that host a PDaC Product Change: pinned to `schema: product` in
|
|
86
|
-
* `.openspec.yaml` AND carrying `product/change.md`. The OpenSpec archive is history and is never
|
|
90
|
+
* List the OpenSpec changes that host a PDaC Product Change: pinned to `schema: product-change` in
|
|
91
|
+
* `.openspec.yaml` AND carrying `product-change/change.md`. The OpenSpec archive is history and is never
|
|
87
92
|
* listed; a change without a product delta (for example one whose honest intent verdict was "no
|
|
88
93
|
* product delta") is not a product change; and a change pinned to another schema is not one
|
|
89
94
|
* either, whatever directories it contains, so it never enters the product rail or its
|
|
@@ -178,7 +183,7 @@ declare const MIN_SUPPORTED_OPENSPEC = "1.0.0";
|
|
|
178
183
|
*/
|
|
179
184
|
declare const OPENSPEC_NPX_SPEC = "@fission-ai/openspec@1";
|
|
180
185
|
/** The PDaC authority context block injected into openspec/config.yaml `context:`. */
|
|
181
|
-
declare const PDAC_CONTEXT_BLOCK = "<!-- pdac:context begin -->\nThis repository uses Product Definition as Code (PDaC). The canonical product definition lives in docs/product/model (actors, journeys, use cases, business rules, domain terms, bounded contexts, structured behaviours, and functional, quality and constraint requirements). OpenSpec artifacts consume it and are never a second source of truth.\nA citation binds consumer text to a canonical artifact: it records the artifact id, a sha256 content digest and an optional verification scenario anchor. Verification reports one status per citation: current, stale, tampered or unresolved.\nTo cite: run `npx prodshape inspect <ID>` to read the current digest, then `npx prodshape cite --id <ID> --digest <digest>` to emit the canonical payload. Wrap it in the document's native comment (`<!-- ... -->` in Markdown) on its own line directly under the text it grounds.\nTo find which artifacts a change impacts, compare the change's intent with the whole product definition first, then widen the result with `npx prodshape impact <ID>`. When the intent contradicts or goes beyond the definition, record that drift in the proposal with the marker `<!-- pdac-drift ids=\"...\" summary=\"...\" -->` (listed by `npx prodshape drift`) and let humans decide \u2014 never fix it quietly.\nEvery current OpenSpec document (proposal, specs, design, tasks and openspec/specs/) carries exactly one explicit scope declaration: `pdac-scope: cited` for a bound document that carries at least one citation, or `pdac-scope: none` with a non-empty human-authored reason (`pdac-scope-reason: <why>` in frontmatter, or `<!-- pdac-scope: none reason=\"<why>\" -->`) for an exempt one. Citations alone never bind: a document without a declaration is unclassified and fails verification, a bound document with zero citations fails, and an exemption without a reason or contradicted by citations fails. Binding and exemption are human declarations: never declare an exemption merely because citations are missing. Verify with `npx prodshape citations verify --provider openspec`: it enumerates the expected current documents, so zero discovered citations is a set of failures, never a pass. Archived changes are excluded by default; `--include-archived` also verifies the citations history carries, reported as warnings, because archived history cannot be edited.\nThe accepted Product Definition changes only through a Product Change: validate it as an overlay while the baseline stays untouched, obtain human product approval (represented by status: approved; the integration verifies the state but cannot identify or judge the actor), apply explicitly on a working branch, and let a human accept the resulting baseline by merging its pull request. A Product Change is not a pull request; apply is not acceptance; neither apply nor merge attests implementation, verification, release or deployment. A Product Change lives under docs/product/changes/ or hosted inside a valid OpenSpec change created with the product schema (product/change.md plus product/proposed/**); its deterministically validated, apply-authorised apply is the only write path into docs/product/model. A spec-driven OpenSpec delivery change never edits docs/product/model directly: it may share a pull request with an applied Product Change or follow later, but it never supplies Product Change status.\n<!-- pdac:context end -->";
|
|
186
|
+
declare const PDAC_CONTEXT_BLOCK = "<!-- pdac:context begin -->\nThis repository uses Product Definition as Code (PDaC). The canonical product definition lives in docs/product/model (actors, journeys, use cases, business rules, domain terms, bounded contexts, structured behaviours, and functional, quality and constraint requirements). OpenSpec artifacts consume it and are never a second source of truth.\nA citation binds consumer text to a canonical artifact: it records the artifact id, a sha256 content digest and an optional verification scenario anchor. Verification reports one status per citation: current, stale, tampered or unresolved.\nTo cite: run `npx prodshape inspect <ID>` to read the current digest, then `npx prodshape cite --id <ID> --digest <digest>` to emit the canonical payload. Wrap it in the document's native comment (`<!-- ... -->` in Markdown) on its own line directly under the text it grounds.\nTo find which artifacts a change impacts, compare the change's intent with the whole product definition first, then widen the result with `npx prodshape impact <ID>`. When the intent contradicts or goes beyond the definition, record that drift in the proposal with the marker `<!-- pdac-drift ids=\"...\" summary=\"...\" -->` (listed by `npx prodshape drift`) and let humans decide \u2014 never fix it quietly.\nEvery current OpenSpec document (proposal, specs, design, tasks and openspec/specs/) carries exactly one explicit scope declaration: `pdac-scope: cited` for a bound document that carries at least one citation, or `pdac-scope: none` with a non-empty human-authored reason (`pdac-scope-reason: <why>` in frontmatter, or `<!-- pdac-scope: none reason=\"<why>\" -->`) for an exempt one. Citations alone never bind: a document without a declaration is unclassified and fails verification, a bound document with zero citations fails, and an exemption without a reason or contradicted by citations fails. Binding and exemption are human declarations: never declare an exemption merely because citations are missing. Verify with `npx prodshape citations verify --provider openspec`: it enumerates the expected current documents, so zero discovered citations is a set of failures, never a pass. Archived changes are excluded by default; `--include-archived` also verifies the citations history carries, reported as warnings, because archived history cannot be edited.\nThe accepted Product Definition changes only through a Product Change: validate it as an overlay while the baseline stays untouched, obtain human product approval (represented by status: approved; the integration verifies the state but cannot identify or judge the actor), apply explicitly on a working branch, and let a human accept the resulting baseline by merging its pull request. A Product Change is not a pull request; apply is not acceptance; neither apply nor merge attests implementation, verification, release or deployment. A Product Change lives under docs/product/changes/ or hosted inside a valid OpenSpec change created with the product schema (product-change/change.md plus product-change/proposed/**); its deterministically validated, apply-authorised apply is the only write path into docs/product/model. A spec-driven OpenSpec delivery change never edits docs/product/model directly: it may share a pull request with an applied Product Change or follow later, but it never supplies Product Change status.\n<!-- pdac:context end -->";
|
|
182
187
|
/** The PDaC citation rules injected per artifact into openspec/config.yaml `rules:`. */
|
|
183
188
|
declare const PDAC_RULES: Record<string, string[]>;
|
|
184
189
|
/** The PDaC operation guidance injected into openspec/config.yaml `operations:`. */
|
|
@@ -240,6 +245,11 @@ interface OpenSpecIntegrationMeta {
|
|
|
240
245
|
requiresOpenspec: string;
|
|
241
246
|
files: Record<string, string>;
|
|
242
247
|
};
|
|
248
|
+
recoverySchema?: {
|
|
249
|
+
name: string;
|
|
250
|
+
requiresOpenspec: string;
|
|
251
|
+
files: Record<string, string>;
|
|
252
|
+
};
|
|
243
253
|
}
|
|
244
254
|
/** The repository-relative path of the integration metadata file, for callers that probe it. */
|
|
245
255
|
declare const OPENSPEC_META_RELATIVE = ".product/integrations/openspec.json";
|
|
@@ -402,4 +412,4 @@ declare function removeOpenSpecIntegration(root: string, options?: {
|
|
|
402
412
|
preserved: string[];
|
|
403
413
|
}>;
|
|
404
414
|
|
|
405
|
-
export { type DeliveryContextBundle, type DeliveryContextEntry, MIN_SUPPORTED_OPENSPEC, type ManagedStrings, OPENSPEC_CI_EXAMPLE_RELATIVE, OPENSPEC_META_RELATIVE, OPENSPEC_NPX_SPEC,
|
|
415
|
+
export { type DeliveryContextBundle, type DeliveryContextEntry, MIN_SUPPORTED_OPENSPEC, type ManagedStrings, OPENSPEC_CI_EXAMPLE_RELATIVE, OPENSPEC_META_RELATIVE, OPENSPEC_NPX_SPEC, OPENSPEC_PRODUCT_CHANGE_SCHEMA_NAME, OPENSPEC_PRODUCT_CHANGE_SCHEMA_RELATIVE, OPENSPEC_PRODUCT_RECOVERY_SCHEMA_NAME, OPENSPEC_PRODUCT_RECOVERY_SCHEMA_RELATIVE, OPENSPEC_PRODUCT_SUBDIR, OPENSPEC_VERIFY_COMMAND, type OpenSpecIntegrationMeta, OpenSpecMetaError, type OpenSpecProductApplyOutcome, type OpenSpecProductApplyResult, type OpenSpecProductChangeRef, type OpenSpecProductChangeValidation, PDAC_CONTEXT_BLOCK, PDAC_OPERATIONS, PDAC_RULES, PRODUCT_CHANGE_SCHEMA_MIN_OPENSPEC, type ProductChangeSchemaAsset, type ProductModelInspection, addOpenSpecIntegration, applyOpenSpecProductChange, bootstrapOpenSpecWorkspace, checkOpenSpecIntegration, currentManagedStrings, deriveDeliveryContext, detectOpenSpecVersion, enumerateOpenSpecDocuments, inspectProductModel, isOpenSpecCliAvailable, isOpenSpecIntegrationInstalled, isOpenSpecWorkspace, listOpenSpecProductChanges, loadOpenSpecProductChange, loadProductChangeSchemaAssets, loadProductRecoverySchemaAssets, mergeConfig, openSpecProvider, readOpenSpecConfig, removeOpenSpecIntegration, renderCiExample, serializeConfig, updateOpenSpecIntegration, validateOpenSpecProductChange };
|