@encore-os/eos-spec 0.4.0 → 0.5.1
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/dist/commands/audit.js +11 -3
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/complete.js +38 -13
- package/dist/commands/complete.js.map +1 -1
- package/dist/commands/conformance.js +27 -0
- package/dist/commands/conformance.js.map +1 -1
- package/dist/commands/next.d.ts +20 -4
- package/dist/commands/next.js +48 -13
- package/dist/commands/next.js.map +1 -1
- package/dist/commands/reconcile.d.ts +3 -10
- package/dist/commands/reconcile.js +6 -37
- package/dist/commands/reconcile.js.map +1 -1
- package/dist/commands/signoff.js +33 -5
- package/dist/commands/signoff.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +0 -2
- package/dist/lib/config.js +0 -4
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/embedding-store.d.ts +0 -2
- package/dist/lib/embedding-store.js +1 -1
- package/dist/lib/embedding-store.js.map +1 -1
- package/dist/lib/exec.d.ts +0 -2
- package/dist/lib/exec.js +1 -12
- package/dist/lib/exec.js.map +1 -1
- package/dist/lib/frontmatter.d.ts +5 -1
- package/dist/lib/frontmatter.js.map +1 -1
- package/dist/lib/next-action.d.ts +19 -2
- package/dist/lib/next-action.js +30 -6
- package/dist/lib/next-action.js.map +1 -1
- package/dist/lib/ollama-embed.d.ts +0 -9
- package/dist/lib/ollama-embed.js +0 -35
- package/dist/lib/ollama-embed.js.map +1 -1
- package/dist/lib/pipeline-config.js +45 -2
- package/dist/lib/pipeline-config.js.map +1 -1
- package/dist/lib/pipeline-map.d.ts +36 -0
- package/dist/lib/pipeline-map.js +89 -5
- package/dist/lib/pipeline-map.js.map +1 -1
- package/dist/lib/pipeline-schema.d.ts +33 -1
- package/dist/lib/pipeline-schema.js +3 -0
- package/dist/lib/pipeline-schema.js.map +1 -1
- package/dist/lib/predicate-registry.js +28 -1
- package/dist/lib/predicate-registry.js.map +1 -1
- package/dist/lib/reconcile-core.d.ts +26 -0
- package/dist/lib/reconcile-core.js +43 -0
- package/dist/lib/reconcile-core.js.map +1 -0
- package/dist/lib/spec-pure.js +44 -1
- package/dist/lib/spec-pure.js.map +1 -1
- package/dist/lib/specs.d.ts +17 -0
- package/dist/lib/specs.js.map +1 -1
- package/package.json +4 -4
|
@@ -49,6 +49,7 @@ export const ENCORE1_PIPELINE_SCHEMA = {
|
|
|
49
49
|
invocation: 'the encore-spec-research skill on ${id}',
|
|
50
50
|
reason: 'Regulated spec needs a research appendix before review.',
|
|
51
51
|
regulatedOnly: true,
|
|
52
|
+
hard: true,
|
|
52
53
|
completesStatus: 'regulatory_grounded',
|
|
53
54
|
},
|
|
54
55
|
{
|
|
@@ -60,14 +61,51 @@ export const ENCORE1_PIPELINE_SCHEMA = {
|
|
|
60
61
|
reason: 'Spec is grounded — run the implementability/landscape review.',
|
|
61
62
|
completesStatus: 'reviewed',
|
|
62
63
|
},
|
|
64
|
+
// ── Phase 1 strictOnly parity gates (Finding A). Each is BYTE-IDENTICAL to the
|
|
65
|
+
// matching LEGACY_PIPELINE stage in pipeline-map.ts (the parity gate proves
|
|
66
|
+
// the config-driven build ≡ LEGACY). NO `completesStatus` ⇒ never moves
|
|
67
|
+
// computeStage; `strictOnly` ⇒ only walked under `next --strict`.
|
|
68
|
+
{
|
|
69
|
+
id: 'research-before-review',
|
|
70
|
+
gate: 'hasResearchBeforeReview',
|
|
71
|
+
actor: 'encore-spec-research skill',
|
|
72
|
+
actorType: 'skill',
|
|
73
|
+
invocation: 'the encore-spec-research skill on ${id} (research must precede review on the non-regulated path)',
|
|
74
|
+
reason: 'Spec was reviewed without a research appendix — ground it before relying on the review.',
|
|
75
|
+
strictOnly: true,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'revalidate-after-review',
|
|
79
|
+
gate: 'hasReValidationAfterReview',
|
|
80
|
+
actor: 'validate-spec command',
|
|
81
|
+
actorType: 'command',
|
|
82
|
+
invocation: "re-run the /validate-spec command on ${id} after spec-review's auto-applied edits, then `eos-spec signoff --type revalidated-after-review --spec ${id}`",
|
|
83
|
+
reason: 'Spec-review auto-applies edits — re-validate to catch what they broke before advancing.',
|
|
84
|
+
strictOnly: true,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 'compliance-for-sensitive',
|
|
88
|
+
gate: 'hasComplianceForSensitive',
|
|
89
|
+
actor: 'compliance-reviewer agent',
|
|
90
|
+
actorType: 'agent',
|
|
91
|
+
invocation: 'the compliance-reviewer agent on ${id} (PHI/PII/billing/credentialing), then `eos-spec signoff --type compliance --spec ${id}`',
|
|
92
|
+
reason: 'Spec carries a PHI/PII/billing/credentialing signal but has no compliance sign-off.',
|
|
93
|
+
strictOnly: true,
|
|
94
|
+
},
|
|
63
95
|
{
|
|
64
96
|
id: 'compliance-review',
|
|
65
97
|
gate: 'hasComplianceSignoff',
|
|
66
98
|
actor: 'compliance-reviewer agent',
|
|
67
99
|
actorType: 'agent',
|
|
68
100
|
invocation: 'the compliance-reviewer agent on ${id}, then merge its review PR',
|
|
69
|
-
reason: 'Regulated spec needs compliance sign-off (human-gated PR).',
|
|
70
|
-
|
|
101
|
+
reason: 'Regulated or PHI-bearing spec needs compliance sign-off (human-gated PR).',
|
|
102
|
+
// #1372 PHI-widening: applies to regulated cores AND PHI/PII-bearing specs in
|
|
103
|
+
// any core (via the `complianceGating` predicate), not `regulatedOnly`.
|
|
104
|
+
appliesWhen: 'complianceGating',
|
|
105
|
+
// Hard gate: compliance sign-off is never implied by a later out-of-order
|
|
106
|
+
// artifact, so the navigator surfaces it even when plan/tasks already exist
|
|
107
|
+
// (keeps #1593 supersession from cancelling this widened #1372 gate).
|
|
108
|
+
hard: true,
|
|
71
109
|
completesStatus: 'compliance_reviewed',
|
|
72
110
|
},
|
|
73
111
|
{
|
|
@@ -124,6 +162,11 @@ export const ENCORE1_PIPELINE_SCHEMA = {
|
|
|
124
162
|
// which has opposite polarity). Cap applies when `unless` returns FALSE.
|
|
125
163
|
{ unless: 'hasAcceptanceCriteria', capBelow: 'tasks_generated' },
|
|
126
164
|
],
|
|
165
|
+
// #1593 supersession: once later artifacts have lifted the computed stage past a
|
|
166
|
+
// soft early gate, the navigator stops re-surfacing that gate (e.g. a missing
|
|
167
|
+
// `<!-- validated: -->` on an already-reviewed/planned/tasked spec). encore1
|
|
168
|
+
// opts in; the builder layout does not (its omission keeps builder unchanged).
|
|
169
|
+
supersedeSoftGates: true,
|
|
127
170
|
};
|
|
128
171
|
/** The builder (encoreos-switchboard) 7-stage / 6-status layout as config-driven
|
|
129
172
|
* data — a faithful transcription of the imperative PIPELINE/STATUS_ORDER in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-config.js","sourceRoot":"","sources":["../../src/lib/pipeline-config.ts"],"names":[],"mappings":"AAEA;;;;;;;uFAOuF;AACvF,MAAM,CAAC,MAAM,uBAAuB,GAAmB;IACrD,WAAW,EAAE;QACX,MAAM;QACN,WAAW;QACX,WAAW;QACX,qBAAqB;QACrB,UAAU;QACV,qBAAqB;QACrB,aAAa;QACb,SAAS;QACT,iBAAiB;KAClB;IACD,MAAM,EAAE;QACN;YACE,EAAE,EAAE,cAAc;YAClB,IAAI,EAAE,YAAY;YAClB,KAAK,EAAE,sBAAsB;YAC7B,SAAS,EAAE,SAAS;YACpB,UAAU,EAAE,2BAA2B;YACvC,MAAM,EAAE,+DAA+D;YACvE,eAAe,EAAE,WAAW;YAC5B,8EAA8E;YAC9E,QAAQ,EAAE,IAAI;SACf;QACD;YACE,EAAE,EAAE,eAAe;YACnB,IAAI,EAAE,sBAAsB;YAC5B,KAAK,EAAE,uBAAuB;YAC9B,SAAS,EAAE,SAAS;YACpB,8EAA8E;YAC9E,sDAAsD;YACtD,UAAU,EACR,oIAAoI;YACtI,MAAM,EAAE,6DAA6D;YACrE,eAAe,EAAE,WAAW;SAC7B;QACD;YACE,EAAE,EAAE,iBAAiB;YACrB,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,4BAA4B;YACnC,SAAS,EAAE,OAAO;YAClB,UAAU,EAAE,yCAAyC;YACrD,MAAM,EAAE,yDAAyD;YACjE,aAAa,EAAE,IAAI;YACnB,eAAe,EAAE,qBAAqB;SACvC;QACD;YACE,EAAE,EAAE,aAAa;YACjB,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,mBAAmB;YAC1B,SAAS,EAAE,OAAO;YAClB,UAAU,EAAE,gCAAgC;YAC5C,MAAM,EAAE,+DAA+D;YACvE,eAAe,EAAE,UAAU;SAC5B;QACD;YACE,EAAE,EAAE,mBAAmB;YACvB,IAAI,EAAE,sBAAsB;YAC5B,KAAK,EAAE,2BAA2B;YAClC,SAAS,EAAE,OAAO;YAClB,UAAU,EAAE,kEAAkE;YAC9E,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"pipeline-config.js","sourceRoot":"","sources":["../../src/lib/pipeline-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,8 +13,19 @@ export type Transition = {
|
|
|
13
13
|
reason: string;
|
|
14
14
|
/** Only applies to regulated cores (cl/pm/hr/rh/gr). */
|
|
15
15
|
regulatedOnly?: boolean;
|
|
16
|
+
/** Resolved applicability predicate (from a schema stage's `appliesWhen`). When
|
|
17
|
+
* present it supersedes `regulatedOnly`: the stage applies to a spec iff this
|
|
18
|
+
* returns true. Lets the compliance gate widen to PHI-bearing specs (#1372). */
|
|
19
|
+
appliesTo?: (spec: SpecFile) => boolean;
|
|
16
20
|
/** Advisory — surfaced as a hint but never blocks progression. */
|
|
17
21
|
optional?: boolean;
|
|
22
|
+
/** Hard gate (regulated research, compliance sign-off): never superseded by an
|
|
23
|
+
* out-of-order downstream artifact, so the navigator always surfaces it when
|
|
24
|
+
* not-done. See {@link StageDef.hard}. */
|
|
25
|
+
hard?: boolean;
|
|
26
|
+
/** Phase 1 parity gate: walked by the navigator ONLY under `next --strict`; no
|
|
27
|
+
* `completesStatus`, so it never moves computeStage. */
|
|
28
|
+
strictOnly?: boolean;
|
|
18
29
|
/** The pipeline_status enum value this transition completes (for schema-coverage + reconciliation). */
|
|
19
30
|
completesStatus?: string;
|
|
20
31
|
/** True when this transition's output already exists for the spec. */
|
|
@@ -22,6 +33,13 @@ export type Transition = {
|
|
|
22
33
|
};
|
|
23
34
|
/** Numeric rank of a pipeline_status value; unknown/undefined ranks below everything. */
|
|
24
35
|
export declare function rank(status?: string): number;
|
|
36
|
+
/** Whether a pipeline transition applies to a given spec. The general
|
|
37
|
+
* applicability test shared by `computeStage` and the navigator: a resolved
|
|
38
|
+
* `appliesTo` predicate (from a schema `appliesWhen`) wins; otherwise
|
|
39
|
+
* `regulatedOnly` falls back to the regulated-core check; otherwise the stage
|
|
40
|
+
* applies to everyone. Centralizing it keeps the widened compliance gate (#1372)
|
|
41
|
+
* consistent across both the stage walk and the cumulative stage derivation. */
|
|
42
|
+
export declare function stageApplies(t: Pick<Transition, 'appliesTo' | 'regulatedOnly'>, spec: SpecFile): boolean;
|
|
25
43
|
/** Legacy hand-written pipeline, preserved verbatim for parity + rollback. The
|
|
26
44
|
* active {@link PIPELINE} export is the config-driven {@link buildPipeline} output
|
|
27
45
|
* (selectable back to this via `EOS_PIPELINE=legacy`). */
|
|
@@ -59,6 +77,7 @@ export declare function buildPipeline(schema: PipelineSchema, registry: Predicat
|
|
|
59
77
|
PIPELINE: Transition[];
|
|
60
78
|
rank: (status?: string) => number;
|
|
61
79
|
computeStage: (spec: SpecFile) => string;
|
|
80
|
+
supersedeSoftGates: boolean;
|
|
62
81
|
};
|
|
63
82
|
/** Canonical, ordered spec/test pipeline. First not-done applicable transition is
|
|
64
83
|
* the next step. Config-driven by default; `EOS_PIPELINE=legacy` selects {@link LEGACY_PIPELINE}. */
|
|
@@ -66,3 +85,20 @@ export declare const PIPELINE: Transition[];
|
|
|
66
85
|
/** Derive a spec's furthest-reached pipeline stage from artifacts only.
|
|
67
86
|
* Config-driven by default; `EOS_PIPELINE=legacy` selects {@link legacyComputeStage}. */
|
|
68
87
|
export declare const computeStage: (spec: SpecFile) => string;
|
|
88
|
+
/** Whether the active layout supersedes soft early gates once a later artifact has
|
|
89
|
+
* lifted the computed stage past them (#1593). True for the config-driven encore1
|
|
90
|
+
* build; the legacy hand-written engine never superseded, so `EOS_PIPELINE=legacy`
|
|
91
|
+
* is false. The navigator consults this; `computeStage` is unaffected either way. */
|
|
92
|
+
export declare const SUPERSEDE_SOFT_GATES: boolean;
|
|
93
|
+
/** True when a not-done transition `t` is SUPERSEDED for `spec` under the active
|
|
94
|
+
* layout: it carries a `completesStatus` that ranks strictly below the spec's
|
|
95
|
+
* computed stage, so a later stage's artifact already exists and the navigator
|
|
96
|
+
* should not route back to this (soft) gate. Stages with no `completesStatus`
|
|
97
|
+
* (the strictOnly parity gates, draft-acs, generate-tests) are never superseded.
|
|
98
|
+
* HARD gates (regulated research, compliance sign-off) are never superseded either —
|
|
99
|
+
* their completion cannot be implied by an out-of-order downstream artifact (#1372). */
|
|
100
|
+
export declare function isSupersededGate(t: Transition, spec: SpecFile): boolean;
|
|
101
|
+
/** Whether a spec is gated on compliance review under the active (encore1) layout —
|
|
102
|
+
* regulated cores OR PHI/PII-bearing specs (#1372). The navigator's review-stage
|
|
103
|
+
* heuristic keys on this so the widened gate stays in one place. */
|
|
104
|
+
export declare function isComplianceGated(spec: SpecFile): boolean;
|
package/dist/lib/pipeline-map.js
CHANGED
|
@@ -19,6 +19,19 @@ export function rank(status) {
|
|
|
19
19
|
const i = STATUS_ORDER.indexOf(status);
|
|
20
20
|
return i === -1 ? -1 : i;
|
|
21
21
|
}
|
|
22
|
+
/** Whether a pipeline transition applies to a given spec. The general
|
|
23
|
+
* applicability test shared by `computeStage` and the navigator: a resolved
|
|
24
|
+
* `appliesTo` predicate (from a schema `appliesWhen`) wins; otherwise
|
|
25
|
+
* `regulatedOnly` falls back to the regulated-core check; otherwise the stage
|
|
26
|
+
* applies to everyone. Centralizing it keeps the widened compliance gate (#1372)
|
|
27
|
+
* consistent across both the stage walk and the cumulative stage derivation. */
|
|
28
|
+
export function stageApplies(t, spec) {
|
|
29
|
+
if (t.appliesTo)
|
|
30
|
+
return t.appliesTo(spec);
|
|
31
|
+
if (t.regulatedOnly)
|
|
32
|
+
return spec.signals.isRegulated;
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
22
35
|
// TODO(post-cutover): once the schema pipeline bakes, delete LEGACY_PIPELINE,
|
|
23
36
|
// legacyComputeStage, and the EOS_PIPELINE ternary selector below.
|
|
24
37
|
/** Legacy hand-written pipeline, preserved verbatim for parity + rollback. The
|
|
@@ -69,13 +82,49 @@ export const LEGACY_PIPELINE = [
|
|
|
69
82
|
completesStatus: 'reviewed',
|
|
70
83
|
isDone: (s) => s.signals.hasSpecReview,
|
|
71
84
|
},
|
|
85
|
+
// ── Phase 1 strictOnly parity gates (Finding A). Kept BYTE-IDENTICAL to the
|
|
86
|
+
// matching ENCORE1_PIPELINE_SCHEMA stages so the config-driven build ≡ LEGACY
|
|
87
|
+
// (pipeline-parity.test.ts test 4). No `completesStatus` ⇒ computeStage is
|
|
88
|
+
// unchanged on every fixture (tests 2/3). `strictOnly` ⇒ ignored by default
|
|
89
|
+
// `next`; surfaced as BLOCKING only under `next --strict`.
|
|
90
|
+
{
|
|
91
|
+
id: 'research-before-review',
|
|
92
|
+
actor: 'encore-spec-research skill',
|
|
93
|
+
actorType: 'skill',
|
|
94
|
+
invocation: (id) => `the encore-spec-research skill on ${id} (research must precede review on the non-regulated path)`,
|
|
95
|
+
reason: 'Spec was reviewed without a research appendix — ground it before relying on the review.',
|
|
96
|
+
strictOnly: true,
|
|
97
|
+
isDone: (s) => !s.signals.hasSpecReview || s.signals.hasResearch,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'revalidate-after-review',
|
|
101
|
+
actor: 'validate-spec command',
|
|
102
|
+
actorType: 'command',
|
|
103
|
+
invocation: (id) => `re-run the /validate-spec command on ${id} after spec-review's auto-applied edits, then \`eos-spec signoff --type revalidated-after-review --spec ${id}\``,
|
|
104
|
+
reason: 'Spec-review auto-applies edits — re-validate to catch what they broke before advancing.',
|
|
105
|
+
strictOnly: true,
|
|
106
|
+
isDone: (s) => !s.signals.hasSpecReview || Boolean(s.signals.hasReValidationAfterReview),
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'compliance-for-sensitive',
|
|
110
|
+
actor: 'compliance-reviewer agent',
|
|
111
|
+
actorType: 'agent',
|
|
112
|
+
invocation: (id) => `the compliance-reviewer agent on ${id} (PHI/PII/billing/credentialing), then \`eos-spec signoff --type compliance --spec ${id}\``,
|
|
113
|
+
reason: 'Spec carries a PHI/PII/billing/credentialing signal but has no compliance sign-off.',
|
|
114
|
+
strictOnly: true,
|
|
115
|
+
isDone: (s) => !s.signals.isSensitive || s.signals.hasComplianceSignoff,
|
|
116
|
+
},
|
|
72
117
|
{
|
|
73
118
|
id: 'compliance-review',
|
|
74
119
|
actor: 'compliance-reviewer agent',
|
|
75
120
|
actorType: 'agent',
|
|
76
121
|
invocation: (id) => `the compliance-reviewer agent on ${id}, then merge its review PR`,
|
|
77
|
-
reason: 'Regulated spec needs compliance sign-off (human-gated PR).',
|
|
78
|
-
|
|
122
|
+
reason: 'Regulated or PHI-bearing spec needs compliance sign-off (human-gated PR).',
|
|
123
|
+
// #1372 PHI-widening (kept in lockstep with ENCORE1_PIPELINE_SCHEMA's
|
|
124
|
+
// `appliesWhen: 'complianceGating'`): applies to regulated cores AND
|
|
125
|
+
// PHI/PII-bearing specs in any core. On the captured baseline `isSensitive` is
|
|
126
|
+
// uniformly false, so this reduces to `isRegulated` and parity is preserved.
|
|
127
|
+
appliesTo: (s) => s.signals.isRegulated || Boolean(s.signals.isSensitive),
|
|
79
128
|
completesStatus: 'compliance_reviewed',
|
|
80
129
|
isDone: (s) => s.signals.hasComplianceSignoff,
|
|
81
130
|
},
|
|
@@ -175,7 +224,7 @@ export function legacyComputeStage(spec) {
|
|
|
175
224
|
const capRank = caps.length ? Math.min(...caps) : Number.POSITIVE_INFINITY;
|
|
176
225
|
let best;
|
|
177
226
|
for (const t of LEGACY_PIPELINE) {
|
|
178
|
-
if (t
|
|
227
|
+
if (!stageApplies(t, spec))
|
|
179
228
|
continue;
|
|
180
229
|
if (!t.isDone(spec) || !t.completesStatus)
|
|
181
230
|
continue;
|
|
@@ -214,7 +263,12 @@ export function buildPipeline(schema, registry) {
|
|
|
214
263
|
invocation: (id) => st.invocation.replaceAll('${id}', id),
|
|
215
264
|
reason: st.reason,
|
|
216
265
|
regulatedOnly: st.regulatedOnly,
|
|
266
|
+
// Resolve the named applicability predicate (if any) into a closure. Wins over
|
|
267
|
+
// `regulatedOnly` in `stageApplies` — the seam the #1372 compliance widening rides.
|
|
268
|
+
appliesTo: st.appliesWhen ? registry[st.appliesWhen] : undefined,
|
|
217
269
|
optional: st.optional,
|
|
270
|
+
hard: st.hard,
|
|
271
|
+
strictOnly: st.strictOnly,
|
|
218
272
|
completesStatus: st.completesStatus,
|
|
219
273
|
isDone: registry[st.gate],
|
|
220
274
|
}));
|
|
@@ -229,7 +283,7 @@ export function buildPipeline(schema, registry) {
|
|
|
229
283
|
const capRank = caps.length ? Math.min(...caps) : Number.POSITIVE_INFINITY;
|
|
230
284
|
let best;
|
|
231
285
|
for (const t of pipeline) {
|
|
232
|
-
if (t
|
|
286
|
+
if (!stageApplies(t, spec))
|
|
233
287
|
continue;
|
|
234
288
|
if (!t.isDone(spec) || !t.completesStatus)
|
|
235
289
|
continue;
|
|
@@ -240,7 +294,13 @@ export function buildPipeline(schema, registry) {
|
|
|
240
294
|
}
|
|
241
295
|
return best ?? 'stub';
|
|
242
296
|
};
|
|
243
|
-
return {
|
|
297
|
+
return {
|
|
298
|
+
STATUS_ORDER: order,
|
|
299
|
+
PIPELINE: pipeline,
|
|
300
|
+
rank: rankFn,
|
|
301
|
+
computeStage: computeStageFn,
|
|
302
|
+
supersedeSoftGates: Boolean(schema.supersedeSoftGates),
|
|
303
|
+
};
|
|
244
304
|
}
|
|
245
305
|
// Active selection — config-driven by default; `EOS_PIPELINE=legacy` rolls back
|
|
246
306
|
// to the hand-written engine. STATUS_ORDER/rank are identical in both
|
|
@@ -253,4 +313,28 @@ export const PIPELINE = process.env.EOS_PIPELINE === 'legacy' ? LEGACY_PIPELINE
|
|
|
253
313
|
/** Derive a spec's furthest-reached pipeline stage from artifacts only.
|
|
254
314
|
* Config-driven by default; `EOS_PIPELINE=legacy` selects {@link legacyComputeStage}. */
|
|
255
315
|
export const computeStage = process.env.EOS_PIPELINE === 'legacy' ? legacyComputeStage : _built.computeStage;
|
|
316
|
+
/** Whether the active layout supersedes soft early gates once a later artifact has
|
|
317
|
+
* lifted the computed stage past them (#1593). True for the config-driven encore1
|
|
318
|
+
* build; the legacy hand-written engine never superseded, so `EOS_PIPELINE=legacy`
|
|
319
|
+
* is false. The navigator consults this; `computeStage` is unaffected either way. */
|
|
320
|
+
export const SUPERSEDE_SOFT_GATES = process.env.EOS_PIPELINE === 'legacy' ? false : _built.supersedeSoftGates;
|
|
321
|
+
/** True when a not-done transition `t` is SUPERSEDED for `spec` under the active
|
|
322
|
+
* layout: it carries a `completesStatus` that ranks strictly below the spec's
|
|
323
|
+
* computed stage, so a later stage's artifact already exists and the navigator
|
|
324
|
+
* should not route back to this (soft) gate. Stages with no `completesStatus`
|
|
325
|
+
* (the strictOnly parity gates, draft-acs, generate-tests) are never superseded.
|
|
326
|
+
* HARD gates (regulated research, compliance sign-off) are never superseded either —
|
|
327
|
+
* their completion cannot be implied by an out-of-order downstream artifact (#1372). */
|
|
328
|
+
export function isSupersededGate(t, spec) {
|
|
329
|
+
if (!SUPERSEDE_SOFT_GATES || t.hard || !t.completesStatus)
|
|
330
|
+
return false;
|
|
331
|
+
const tRank = rank(t.completesStatus);
|
|
332
|
+
return tRank >= 0 && tRank < rank(computeStage(spec));
|
|
333
|
+
}
|
|
334
|
+
/** Whether a spec is gated on compliance review under the active (encore1) layout —
|
|
335
|
+
* regulated cores OR PHI/PII-bearing specs (#1372). The navigator's review-stage
|
|
336
|
+
* heuristic keys on this so the widened gate stays in one place. */
|
|
337
|
+
export function isComplianceGated(spec) {
|
|
338
|
+
return DEFAULT_PREDICATES.complianceGating(spec);
|
|
339
|
+
}
|
|
256
340
|
//# sourceMappingURL=pipeline-map.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-map.js","sourceRoot":"","sources":["../../src/lib/pipeline-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline-map.js","sourceRoot":"","sources":["../../src/lib/pipeline-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,10 +19,32 @@ 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
|
+
/** Hard gate (regulated research, compliance sign-off): an evidence gate whose
|
|
36
|
+
* completion can NEVER be implied by a later out-of-order artifact. Excluded from
|
|
37
|
+
* `supersedeSoftGates`, so the navigator ALWAYS surfaces a not-done hard gate even
|
|
38
|
+
* when downstream artifacts (plan/tasks) exist — skipping one is a real compliance
|
|
39
|
+
* problem, not marker noise. This keeps the #1372 compliance widening from being
|
|
40
|
+
* cancelled by the #1593 soft-gate supersession. Soft structural stages
|
|
41
|
+
* (validate-spec/spec-review) omit it and remain superseded once leapfrogged. */
|
|
42
|
+
hard?: boolean;
|
|
43
|
+
/** Phase 1 parity gate: this stage participates in the navigator walk ONLY under
|
|
44
|
+
* `next --strict`. It carries no `completesStatus` (never moves computeStage), so
|
|
45
|
+
* default `next`/`computeStage`/`reconcile` are unaffected; under `--strict` it
|
|
46
|
+
* surfaces as a BLOCKING action when its gate is unmet. */
|
|
47
|
+
strictOnly?: boolean;
|
|
26
48
|
/** The pipeline_status enum value this transition completes (for schema-coverage + reconciliation). */
|
|
27
49
|
completesStatus?: string;
|
|
28
50
|
};
|
|
@@ -41,6 +63,16 @@ export type PipelineSchema = {
|
|
|
41
63
|
statusOrder: string[];
|
|
42
64
|
stages: StageDef[];
|
|
43
65
|
caps: CapDef[];
|
|
66
|
+
/** When true, the NAVIGATOR treats a not-done stage as satisfied if its
|
|
67
|
+
* `completesStatus` ranks strictly BELOW the spec's computed stage — i.e. a
|
|
68
|
+
* later stage's artifact already exists, so a missing earlier (soft) marker is
|
|
69
|
+
* superseded rather than re-surfaced. Models encoreos's #1593 behavior: a spec
|
|
70
|
+
* reviewed + compliance-signed + planned + tasked but missing the early
|
|
71
|
+
* `<!-- validated: -->` marker routes to the implement/complete tail, not back
|
|
72
|
+
* to validate-spec. `computeStage` is unaffected (it already reports the
|
|
73
|
+
* furthest-reached stage); only `recommendAction`'s walk honors this. Opt-in
|
|
74
|
+
* per layout — the builder layout omits it (default false) and is unchanged. */
|
|
75
|
+
supersedeSoftGates?: boolean;
|
|
44
76
|
};
|
|
45
77
|
/** Validate a {@link PipelineSchema} against its {@link PredicateRegistry}: every
|
|
46
78
|
* 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":"
|
|
1
|
+
{"version":3,"file":"pipeline-schema.js","sourceRoot":"","sources":["../../src/lib/pipeline-schema.ts"],"names":[],"mappings":"AAmFA;;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 (
|
|
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,
|
|
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"}
|
package/dist/lib/spec-pure.js
CHANGED
|
@@ -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
|
-
|
|
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
|
}
|