@encore-os/eos-spec 0.3.1 → 0.5.0

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.
Files changed (81) hide show
  1. package/dist/commands/audit.js +11 -3
  2. package/dist/commands/audit.js.map +1 -1
  3. package/dist/commands/complete.js +41 -14
  4. package/dist/commands/complete.js.map +1 -1
  5. package/dist/commands/conformance.js +27 -0
  6. package/dist/commands/conformance.js.map +1 -1
  7. package/dist/commands/gen-tests.js +5 -2
  8. package/dist/commands/gen-tests.js.map +1 -1
  9. package/dist/commands/init.js +96 -22
  10. package/dist/commands/init.js.map +1 -1
  11. package/dist/commands/next.d.ts +20 -4
  12. package/dist/commands/next.js +53 -15
  13. package/dist/commands/next.js.map +1 -1
  14. package/dist/commands/precedent.d.ts +2 -0
  15. package/dist/commands/precedent.js +12 -3
  16. package/dist/commands/precedent.js.map +1 -1
  17. package/dist/commands/reconcile.d.ts +3 -10
  18. package/dist/commands/reconcile.js +6 -37
  19. package/dist/commands/reconcile.js.map +1 -1
  20. package/dist/commands/signoff.js +33 -5
  21. package/dist/commands/signoff.js.map +1 -1
  22. package/dist/commands/verify-acs.js +7 -4
  23. package/dist/commands/verify-acs.js.map +1 -1
  24. package/dist/index.d.ts +3 -2
  25. package/dist/index.js +15 -3
  26. package/dist/index.js.map +1 -1
  27. package/dist/lib/code-evidence.js +2 -1
  28. package/dist/lib/code-evidence.js.map +1 -1
  29. package/dist/lib/coherence.d.ts +2 -2
  30. package/dist/lib/coherence.js +7 -6
  31. package/dist/lib/coherence.js.map +1 -1
  32. package/dist/lib/config.d.ts +34 -2
  33. package/dist/lib/config.js +45 -3
  34. package/dist/lib/config.js.map +1 -1
  35. package/dist/lib/discovery-defaults.d.ts +20 -0
  36. package/dist/lib/discovery-defaults.js +21 -0
  37. package/dist/lib/discovery-defaults.js.map +1 -0
  38. package/dist/lib/embedding-store.d.ts +0 -2
  39. package/dist/lib/embedding-store.js +1 -1
  40. package/dist/lib/embedding-store.js.map +1 -1
  41. package/dist/lib/exec.d.ts +0 -2
  42. package/dist/lib/exec.js +1 -12
  43. package/dist/lib/exec.js.map +1 -1
  44. package/dist/lib/frontmatter.d.ts +5 -1
  45. package/dist/lib/frontmatter.js.map +1 -1
  46. package/dist/lib/migration-collision.d.ts +5 -4
  47. package/dist/lib/migration-collision.js +8 -6
  48. package/dist/lib/migration-collision.js.map +1 -1
  49. package/dist/lib/next-action.d.ts +19 -2
  50. package/dist/lib/next-action.js +28 -6
  51. package/dist/lib/next-action.js.map +1 -1
  52. package/dist/lib/ollama-embed.d.ts +0 -9
  53. package/dist/lib/ollama-embed.js +0 -35
  54. package/dist/lib/ollama-embed.js.map +1 -1
  55. package/dist/lib/pipeline-config.js +40 -2
  56. package/dist/lib/pipeline-config.js.map +1 -1
  57. package/dist/lib/pipeline-map.d.ts +30 -0
  58. package/dist/lib/pipeline-map.js +86 -5
  59. package/dist/lib/pipeline-map.js.map +1 -1
  60. package/dist/lib/pipeline-schema.d.ts +25 -1
  61. package/dist/lib/pipeline-schema.js +3 -0
  62. package/dist/lib/pipeline-schema.js.map +1 -1
  63. package/dist/lib/predicate-registry.js +28 -1
  64. package/dist/lib/predicate-registry.js.map +1 -1
  65. package/dist/lib/reconcile-core.d.ts +26 -0
  66. package/dist/lib/reconcile-core.js +43 -0
  67. package/dist/lib/reconcile-core.js.map +1 -0
  68. package/dist/lib/scaffold-templates.d.ts +30 -0
  69. package/dist/lib/scaffold-templates.js +203 -0
  70. package/dist/lib/scaffold-templates.js.map +1 -0
  71. package/dist/lib/spec-pure.js +44 -1
  72. package/dist/lib/spec-pure.js.map +1 -1
  73. package/dist/lib/specs.d.ts +17 -0
  74. package/dist/lib/specs.js.map +1 -1
  75. package/dist/lib/test-generator.d.ts +1 -1
  76. package/dist/lib/test-generator.js +3 -2
  77. package/dist/lib/test-generator.js.map +1 -1
  78. package/dist/lib/verifies-scan.d.ts +5 -1
  79. package/dist/lib/verifies-scan.js +9 -3
  80. package/dist/lib/verifies-scan.js.map +1 -1
  81. package/package.json +4 -4
