@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 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: metadata paths are validated and confined to `openspec/schemas/product/`; `prodshape integration add openspec` collides on every pre-existing unrecorded target, even when byte-identical; `update` replaces or removes only content whose recorded digest still proves ownership, including obsolete assets; and `remove` deletes only recorded, proven-managed files while preserving and reporting unrecorded or hand-edited ones. With no recorded product schema it touches nothing under `openspec/schemas/`. Dry runs report exactly what the real operation would do.
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
- 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`. 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.
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
@@ -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.
@@ -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 OPENSPEC_PRODUCT_SCHEMA_NAME = "product";
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 OPENSPEC_PRODUCT_SCHEMA_RELATIVE = "openspec/schemas/product";
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 PRODUCT_SCHEMA_MIN_OPENSPEC = "1.7.0";
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 ProductSchemaAsset {
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 loadProductSchemaAssets(): Promise<ProductSchemaAsset[]>;
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, OPENSPEC_PRODUCT_SCHEMA_NAME, OPENSPEC_PRODUCT_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_SCHEMA_MIN_OPENSPEC, type ProductModelInspection, type ProductSchemaAsset, addOpenSpecIntegration, applyOpenSpecProductChange, bootstrapOpenSpecWorkspace, checkOpenSpecIntegration, currentManagedStrings, deriveDeliveryContext, detectOpenSpecVersion, enumerateOpenSpecDocuments, inspectProductModel, isOpenSpecCliAvailable, isOpenSpecIntegrationInstalled, isOpenSpecWorkspace, listOpenSpecProductChanges, loadOpenSpecProductChange, loadProductSchemaAssets, mergeConfig, openSpecProvider, readOpenSpecConfig, removeOpenSpecIntegration, renderCiExample, serializeConfig, updateOpenSpecIntegration, validateOpenSpecProductChange };
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 };