@@ -19,10 +19,24 @@ export type StageDef = {
19
19
  invocation: string;
20
20
  /** Human-readable reason shown when this is the next step. */
21
21
  reason: string;
22
- /** Only applies to regulated cores (cl/pm/hr/rh/gr). */
22
+ /** Only applies to regulated cores (cl/pm/hr/rh/gr). Shorthand for an
23
+ * applicability predicate keyed on `isRegulated`. */
23
24
  regulatedOnly?: boolean;
25
+ /** Name of a registry predicate that decides whether this stage applies to a
26
+ * given spec — the general form of `regulatedOnly`. When set, the stage is
27
+ * walked (and contributes to `computeStage`) ONLY for specs the predicate
28
+ * accepts, regardless of core. Used to widen the compliance gate beyond the
29
+ * regulated cores to PHI/PII-bearing specs (encore1 `complianceGating`, #1372)
30
+ * without hardcoding that logic into the engine — the builder layout, which has
31
+ * no compliance stage, never references it. Takes precedence over `regulatedOnly`. */
32
+ appliesWhen?: string;
24
33
  /** Advisory — surfaced as a hint but never blocks progression. */
25
34
  optional?: boolean;
35
+ /** Phase 1 parity gate: this stage participates in the navigator walk ONLY under
36
+ * `next --strict`. It carries no `completesStatus` (never moves computeStage), so
37
+ * default `next`/`computeStage`/`reconcile` are unaffected; under `--strict` it
38
+ * surfaces as a BLOCKING action when its gate is unmet. */
39
+ strictOnly?: boolean;
26
40
  /** The pipeline_status enum value this transition completes (for schema-coverage + reconciliation). */
27
41
  completesStatus?: string;
28
42
  };
@@ -41,6 +55,16 @@ export type PipelineSchema = {
41
55
  statusOrder: string[];
42
56
  stages: StageDef[];
43
57
  caps: CapDef[];
58
+ /** When true, the NAVIGATOR treats a not-done stage as satisfied if its
59
+ * `completesStatus` ranks strictly BELOW the spec's computed stage — i.e. a
60
+ * later stage's artifact already exists, so a missing earlier (soft) marker is
61
+ * superseded rather than re-surfaced. Models encoreos's #1593 behavior: a spec
62
+ * reviewed + compliance-signed + planned + tasked but missing the early
63
+ * `<!-- validated: -->` marker routes to the implement/complete tail, not back
64
+ * to validate-spec. `computeStage` is unaffected (it already reports the
65
+ * furthest-reached stage); only `recommendAction`'s walk honors this. Opt-in
66
+ * per layout — the builder layout omits it (default false) and is unchanged. */
67
+ supersedeSoftGates?: boolean;
44
68
  };
45
69
  /** Validate a {@link PipelineSchema} against its {@link PredicateRegistry}: every
46
70
  * stage gate and cap predicate must be registered, and every `completesStatus`/
@@ -6,6 +6,9 @@ export function validateSchema(schema, registry) {
6
6
  if (!registry[st.gate]) {
7
7
  throw new Error(`pipeline schema: unknown gate predicate '${st.gate}' for stage '${st.id}'`);
8
8
  }
9
+ if (st.appliesWhen && !registry[st.appliesWhen]) {
10
+ throw new Error(`pipeline schema: unknown appliesWhen predicate '${st.appliesWhen}' for stage '${st.id}'`);
11
+ }
9
12
  if (st.completesStatus && !schema.statusOrder.includes(st.completesStatus)) {
10
13
  throw new Error(`pipeline schema: stage '${st.id}' completesStatus '${st.completesStatus}' not in statusOrder`);
11
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-schema.js","sourceRoot":"","sources":["../../src/lib/pipeline-schema.ts"],"names":[],"mappings":"AAmDA;;wEAEwE;AACxE,MAAM,UAAU,cAAc,CAAC,MAAsB,EAAE,QAA2B;IAChF,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAC/B,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,4CAA4C,EAAE,CAAC,IAAI,gBAAgB,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,EAAE,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,KAAK,CAAC,2BAA2B,EAAE,CAAC,EAAE,sBAAsB,EAAE,CAAC,eAAe,sBAAsB,CAAC,CAAC;QAClH,CAAC;IACH,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,2CAA2C,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,CAAC,QAAQ,sBAAsB,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"pipeline-schema.js","sourceRoot":"","sources":["../../src/lib/pipeline-schema.ts"],"names":[],"mappings":"AA2EA;;wEAEwE;AACxE,MAAM,UAAU,cAAc,CAAC,MAAsB,EAAE,QAA2B;IAChF,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAC/B,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,4CAA4C,EAAE,CAAC,IAAI,gBAAgB,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,EAAE,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,mDAAmD,EAAE,CAAC,WAAW,gBAAgB,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7G,CAAC;QACD,IAAI,EAAE,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,KAAK,CAAC,2BAA2B,EAAE,CAAC,EAAE,sBAAsB,EAAE,CAAC,eAAe,sBAAsB,CAAC,CAAC;QAClH,CAAC;IACH,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,2CAA2C,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,CAAC,QAAQ,sBAAsB,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -11,8 +11,16 @@ export const DEFAULT_PREDICATES = {
11
11
  hasResearch: (s) => s.signals.hasResearch,
12
12
  // spec-review.
13
13
  hasSpecReview: (s) => s.signals.hasSpecReview,
14
- // compliance-review (regulatedOnly).
14
+ // compliance-review (gate predicate).
15
15
  hasComplianceSignoff: (s) => s.signals.hasComplianceSignoff,
16
+ // compliance-review APPLICABILITY (encore1 `appliesWhen`, #1372 PHI-widening):
17
+ // the compliance gate applies to regulated cores AND to PHI/PII/billing/
18
+ // credentialing-bearing specs in ANY core. Reuses the existing `isSensitive`
19
+ // signal (the engine's PHI-bearing detector) rather than a parallel
20
+ // `isPhiBearing`, so there is a single source of the compliance-gating
21
+ // condition. The builder layout has no compliance stage and never references
22
+ // this, so widening it here cannot affect builder.
23
+ complianceGating: (s) => s.signals.isRegulated || Boolean(s.signals.isSensitive),
16
24
  // draft-acs: done when there are no user stories, or ACs are drafted.
17
25
  acsDraftedOrNoStories: (s) => !s.signals.hasUserStories || s.signals.hasAcceptanceCriteria,
18
26
  // generate-tests: ACs absent, OR an active generated suite / verified ACs / linked local test exists (B5 + C1).
@@ -36,5 +44,24 @@ export const DEFAULT_PREDICATES = {
36
44
  hasTasks: (s) => s.hasTasks,
37
45
  // AC cap predicate (computeStage): caps below tasks_generated when ACs are absent.
38
46
  hasAcceptanceCriteria: (s) => s.signals.hasAcceptanceCriteria,
47
+ // ── Phase 1 parity gates (Finding A) — wired as strictOnly schema stages with NO
48
+ // completesStatus, so they NEVER move computeStage (the parity gate is over a
49
+ // fixture corpus that predates these signals). Each is SATISFIED-by-default and
50
+ // only fails once the genuinely-missing condition is present, so the bare CLI's
51
+ // default `next` is unchanged and only `next --strict` surfaces them as BLOCKING.
52
+ // research-before-review: research grounding must precede spec-review on the
53
+ // non-regulated path. Nothing to order until the spec is reviewed; once reviewed,
54
+ // a research appendix must exist. (Regulated cores already hard-order research via
55
+ // the regulatedOnly `ground-research` stage + the research honest-cap.)
56
+ hasResearchBeforeReview: (s) => !s.signals.hasSpecReview || s.signals.hasResearch,
57
+ // revalidate-after-review: spec-review auto-applies edits; the pipeline re-runs
58
+ // validate-spec to catch what they broke. Satisfied until the spec is reviewed;
59
+ // once reviewed, a `<!-- revalidated-after-review: -->` marker must be present.
60
+ hasReValidationAfterReview: (s) => !s.signals.hasSpecReview || Boolean(s.signals.hasReValidationAfterReview),
61
+ // compliance-for-sensitive: a spec carrying a PHI/PII/billing/credentialing signal
62
+ // (ANY core, not just regulated) needs a compliance sign-off. Non-sensitive specs
63
+ // pass. This ADDS the sensitive-non-regulated path; it does NOT replace the
64
+ // regulated-core `compliance-review` stage (which still gates on `hasComplianceSignoff`).
65
+ hasComplianceForSensitive: (s) => !s.signals.isSensitive || s.signals.hasComplianceSignoff,
39
66
  };
40
67
  //# sourceMappingURL=predicate-registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-registry.js","sourceRoot":"","sources":["../../src/lib/predicate-registry.ts"],"names":[],"mappings":"AAEA;;;sFAGsF;AACtF,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,kFAAkF;IAClF,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU;IAC/B,6CAA6C;IAC7C,oBAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB;IAC3D,+EAA+E;IAC/E,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW;IACzC,eAAe;IACf,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa;IAC7C,qCAAqC;IACrC,oBAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB;IAC3D,sEAAsE;IACtE,qBAAqB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,IAAI,CAAC,CAAC,OAAO,CAAC,qBAAqB;IAC1F,gHAAgH;IAChH,sBAAsB,EAAE,CAAC,CAAC,EAAE,EAAE,CAC5B,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB;QAChC,CAAC,CAAC,OAAO,CAAC,uBAAuB;QACjC,CAAC,CAAC,OAAO,CAAC,6BAA6B;QACvC,CAAC,CAAC,OAAO,CAAC,kBAAkB;IAC9B,gFAAgF;IAChF,6EAA6E;IAC7E,+EAA+E;IAC/E,6DAA6D;IAC7D,mBAAmB,EAAE,CAAC,CAAC,EAAE,EAAE,CACzB,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB;QAChC,CAAC,CAAC,OAAO,CAAC,iBAAiB;QAC3B,CAAC,CAAC,OAAO,CAAC,6BAA6B;QACvC,CAAC,CAAC,OAAO,CAAC,kBAAkB;IAC9B,gDAAgD;IAChD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY;IAC3C,gCAAgC;IAChC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO;IACzB,mCAAmC;IACnC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ;IAC3B,mFAAmF;IACnF,qBAAqB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB;CAC9D,CAAC"}
1
+ {"version":3,"file":"predicate-registry.js","sourceRoot":"","sources":["../../src/lib/predicate-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { SpecFile } from './specs.js';
2
+ /**
3
+ * The per-spec reconcile core, extracted so the `reconcile` command AND the
4
+ * `signoff --reconcile` post-step share ONE implementation and cannot drift
5
+ * (Finding A item 4: `reconcile` was never auto-invoked, so `pipeline_status`
6
+ * silently lagged the artifacts a sign-off had just produced). fs-bound (reads +
7
+ * writes the spec markdown) — stays behind the package main entry, never `/pure`.
8
+ */
9
+ export type ReconcileDirection = 'ok' | 'lagging' | 'overstated';
10
+ /** Classify frontmatter status vs the artifact-derived stage. */
11
+ export declare function classify(written: string | undefined, computed: string | undefined): ReconcileDirection;
12
+ export type ReconcileRow = {
13
+ id: string;
14
+ core: string;
15
+ written?: string;
16
+ computed?: string;
17
+ direction: ReconcileDirection;
18
+ };
19
+ /**
20
+ * Recompute one spec's pipeline_status from its on-disk artifacts and, when
21
+ * `write` is set, surgically materialize the computed status (plus a healed
22
+ * `artifacts.tasks` pointer) into the spec frontmatter. Returns the divergence
23
+ * row regardless of whether anything was written. Mirrors the inner loop body of
24
+ * the `reconcile` command exactly (the command now delegates here).
25
+ */
26
+ export declare function reconcileSpec(repoRoot: string, spec: SpecFile, write: boolean): ReconcileRow;
@@ -0,0 +1,43 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { isAbsolute, join } from 'node:path';
3
+ import { resolveTasksArtifact, setPipelineStatus, setTasksArtifact } from './frontmatter.js';
4
+ import { computeStage, rank } from './pipeline-map.js';
5
+ /** Classify frontmatter status vs the artifact-derived stage. */
6
+ export function classify(written, computed) {
7
+ if (written === computed)
8
+ return 'ok';
9
+ return rank(computed) > rank(written) ? 'lagging' : 'overstated';
10
+ }
11
+ /**
12
+ * Recompute one spec's pipeline_status from its on-disk artifacts and, when
13
+ * `write` is set, surgically materialize the computed status (plus a healed
14
+ * `artifacts.tasks` pointer) into the spec frontmatter. Returns the divergence
15
+ * row regardless of whether anything was written. Mirrors the inner loop body of
16
+ * the `reconcile` command exactly (the command now delegates here).
17
+ */
18
+ export function reconcileSpec(repoRoot, spec, write) {
19
+ const computed = computeStage(spec);
20
+ const written = spec.signals.pipelineStatus;
21
+ const direction = classify(written, computed);
22
+ if (write && computed) {
23
+ const original = readFileSync(spec.path, 'utf8');
24
+ let text = original;
25
+ if (direction !== 'ok')
26
+ text = setPipelineStatus(text, computed);
27
+ // Materialize artifacts.tasks alongside pipeline_status so a spec that reaches
28
+ // tasks_generated satisfies the pipeline-status validator (pipeline/missing-
29
+ // tasks-artifact) without hand-editing (#997 Bug 2). Non-destructive: a VALID
30
+ // existing pointer is preserved; only an absent or stale pointer is set to the
31
+ // canonical path, and only when that canonical file actually exists (#16).
32
+ if (spec.hasTasks) {
33
+ const fileExists = (rel) => existsSync(isAbsolute(rel) ? rel : join(repoRoot, rel));
34
+ const next = resolveTasksArtifact(text, `specs/${spec.core}/tasks/${spec.id}-TASKS.md`, fileExists);
35
+ if (next)
36
+ text = setTasksArtifact(text, next);
37
+ }
38
+ if (text !== original)
39
+ writeFileSync(spec.path, text, 'utf8');
40
+ }
41
+ return { id: spec.id, core: spec.core, written, computed, direction };
42
+ }
43
+ //# sourceMappingURL=reconcile-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile-core.js","sourceRoot":"","sources":["../../src/lib/reconcile-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAavD,iEAAiE;AACjE,MAAM,UAAU,QAAQ,CAAC,OAA2B,EAAE,QAA4B;IAChF,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACtC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;AACnE,CAAC;AAUD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,IAAc,EAAE,KAAc;IAC5E,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;IAC5C,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,IAAI,GAAG,QAAQ,CAAC;QACpB,IAAI,SAAS,KAAK,IAAI;YAAE,IAAI,GAAG,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACjE,+EAA+E;QAC/E,6EAA6E;QAC7E,8EAA8E;QAC9E,+EAA+E;QAC/E,2EAA2E;QAC3E,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5F,MAAM,IAAI,GAAG,oBAAoB,CAAC,IAAI,EAAE,SAAS,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;YACpG,IAAI,IAAI;gBAAE,IAAI,GAAG,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,IAAI,KAAK,QAAQ;YAAE,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACxE,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Inlined scaffold content for `eos-spec init --scaffold` (TOOL-03 AC-5). The npm
3
+ * tarball ships only `dist/` + `bin/` (package.json `files`), so a bootstrap must
4
+ * carry its config + template bodies as compiled string constants — there is no
5
+ * `templates/` data dir in the published package. This module is fs-free: it holds
6
+ * only strings, so `init.ts` writes them with its own never-clobber primitive.
7
+ *
8
+ * The templates are intentionally minimal, valid stubs (mirroring the engine's own
9
+ * test corpus). `create` fills the `{{ID}}/{{CORE}}/{{TITLE}}/{{DATE}}` placeholders
10
+ * via `applyHeader`; `init --scaffold` writes the template files verbatim (the
11
+ * placeholders are for `create`, not for scaffolding) and only interpolates the
12
+ * config's `last_updated`.
13
+ */
14
+ /** Relative path (from repo root) of the scaffolded config. */
15
+ export declare const SCAFFOLD_CONFIG_PATH = "specs/config.yaml";
16
+ /**
17
+ * A portable default `specs/config.yaml`. One example core (`app`); a consumer edits
18
+ * `cores:` to match their domain. Carries the optional TOOL-03 discovery-path keys
19
+ * with their fork-layout defaults made explicit, so a new repo sees how to retarget
20
+ * `paths.migrations` / `generated_tests` / `verifies_*` for its own layout.
21
+ */
22
+ export declare function defaultConfigYaml(lastUpdated: string): string;
23
+ /**
24
+ * Template files written under \`specs/_templates/\` by \`init --scaffold\`, verbatim
25
+ * (placeholders intact). \`rel\` is relative to repo root.
26
+ */
27
+ export declare const SCAFFOLD_TEMPLATE_FILES: ReadonlyArray<{
28
+ rel: string;
29
+ content: string;
30
+ }>;
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Inlined scaffold content for `eos-spec init --scaffold` (TOOL-03 AC-5). The npm
3
+ * tarball ships only `dist/` + `bin/` (package.json `files`), so a bootstrap must
4
+ * carry its config + template bodies as compiled string constants — there is no
5
+ * `templates/` data dir in the published package. This module is fs-free: it holds
6
+ * only strings, so `init.ts` writes them with its own never-clobber primitive.
7
+ *
8
+ * The templates are intentionally minimal, valid stubs (mirroring the engine's own
9
+ * test corpus). `create` fills the `{{ID}}/{{CORE}}/{{TITLE}}/{{DATE}}` placeholders
10
+ * via `applyHeader`; `init --scaffold` writes the template files verbatim (the
11
+ * placeholders are for `create`, not for scaffolding) and only interpolates the
12
+ * config's `last_updated`.
13
+ */
14
+ /** Relative path (from repo root) of the scaffolded config. */
15
+ export const SCAFFOLD_CONFIG_PATH = 'specs/config.yaml';
16
+ /**
17
+ * A portable default `specs/config.yaml`. One example core (`app`); a consumer edits
18
+ * `cores:` to match their domain. Carries the optional TOOL-03 discovery-path keys
19
+ * with their fork-layout defaults made explicit, so a new repo sees how to retarget
20
+ * `paths.migrations` / `generated_tests` / `verifies_*` for its own layout.
21
+ */
22
+ export function defaultConfigYaml(lastUpdated) {
23
+ return `# Spec workflow configuration — consumed by the @encore-os/eos-spec engine.
24
+ # Scaffolded by \`eos-spec init --scaffold\`. Edit \`cores:\` to match your domain,
25
+ # then \`eos-spec create <CORE>-01 "Title"\` to author your first spec.
26
+ version: 1
27
+ last_updated: ${lastUpdated}
28
+
29
+ # Cores that own specs. Order is presentation order. Add one row per area; the id
30
+ # is the spec-id prefix (e.g. core \`app\` ⇒ \`APP-01\`).
31
+ cores:
32
+ - id: app
33
+ name: Application
34
+
35
+ # Pipeline stages — tracked in spec frontmatter as \`pipeline_status:\`.
36
+ pipeline_stages:
37
+ - id: stub
38
+ description: File created, content placeholder
39
+ - id: clarified
40
+ description: Ambiguities resolved
41
+ - id: validated
42
+ description: Structure verified against the template
43
+ - id: reviewed
44
+ description: Review completed
45
+ - id: planned
46
+ description: Implementation plan written
47
+ - id: tasks_generated
48
+ description: TASKS.md created; ready for implementation
49
+
50
+ # Status enum — displayed in spec frontmatter \`status:\`.
51
+ statuses:
52
+ - id: specification
53
+ label: "📋 Specification"
54
+ description: Drafting; not ready to implement
55
+ - id: in_progress
56
+ label: "🔵 In Progress"
57
+ description: Implementation underway
58
+ - id: complete
59
+ label: "✅ Complete"
60
+ description: All tasks complete and validated
61
+ - id: archived
62
+ label: "🗄️ Archived"
63
+ description: Moved to specs/{core}/archive/
64
+ - id: superseded
65
+ label: "📋 Superseded"
66
+ description: Replaced by another spec; kept for traceability
67
+
68
+ # Directory layout (relative to specs/{core}/).
69
+ paths:
70
+ specs: specs
71
+ plans: plans
72
+ tasks: tasks
73
+ archive: archive
74
+ # Discovery paths (TOOL-03). Optional — these defaults match the fork layout;
75
+ # retarget them if your repo keeps migrations / generated tests / @verifies
76
+ # tests elsewhere.
77
+ migrations: supabase/migrations
78
+ generated_tests: e2e/generated
79
+ verifies_scan_roots: [tests, src]
80
+ verifies_backlink_roots: [e2e, src, runner, scripts]
81
+
82
+ # Templates — by intent. Paths are relative to repo root.
83
+ templates:
84
+ full_spec: specs/_templates/SPEC_TEMPLATE.md
85
+ lite_spec: specs/_templates/SPEC_TEMPLATE_LITE.md
86
+ enhancement_single: specs/_templates/SPEC_TEMPLATE_LITE.md
87
+ plan: specs/_templates/PLAN_TEMPLATE.md
88
+ tasks: specs/_templates/TASKS_TEMPLATE.md
89
+
90
+ # Repo rules that override scoring. Empty by default; add your own.
91
+ hard_gates: []
92
+
93
+ # Unified CLI invocations for automation (run from repo root).
94
+ commands:
95
+ unified:
96
+ whats_next: "eos-spec next"
97
+ list: "eos-spec list"
98
+ create: "eos-spec create"
99
+ legacy: {}
100
+
101
+ # Archive policy — what \`eos-spec archive\` does.
102
+ archive:
103
+ enabled: true
104
+ trigger: status_complete_for_n_days
105
+ threshold_days: 30
106
+ destination: specs/{core}/archive/
107
+ preserves:
108
+ - the spec markdown
109
+ removes_from:
110
+ - any index/registry docs listing the spec as active
111
+
112
+ delta_types:
113
+ - additive
114
+ - modifying
115
+
116
+ # Defaults applied when fields are omitted.
117
+ defaults:
118
+ spec_version: "1.0"
119
+ test_coverage_target: 80
120
+ `;
121
+ }
122
+ const SPEC_TEMPLATE = `---
123
+ # Replace placeholder values when authoring.
124
+ id: {{ID}}
125
+ title: "{{TITLE}}"
126
+ core: {{CORE}}
127
+ status: specification
128
+ version: "1.0"
129
+ created: "{{DATE}}"
130
+ updated: "{{DATE}}"
131
+ pipeline_status: stub
132
+ acceptance_criteria: []
133
+ ---
134
+ <!-- SCAFFOLD-STUB: fill all sections and delete this line before sign-off -->
135
+
136
+ # {{ID}} {{TITLE}}
137
+
138
+ ## Summary
139
+
140
+ One paragraph: what the feature is and who it's for.
141
+
142
+ ## User Stories {#user-stories}
143
+
144
+ - **US-1** [planned] As a *role*, I want *capability* so that *value*.
145
+
146
+ ## Acceptance Criteria
147
+
148
+ Authoritative copy is the \`acceptance_criteria:\` frontmatter.
149
+
150
+ ## Test Plan
151
+
152
+ How each AC is proven.
153
+ `;
154
+ const SPEC_TEMPLATE_LITE = `---
155
+ id: {{ID}}
156
+ title: "{{TITLE}}"
157
+ core: {{CORE}}
158
+ status: specification
159
+ version: "1.0"
160
+ pipeline_status: stub
161
+ acceptance_criteria: []
162
+ ---
163
+ <!-- SCAFFOLD-STUB: fill all sections and delete this line before sign-off -->
164
+
165
+ # {{ID}} {{TITLE}}
166
+
167
+ ## Summary
168
+
169
+ What changes and why.
170
+ `;
171
+ const PLAN_TEMPLATE = `# {{ID}} {{TITLE}} — Implementation Plan
172
+
173
+ ## Phases
174
+
175
+ 1. …
176
+ `;
177
+ const TASKS_TEMPLATE = `# {{ID}} {{TITLE}} — Tasks
178
+
179
+ - [ ] T1 First task
180
+ `;
181
+ const SPEC_GUIDE = `# Spec Guide
182
+
183
+ A decision tree for authoring specs. Replace this stub with your conventions; its
184
+ presence satisfies \`eos-spec init\`.
185
+ `;
186
+ const TEMPLATE_INDEX = `# Template Index
187
+
188
+ Which template to use when. Replace this stub with your selection guide; its
189
+ presence satisfies \`eos-spec init\`.
190
+ `;
191
+ /**
192
+ * Template files written under \`specs/_templates/\` by \`init --scaffold\`, verbatim
193
+ * (placeholders intact). \`rel\` is relative to repo root.
194
+ */
195
+ export const SCAFFOLD_TEMPLATE_FILES = [
196
+ { rel: 'specs/_templates/SPEC_TEMPLATE.md', content: SPEC_TEMPLATE },
197
+ { rel: 'specs/_templates/SPEC_TEMPLATE_LITE.md', content: SPEC_TEMPLATE_LITE },
198
+ { rel: 'specs/_templates/PLAN_TEMPLATE.md', content: PLAN_TEMPLATE },
199
+ { rel: 'specs/_templates/TASKS_TEMPLATE.md', content: TASKS_TEMPLATE },
200
+ { rel: 'specs/_templates/SPEC_GUIDE.md', content: SPEC_GUIDE },
201
+ { rel: 'specs/_templates/TEMPLATE_INDEX.md', content: TEMPLATE_INDEX },
202
+ ];
203
+ //# sourceMappingURL=scaffold-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold-templates.js","sourceRoot":"","sources":["../../src/lib/scaffold-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,+DAA+D;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAExD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,OAAO;;;;gBAIO,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6F1B,CAAC;AACF,CAAC;AAED,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BrB,CAAC;AAEF,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;CAgB1B,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;CAKrB,CAAC;AAEF,MAAM,cAAc,GAAG;;;CAGtB,CAAC;AAEF,MAAM,UAAU,GAAG;;;;CAIlB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;CAItB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAoD;IACtF,EAAE,GAAG,EAAE,mCAAmC,EAAE,OAAO,EAAE,aAAa,EAAE;IACpE,EAAE,GAAG,EAAE,wCAAwC,EAAE,OAAO,EAAE,kBAAkB,EAAE;IAC9E,EAAE,GAAG,EAAE,mCAAmC,EAAE,OAAO,EAAE,aAAa,EAAE;IACpE,EAAE,GAAG,EAAE,oCAAoC,EAAE,OAAO,EAAE,cAAc,EAAE;IACtE,EAAE,GAAG,EAAE,gCAAgC,EAAE,OAAO,EAAE,UAAU,EAAE;IAC9D,EAAE,GAAG,EAAE,oCAAoC,EAAE,OAAO,EAAE,cAAc,EAAE;CACvE,CAAC"}
@@ -20,6 +20,28 @@ import { acStatusCounts, allAcceptanceCriteriaTerminal } from './requirements.js
20
20
  export const REGULATED_CORES = new Set(['cl', 'pm', 'hr', 'rh', 'gr']);
21
21
  /** The marker the generator emits for an AC-less spec. */
22
22
  const GENERATED_NO_AC_MARKER = 'no acceptance_criteria — run encore-spec-ac-draft first';
23
+ /** Keywords that mark a spec as carrying sensitive data — PHI/PII/billing/
24
+ * credentialing. The `/spec-pipeline` step-3b compliance gate fires on these
25
+ * mentions in ANY core (not just the regulated `cl/pm/hr/rh/gr` set), so the
26
+ * engine must detect them to gate `hasComplianceForSensitive` at parity with the
27
+ * command prose. Matched at word boundaries, case-insensitively, over frontmatter
28
+ * + body. Kept to high-signal regime tokens so an incidental mention never trips
29
+ * it; a spec can also opt in explicitly via a `<!-- sensitive -->`/`<!-- sensitive: -->`
30
+ * marker or a `sensitive`/`phi`/`pii`/`billing`/`credentialing` tag. */
31
+ const SENSITIVE_KEYWORD_RE = /\b(PHI|PII|protected health information|personally identifiable information|billing|claims?|reimbursement|remittance advice|credentialing|payer enrollment|HIPAA|42 CFR Part 2)\b/i;
32
+ /** True when the spec text (frontmatter + body) signals sensitive data: a
33
+ * high-signal regime keyword, an explicit `<!-- sensitive -->` marker, or a
34
+ * `sensitive`/`phi`/`pii`/`billing`/`credentialing` tag. Pure (operates on the raw
35
+ * spec text + the parsed `tags` array). Independent of `isRegulated` — a non-
36
+ * regulated FA billing or PF credentialing spec is `isSensitive` without being a
37
+ * regulated core, which is exactly the parity gap Finding A item 2 names. */
38
+ function detectSensitive(text, tags) {
39
+ if (/<!--\s*sensitive\s*(?::[^>]*)?-->/i.test(text))
40
+ return true;
41
+ if (tags.some((t) => /^(sensitive|phi|pii|billing|credentialing)$/i.test(String(t).trim())))
42
+ return true;
43
+ return SENSITIVE_KEYWORD_RE.test(text);
44
+ }
23
45
  /** True when a generated test source has ≥1 ACTIVE `test(` block (not `test.fixme`/
24
46
  * `test.describe`) and is not an AC-less placeholder. Pure (operates on source text). */
25
47
  export function hasActiveGeneratedTestSource(source) {
@@ -41,6 +63,7 @@ export function deriveSignalsFromText(core, text, flags = {}) {
41
63
  const hasUserStoriesSection = /^#{1,3}\s+User Stories\b/im.test(text);
42
64
  const affectedFiles = Array.isArray(fm.affected_files) ? fm.affected_files.map(String) : [];
43
65
  const uiAffectedFiles = affectedFiles.some((f) => /\/(components|pages|wizards)\//.test(f) || f.endsWith('.tsx'));
66
+ const tags = Array.isArray(fm.tags) ? fm.tags.map(String) : [];
44
67
  return {
45
68
  isRegulated: REGULATED_CORES.has(core.toLowerCase()),
46
69
  pipelineStatus: typeof fm.pipeline_status === 'string' ? fm.pipeline_status : undefined,
@@ -60,11 +83,22 @@ export function deriveSignalsFromText(core, text, flags = {}) {
60
83
  hasDocshots: docshotImageExists || /-docs-shots\.spec\.ts/.test(text) || /<!--\s*docshots:/i.test(text),
61
84
  hasHealSignoff: /<!--\s*heal-verified:/i.test(text),
62
85
  hasUiGateWaiver: /<!--\s*ui-gate-waived:/i.test(text),
86
+ // PHI/PII/billing/credentialing signal — drives the `hasComplianceForSensitive`
87
+ // gate for NON-regulated cores too (Finding A item 2). Content-derived, so it
88
+ // needs no fs flag; stays in this pure helper.
89
+ isSensitive: detectSensitive(text, tags),
90
+ // Re-validation after spec-review (Finding A item 1): the `/spec-pipeline` step-5
91
+ // re-run of validate-spec, recorded as a `<!-- revalidated-after-review: <date> -->`
92
+ // marker parallel to the other sign-off markers.
93
+ hasReValidationAfterReview: /<!--\s*revalidated-after-review:/i.test(text),
63
94
  isCreateWizardSpec,
64
95
  hasSubmitE2e: submitE2eProvesPersist || /<!--\s*submit-e2e-waived:/i.test(text),
65
96
  blockedBy: collectSpecIds(fm.blocked_by),
66
97
  hasVerificationSection: /^#{1,3}\s+Verification\b/im.test(text),
67
98
  acStatus: acStatusCounts(fm.acceptance_criteria),
99
+ // WEB-51: a recorded demo-proof artifact pointer. Content-derived (no fs flag),
100
+ // so it stays in this pure helper alongside the other frontmatter signals.
101
+ hasProofArtifact: typeof fm.proof === 'string' && fm.proof.trim() !== '',
68
102
  };
69
103
  }
70
104
  // ── pure path classification (the fs-free half of specs.ts's directory walk) ──
@@ -112,7 +146,16 @@ function specBasename(path) {
112
146
  * (epic #300, Wave-1 G3).
113
147
  */
114
148
  export function extractSpecId(filename, core) {
115
- const re = new RegExp(`^(${escapeForRegExp(core)}(?:-[A-Z]{1,4})?-\\d+(?:\\.\\d+)?(?:-(?:EN-\\d+|E\\d+|P\\d+(?:\\.\\d+)?(?:-EN-\\d+)?))?)`, 'i');
149
+ // The enhancement suffix carries a trailing `(?![A-Za-z0-9])` boundary so the
150
+ // `E\d+` / `P\d+` alternatives only fire on a COMPLETE id segment, never the leading
151
+ // fragment of an ordinary slug word that happens to begin with `e`/`p`. Without it,
152
+ // `WEB-05-e2e-walking-skeleton` parsed as `WEB-05-e2` (the `E\d+` branch ate `-e2` of
153
+ // `e2e`), so the file counted in `listSpecs` but `findSpec`'s id-equality filter never
154
+ // matched it — the spec silently escaped every per-spec gate (issue #14). In every valid
155
+ // id the enhancement is followed by `-slug` or end-of-name, so the boundary is a no-op
156
+ // for real suffixes (`CE-03-E1`, `HR-09-P5`, `PM-15-P2-EN-01`, `LO-01-EN-1`) and only
157
+ // rejects the prefix-of-a-longer-alnum-run over-match.
158
+ const re = new RegExp(`^(${escapeForRegExp(core)}(?:-[A-Z]{1,4})?-\\d+(?:\\.\\d+)?(?:-(?:EN-\\d+|E\\d+|P\\d+(?:\\.\\d+)?(?:-EN-\\d+)?)(?![A-Za-z0-9]))?)`, 'i');
116
159
  const match = re.exec(specBasename(filename));
117
160
  return match ? match[1] : null;
118
161
  }
@@ -1 +1 @@
1
- {"version":3,"file":"spec-pure.js","sourceRoot":"","sources":["../../src/lib/spec-pure.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spec-pure.js","sourceRoot":"","sources":["../../src/lib/spec-pure.ts"],"names":[],"mappings":"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"}
@@ -59,6 +59,18 @@ export type SpecSignals = {
59
59
  * `eos-spec signoff --type ui-gate-waived`. Documented escape for the C1
60
60
  * UI-evidence gate (e.g. a backend spec that `isUiBearing` false-positives on). */
61
61
  hasUiGateWaiver: boolean;
62
+ /** Phase 1 (Finding A item 2): the spec carries a PHI/PII/billing/credentialing
63
+ * signal (keyword, `<!-- sensitive -->` marker, or `sensitive`/`phi`/`pii`/
64
+ * `billing`/`credentialing` tag). Generalizes the regulated-core-only compliance
65
+ * gate to sensitive NON-regulated cores via `hasComplianceForSensitive`. Optional
66
+ * on the type for signal-shape stability across the captured parity fixtures (which
67
+ * predate it); always populated by deriveSignals. */
68
+ isSensitive?: boolean;
69
+ /** Phase 1 (Finding A item 1): a `<!-- revalidated-after-review: <date> -->` marker
70
+ * is present — the `/spec-pipeline` step-5 re-run of validate-spec after spec-review
71
+ * auto-applied edits. Gates `hasReValidationAfterReview` under `next --strict`.
72
+ * Optional for fixture-shape stability; always populated by deriveSignals. */
73
+ hasReValidationAfterReview?: boolean;
62
74
  /** Phase 3 (#1185): the spec is a kind:'create' wizard per the generated
63
75
  * wizard-create-specs bridge. Gates the submit→DB E2E completion check. */
64
76
  isCreateWizardSpec?: boolean;
@@ -78,6 +90,11 @@ export type SpecSignals = {
78
90
  * frontmatter — the typed AC model the `audit` command consumes (#174). Optional on
79
91
  * the type for signal-shape stability; always populated by deriveSignals. */
80
92
  acStatus?: AcStatusCounts;
93
+ /** A `proof:` frontmatter pointer to a recorded demo-proof artifact is present
94
+ * (WEB-51). The `audit` command warns (warn-first, non-gating) when a UI-bearing
95
+ * spec at a done status lacks it. Optional for signal-shape stability; always
96
+ * populated by deriveSignals. */
97
+ hasProofArtifact?: boolean;
81
98
  };
82
99
  export type SpecFile = {
83
100
  id: string;