@ai-sdlc/orchestrator 0.9.0 → 0.13.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 (172) hide show
  1. package/dist/__test-helpers/git-env.d.ts +40 -0
  2. package/dist/__test-helpers/git-env.js +73 -0
  3. package/dist/adapters.d.ts +42 -3
  4. package/dist/adapters.js +133 -3
  5. package/dist/admission-composite.d.ts +134 -1
  6. package/dist/admission-composite.js +170 -6
  7. package/dist/admission-enrichment.d.ts +12 -3
  8. package/dist/admission-enrichment.js +71 -10
  9. package/dist/admission-hc.d.ts +20 -1
  10. package/dist/admission-hc.js +12 -1
  11. package/dist/admission-score.d.ts +44 -0
  12. package/dist/admission-score.js +11 -2
  13. package/dist/backlog-adapter.d.ts +45 -0
  14. package/dist/backlog-adapter.js +145 -1
  15. package/dist/calibration.d.ts +81 -0
  16. package/dist/calibration.js +76 -0
  17. package/dist/cli/commands/git-remote.d.ts +25 -0
  18. package/dist/cli/commands/git-remote.js +80 -1
  19. package/dist/cli/commands/init-features.d.ts +507 -0
  20. package/dist/cli/commands/init-features.js +1100 -0
  21. package/dist/cli/commands/init-templates.d.ts +301 -0
  22. package/dist/cli/commands/init-templates.js +1341 -0
  23. package/dist/cli/commands/init.d.ts +67 -0
  24. package/dist/cli/commands/init.js +301 -2
  25. package/dist/cli/commands/run.js +9 -1
  26. package/dist/cli/index.d.ts +11 -0
  27. package/dist/cli/index.js +42 -8
  28. package/dist/compliance/composer.d.ts +79 -0
  29. package/dist/compliance/composer.js +258 -0
  30. package/dist/compliance/errors.d.ts +64 -0
  31. package/dist/compliance/errors.js +85 -0
  32. package/dist/compliance/loader.d.ts +52 -0
  33. package/dist/compliance/loader.js +124 -0
  34. package/dist/compliance/types.d.ts +184 -0
  35. package/dist/compliance/types.js +41 -0
  36. package/dist/compliance-clearance.d.ts +269 -0
  37. package/dist/compliance-clearance.js +269 -0
  38. package/dist/config.js +17 -0
  39. package/dist/cost-tracker.d.ts +22 -0
  40. package/dist/cost-tracker.js +41 -0
  41. package/dist/database/adapters/external.js +5 -1
  42. package/dist/design-authority.d.ts +13 -0
  43. package/dist/design-authority.js +13 -0
  44. package/dist/embedding/adapters/openai-text-embedding-3-small.d.ts +71 -0
  45. package/dist/embedding/adapters/openai-text-embedding-3-small.js +190 -0
  46. package/dist/embedding/consumers/tessellation-drift.d.ts +74 -0
  47. package/dist/embedding/consumers/tessellation-drift.js +76 -0
  48. package/dist/embedding/cross-provider.d.ts +78 -0
  49. package/dist/embedding/cross-provider.js +75 -0
  50. package/dist/embedding/deprecation.d.ts +151 -0
  51. package/dist/embedding/deprecation.js +229 -0
  52. package/dist/embedding/errors.d.ts +90 -0
  53. package/dist/embedding/errors.js +150 -0
  54. package/dist/embedding/index.d.ts +29 -0
  55. package/dist/embedding/index.js +24 -0
  56. package/dist/embedding/pipeline-load.d.ts +146 -0
  57. package/dist/embedding/pipeline-load.js +178 -0
  58. package/dist/embedding/registry.d.ts +45 -0
  59. package/dist/embedding/registry.js +61 -0
  60. package/dist/embedding/stale-vector.d.ts +110 -0
  61. package/dist/embedding/stale-vector.js +92 -0
  62. package/dist/embedding/storage/index.d.ts +51 -0
  63. package/dist/embedding/storage/index.js +43 -0
  64. package/dist/embedding/storage/jsonl-backend.d.ts +150 -0
  65. package/dist/embedding/storage/jsonl-backend.js +332 -0
  66. package/dist/embedding/storage/types.d.ts +135 -0
  67. package/dist/embedding/storage/types.js +13 -0
  68. package/dist/embedding/types.d.ts +180 -0
  69. package/dist/embedding/types.js +10 -0
  70. package/dist/execute.d.ts +29 -2
  71. package/dist/execute.js +179 -35
  72. package/dist/index.d.ts +14 -2
  73. package/dist/index.js +19 -2
  74. package/dist/journey/inheritance-validator.d.ts +396 -0
  75. package/dist/journey/inheritance-validator.js +370 -0
  76. package/dist/journey/state-id-drift-rule.d.ts +137 -0
  77. package/dist/journey/state-id-drift-rule.js +245 -0
  78. package/dist/journey-sa2-router.d.ts +395 -0
  79. package/dist/journey-sa2-router.js +308 -0
  80. package/dist/models/classifier.d.ts +3 -1
  81. package/dist/models/classifier.js +61 -5
  82. package/dist/pillar-breakdown.d.ts +23 -1
  83. package/dist/pillar-breakdown.js +9 -0
  84. package/dist/runners/review-agent.js +6 -2
  85. package/dist/runners/runner-registry.d.ts +36 -0
  86. package/dist/runners/runner-registry.js +90 -0
  87. package/dist/runtime/attestations.d.ts +663 -11
  88. package/dist/runtime/attestations.js +971 -24
  89. package/dist/runtime/index.d.ts +1 -1
  90. package/dist/runtime/index.js +1 -1
  91. package/dist/runtime/parallelism-flag.d.ts +21 -3
  92. package/dist/runtime/parallelism-flag.js +27 -6
  93. package/dist/runtime/port-allocator.d.ts +11 -0
  94. package/dist/runtime/port-allocator.js +30 -0
  95. package/dist/sa-scoring/layer3-llm.js +6 -1
  96. package/dist/sa-scoring/revision-proposal-config.d.ts +178 -0
  97. package/dist/sa-scoring/revision-proposal-config.js +198 -0
  98. package/dist/sa-scoring/revision-proposal.d.ts +285 -0
  99. package/dist/sa-scoring/revision-proposal.js +417 -0
  100. package/dist/signal-ingestion/adapters/community-thread.d.ts +43 -0
  101. package/dist/signal-ingestion/adapters/community-thread.js +55 -0
  102. package/dist/signal-ingestion/adapters/in-app-feedback.d.ts +67 -0
  103. package/dist/signal-ingestion/adapters/in-app-feedback.js +51 -0
  104. package/dist/signal-ingestion/adapters/manual.d.ts +78 -0
  105. package/dist/signal-ingestion/adapters/manual.js +112 -0
  106. package/dist/signal-ingestion/adapters/support-ticket.d.ts +47 -0
  107. package/dist/signal-ingestion/adapters/support-ticket.js +51 -0
  108. package/dist/signal-ingestion/classifier.d.ts +205 -0
  109. package/dist/signal-ingestion/classifier.js +494 -0
  110. package/dist/signal-ingestion/clustering-types.d.ts +36 -0
  111. package/dist/signal-ingestion/clustering-types.js +14 -0
  112. package/dist/signal-ingestion/clustering.d.ts +200 -0
  113. package/dist/signal-ingestion/clustering.js +413 -0
  114. package/dist/signal-ingestion/config.d.ts +351 -0
  115. package/dist/signal-ingestion/config.js +587 -0
  116. package/dist/signal-ingestion/d1.d.ts +252 -0
  117. package/dist/signal-ingestion/d1.js +235 -0
  118. package/dist/signal-ingestion/errors.d.ts +73 -0
  119. package/dist/signal-ingestion/errors.js +108 -0
  120. package/dist/signal-ingestion/governance-events.d.ts +181 -0
  121. package/dist/signal-ingestion/governance-events.js +189 -0
  122. package/dist/signal-ingestion/index.d.ts +35 -0
  123. package/dist/signal-ingestion/index.js +53 -0
  124. package/dist/signal-ingestion/manual-share-metric.d.ts +93 -0
  125. package/dist/signal-ingestion/manual-share-metric.js +106 -0
  126. package/dist/signal-ingestion/registry.d.ts +40 -0
  127. package/dist/signal-ingestion/registry.js +137 -0
  128. package/dist/signal-ingestion/residency.d.ts +227 -0
  129. package/dist/signal-ingestion/residency.js +238 -0
  130. package/dist/signal-ingestion/significance.d.ts +554 -0
  131. package/dist/signal-ingestion/significance.js +555 -0
  132. package/dist/signal-ingestion/types.d.ts +191 -0
  133. package/dist/signal-ingestion/types.js +8 -0
  134. package/dist/substrate/drift-composition.d.ts +270 -0
  135. package/dist/substrate/drift-composition.js +306 -0
  136. package/dist/substrate/drift-tui-surface.d.ts +61 -0
  137. package/dist/substrate/drift-tui-surface.js +102 -0
  138. package/dist/substrate/identity-class.d.ts +176 -0
  139. package/dist/substrate/identity-class.js +201 -0
  140. package/dist/tessellation/cross-soul-provenance-rule.d.ts +133 -0
  141. package/dist/tessellation/cross-soul-provenance-rule.js +171 -0
  142. package/dist/tessellation/inter-soul-embedding-distance-rule.d.ts +61 -0
  143. package/dist/tessellation/inter-soul-embedding-distance-rule.js +67 -0
  144. package/dist/tessellation/rule-registry.d.ts +269 -0
  145. package/dist/tessellation/rule-registry.js +92 -0
  146. package/dist/tessellation/soul-slug-ast-scan-rule.d.ts +90 -0
  147. package/dist/tessellation/soul-slug-ast-scan-rule.js +158 -0
  148. package/dist/tessellation-admission.d.ts +162 -0
  149. package/dist/tessellation-admission.js +146 -0
  150. package/dist/tessellation-drift.d.ts +246 -0
  151. package/dist/tessellation-drift.js +250 -0
  152. package/dist/validate-config.js +13 -0
  153. package/dist/validate-issue.js +2 -2
  154. package/dist/variant/cardinality-activation.d.ts +126 -0
  155. package/dist/variant/cardinality-activation.js +101 -0
  156. package/dist/variant/deprecation-lifecycle.d.ts +184 -0
  157. package/dist/variant/deprecation-lifecycle.js +208 -0
  158. package/dist/variant/drift-extension.d.ts +136 -0
  159. package/dist/variant/drift-extension.js +164 -0
  160. package/dist/variant/engineering-review.d.ts +185 -0
  161. package/dist/variant/engineering-review.js +142 -0
  162. package/dist/variant/index.d.ts +32 -0
  163. package/dist/variant/index.js +32 -0
  164. package/dist/variant/inheritance-validator.d.ts +165 -0
  165. package/dist/variant/inheritance-validator.js +139 -0
  166. package/dist/variant/internal-adopter/index.d.ts +11 -0
  167. package/dist/variant/internal-adopter/index.js +10 -0
  168. package/dist/variant/internal-adopter/products.d.ts +156 -0
  169. package/dist/variant/internal-adopter/products.js +366 -0
  170. package/dist/variant-admission.d.ts +316 -0
  171. package/dist/variant-admission.js +247 -0
  172. package/package.json +11 -8
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Signal ingestion source-adapter substrate for RFC-0030 Phase 1.
3
+ *
4
+ * Source adapters fetch raw demand signals from external systems while keeping
5
+ * classification, clustering, and scoring out of this layer.
6
+ */
7
+ export type SignalSourceName = 'signal-source-support-ticket' | 'signal-source-community-thread' | 'signal-source-in-app-feedback' | 'signal-source-manual' | (string & {});
8
+ export type SignalTier = 1 | 2;
9
+ export type CustomerTier = 'enterprise' | 'mid' | 'smb' | 'free' | 'churned';
10
+ export interface RawSignal {
11
+ /** Stable identifier in the source system, e.g. zendesk-ticket-12345. */
12
+ sourceId: string;
13
+ /** Original source timestamp. */
14
+ sourceTimestamp: Date;
15
+ /** Optional customer/account identifier supplied by the source. */
16
+ customerId?: string;
17
+ /** Optional structured tier supplied by the source. */
18
+ customerTier?: CustomerTier;
19
+ /** Free-text signal body. */
20
+ payload: string;
21
+ /** Source-specific structured metadata. */
22
+ metadata?: Record<string, unknown>;
23
+ /** Required for manual signals per RFC-0030 OQ-13.4. */
24
+ attestedBy?: string;
25
+ /** Auto-filled for manual signals when omitted. */
26
+ attestedAt?: Date;
27
+ /**
28
+ * Optional ISO-3166 country code or compliance region tag for the signal's
29
+ * origin (e.g. 'eu', 'us-east', 'gb', 'apac', 'us'). Consumed by the
30
+ * Phase 4 residency-violation gate per RFC-0030 OQ-13.3: when the adopter
31
+ * has a declared regime constraint (via RFC-0022 compliance posture) that
32
+ * requires data residency in a specific region, signals from outside the
33
+ * allowed region(s) are refused and emitted as
34
+ * `Decision: signal-residency-violation`. When undefined, the residency
35
+ * gate skips this signal (no false positives on adapters that don't surface
36
+ * region metadata).
37
+ */
38
+ region?: string;
39
+ /**
40
+ * Optional evidence link for manual signals per RFC-0030 OQ-13.4 v0.3
41
+ * re-walkthrough. When present (call recording URL, ticket URL, transcript
42
+ * link), the audit trail is materially stronger. When absent, the attested
43
+ * observation stands but is flagged in the manual-share quality metric.
44
+ *
45
+ * The pipeline preserves this field through classification + clustering +
46
+ * D1 aggregation so it remains visible in the audit export.
47
+ */
48
+ evidenceUrl?: string;
49
+ }
50
+ export interface SignalSourceAdapter {
51
+ readonly name: SignalSourceName;
52
+ readonly defaultTier: SignalTier;
53
+ /**
54
+ * RFC-0030 OQ-13.1 v0.3 re-walkthrough: when `true`, this adapter requires
55
+ * OAuth credential management (refresh tokens, scopes) which is deferred to
56
+ * a future credential-management RFC. The Phase 1 registry refuses to fetch
57
+ * from such adapters and emits `Decision: adapter-requires-credential-mgmt-rfc`.
58
+ *
59
+ * Defaults to `false` (undefined → false) — all v1-shipped adapters MUST be
60
+ * env-var-based.
61
+ */
62
+ readonly requiresOAuth?: boolean;
63
+ /**
64
+ * Adapter self-validation. Credential lifecycle is intentionally deferred to
65
+ * a future RFC; Phase 1 only reports whether this adapter can be used.
66
+ */
67
+ isAvailable(): Promise<boolean>;
68
+ /** Fetch immutable signals from the source since the provided timestamp. */
69
+ fetchSignals(since: Date): Promise<RawSignal[]>;
70
+ }
71
+ export interface AdapterCredentialInvalidDecision {
72
+ type: 'Decision';
73
+ decision: 'adapter-credential-invalid';
74
+ adapter: SignalSourceName;
75
+ message: string;
76
+ }
77
+ /**
78
+ * RFC-0030 OQ-13.1 v0.3 re-walkthrough: emitted when an adapter's required
79
+ * credential env var is missing or empty. Downstream auto-action: emit a
80
+ * SETUP task asking the operator to set the env var. Pipeline continues with
81
+ * remaining valid adapters.
82
+ *
83
+ * Distinct from `AdapterCredentialRejectedDecision` (env var present but
84
+ * upstream auth call failed). Two distinct operator actions: SETUP vs.
85
+ * ROTATION. v0.2's collapsed `adapter-credential-invalid` is preserved for
86
+ * backward compat — adapters that don't yet probe env vars surface the
87
+ * legacy Decision.
88
+ */
89
+ export interface AdapterCredentialNotConfiguredDecision {
90
+ type: 'Decision';
91
+ decision: 'adapter-credential-not-configured';
92
+ adapter: SignalSourceName;
93
+ envVarName: string;
94
+ message: string;
95
+ }
96
+ /**
97
+ * RFC-0030 OQ-13.1 v0.3 re-walkthrough: emitted when an adapter has the
98
+ * credential env var present BUT the upstream service rejected the auth call
99
+ * (401 / 403). Downstream auto-action: emit a ROTATION task asking the
100
+ * operator to rotate / re-generate the credential. Pipeline continues with
101
+ * remaining valid adapters.
102
+ */
103
+ export interface AdapterCredentialRejectedDecision {
104
+ type: 'Decision';
105
+ decision: 'adapter-credential-rejected';
106
+ adapter: SignalSourceName;
107
+ message: string;
108
+ }
109
+ /**
110
+ * RFC-0030 OQ-13.1 v0.3 re-walkthrough: emitted when an adapter declares
111
+ * `requiresOAuth = true`. Phase 1 ships ENV-VAR-ONLY adapters; OAuth lifecycle
112
+ * (refresh tokens, scopes) is a substantial separate concern deferred to a
113
+ * future credential-management RFC. The registry refuses such adapters and
114
+ * surfaces this Decision; pipeline continues with the env-var-based adapters.
115
+ */
116
+ export interface AdapterRequiresCredentialMgmtRfcDecision {
117
+ type: 'Decision';
118
+ decision: 'adapter-requires-credential-mgmt-rfc';
119
+ adapter: SignalSourceName;
120
+ message: string;
121
+ }
122
+ export interface ManualSignalIncompleteDecision {
123
+ type: 'Decision';
124
+ decision: 'manual-signal-incomplete';
125
+ adapter: 'signal-source-manual';
126
+ sourceId?: string;
127
+ message: string;
128
+ }
129
+ /**
130
+ * RFC-0030 OQ-13.4 v0.3 re-walkthrough: emitted when a manual signal entry
131
+ * would exceed the per-operator daily cap (default 10/day, configurable via
132
+ * `manualEntry.dailyCapPerOperator`). Downstream auto-action: surface a
133
+ * batch-review escalation task. The signal is REFUSED (not silently dropped)
134
+ * so the operator sees the rejection and can escalate legitimately.
135
+ */
136
+ export interface ManualSignalRateLimitExceededDecision {
137
+ type: 'Decision';
138
+ decision: 'manual-signal-rate-limit-exceeded';
139
+ adapter: 'signal-source-manual';
140
+ attestedBy: string;
141
+ /** UTC ISO date (YYYY-MM-DD) of the bucket that overflowed. */
142
+ utcDate: string;
143
+ dailyCap: number;
144
+ sourceId?: string;
145
+ message: string;
146
+ }
147
+ /**
148
+ * RFC-0030 OQ-13.4 v0.3 re-walkthrough: emitted when the rolling
149
+ * manual/total share metric exceeds the configured threshold (default 30%
150
+ * over a 7-day window). Architectural anti-pattern warning, NOT a block —
151
+ * surfaces that the pipeline is acting as a data-entry tool rather than
152
+ * automated demand-detection. Pipeline continues normally.
153
+ */
154
+ export interface ManualSignalShareElevatedDecision {
155
+ type: 'Decision';
156
+ decision: 'manual-signal-share-elevated';
157
+ /** Computed manual/total ratio over the window. */
158
+ manualShare: number;
159
+ /** Threshold that was exceeded (config: `manualEntry.qualityMetric.shareWarningThreshold`). */
160
+ threshold: number;
161
+ windowDays: number;
162
+ manualSignals: number;
163
+ totalSignals: number;
164
+ message: string;
165
+ }
166
+ export interface SignalFetchResult {
167
+ signals: RawSignal[];
168
+ decisions: Array<AdapterCredentialInvalidDecision | AdapterCredentialNotConfiguredDecision | AdapterCredentialRejectedDecision | AdapterRequiresCredentialMgmtRfcDecision | ManualSignalIncompleteDecision | ManualSignalRateLimitExceededDecision | SignalResidencyViolationDecision>;
169
+ }
170
+ /**
171
+ * Emitted at adapter level when a signal's `region` doesn't match the adopter's
172
+ * declared regime constraints per RFC-0030 OQ-13.3 (composes with RFC-0022
173
+ * Compliance Posture). Adapter response: refuse the signal + log the Decision +
174
+ * emit a `compliance.yaml regimeOverrides` clarification task. Pipeline does
175
+ * NOT halt — the catalog absorbs the violation (G0 non-blocking pipeline contract
176
+ * per RFC-0035).
177
+ */
178
+ export interface SignalResidencyViolationDecision {
179
+ type: 'Decision';
180
+ decision: 'signal-residency-violation';
181
+ adapter: SignalSourceName;
182
+ sourceId: string;
183
+ /** The region the signal claimed (or 'unknown' when region metadata absent). */
184
+ signalRegion: string;
185
+ /** Regime IDs (e.g. 'gdpr', 'hipaa') whose residency constraints were violated. */
186
+ violatedRegimes: string[];
187
+ /** Allowed regions per the adopter's regime declaration. */
188
+ allowedRegions: string[];
189
+ message: string;
190
+ }
191
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Signal ingestion source-adapter substrate for RFC-0030 Phase 1.
3
+ *
4
+ * Source adapters fetch raw demand signals from external systems while keeping
5
+ * classification, clustering, and scoring out of this layer.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,270 @@
1
+ /**
2
+ * RFC-0028 §7.2 — structural + statistical drift composition.
3
+ *
4
+ * Phase 3 of RFC-0028 §7.2 v0.2 resolution. Wires the canonical pairing of
5
+ * the two drift-detection layers with the explicit composition rules the
6
+ * operator resolved on 2026-05-27:
7
+ *
8
+ * 1. **Structural drift (CI authoring-time) REJECTS deployment.** The
9
+ * type-registry CI gate (`scripts/check-substrate-contract.mjs`,
10
+ * AISDLC-453) is the hard gate. When any of its 5 assertions fail it emits
11
+ * `Decision: substrate-structural-drift-detected` (severity HIGH) and
12
+ * blocks PR merge via a non-zero exit code. This module does NOT rebuild
13
+ * that gate — it *represents* its outcome so the two layers can be
14
+ * composed and correlated. {@link toStructuralDriftEvents} maps the gate's
15
+ * result into the composition model.
16
+ *
17
+ * 2. **Statistical drift (runtime) SURFACES to operator (RFC-0035 G0
18
+ * non-blocking).** PPA's `SoulDriftDetected` signal (rolling 30-day mean
19
+ * < 0.4 or stddev > 0.15 sustained for 3 sprints) routes to
20
+ * `Decision: soul-statistical-drift-detected` → operator batch review with
21
+ * three reconciliation paths. The pipeline NEVER halts on statistical
22
+ * drift. {@link evaluateStatisticalDrift} computes the signal;
23
+ * {@link composeDrift} routes the firing signal to the catalog request.
24
+ *
25
+ * 3. **Both Decisions composable in the catalog.** Both classes carry a
26
+ * `soulId` + a stable `driftClass` discriminant and share one catalog
27
+ * scope ({@link DRIFT_DECISION_SCOPE}) so an operator can query
28
+ * "show me all drift events for Soul X" and get structural (rejected at
29
+ * CI) and statistical (caught at runtime) events side-by-side —
30
+ * {@link correlateDriftBySoul}.
31
+ *
32
+ * 4. **Cold-start handling.** Statistical detection needs a rolling 30d
33
+ * baseline. Pre-baseline (< 30d of signal), the detector returns a
34
+ * `calibrating` status and emits NO statistical Decisions — structural
35
+ * detection is the sole defense during the calibration window. The
36
+ * cold-start shape mirrors RFC-0030 §13 OQ-13.5's z-score flooding
37
+ * detector (calibrating until the rolling window fills, then active).
38
+ *
39
+ * **AC-8 — no parallel event emitter.** This module does NOT import or write
40
+ * to the catalog event log directly. Mirroring the Phase 1 `identity-class.ts`
41
+ * audit and the Phase 2 `check-substrate-contract.mjs` gate, it produces
42
+ * `DriftDecisionRequest` payloads (summary + scope + source + options) that
43
+ * the *caller* forwards to the existing RFC-0035 substrate via
44
+ * `node pipeline-cli/bin/cli-decisions.mjs add` (or `makeDecisionOpenedEvent`
45
+ * + `appendDecisionEvent` in-process). The request shape is byte-compatible
46
+ * with `cli-decisions add --summary … --scope … --option id:desc`. This keeps
47
+ * the orchestrator package free of a build-time dependency on
48
+ * `@ai-sdlc/pipeline-cli`'s dist output and avoids a second emitter.
49
+ *
50
+ * @see spec/rfcs/RFC-0028-engineering-axis-substrate-enforcement.md §7.2
51
+ * @see spec/rfcs/RFC-0035-decision-catalog-operator-routing.md (G0 routing)
52
+ * @see scripts/check-substrate-contract.mjs (the structural layer, AISDLC-453)
53
+ * @module substrate/drift-composition
54
+ */
55
+ /**
56
+ * The two canonical drift classes per RFC-0028 §7.2. The discriminant is
57
+ * stable so the catalog can correlate both classes for a single Soul DID.
58
+ */
59
+ export type DriftClass = 'structural' | 'statistical';
60
+ /**
61
+ * The RFC-0035 Decision scope used for every drift Decision. Both classes
62
+ * share one scope so `cli-decisions list --scope substrate-drift` returns
63
+ * the composed view (AC-3 / AC-5).
64
+ */
65
+ export declare const DRIFT_DECISION_SCOPE = "substrate-drift";
66
+ /** Decision summary slug for structural drift (matches AISDLC-453 gate). */
67
+ export declare const STRUCTURAL_DECISION_SLUG = "substrate-structural-drift-detected";
68
+ /** Decision summary slug for statistical drift (RFC-0028 §7.2 rule 2). */
69
+ export declare const STATISTICAL_DECISION_SLUG = "soul-statistical-drift-detected";
70
+ /**
71
+ * Statistical-drift detection thresholds, frozen from RFC-0028 §7.2 / PPA's
72
+ * `SoulDriftDetected` definition. A drift fires when the rolling 30-day mean
73
+ * drops below {@link MEAN_FLOOR} OR the rolling stddev exceeds
74
+ * {@link STDDEV_CEILING}, sustained for {@link SUSTAINED_SPRINTS} sprints.
75
+ */
76
+ export declare const MEAN_FLOOR = 0.4;
77
+ export declare const STDDEV_CEILING = 0.15;
78
+ export declare const SUSTAINED_SPRINTS = 3;
79
+ /** Rolling baseline window in days (RFC-0028 §7.2 cold-start: 30d). */
80
+ export declare const BASELINE_WINDOW_DAYS = 30;
81
+ /**
82
+ * One Decision-option choice the operator picks from. Mirrors the
83
+ * RFC-0035 `DecisionOption` shape (`pipeline-cli/src/decisions/decision-record.ts`)
84
+ * without importing it — kept structurally identical so a caller can spread
85
+ * these directly into `makeDecisionOpenedEvent({ options })` or render them as
86
+ * `--option <id>:<description>` flags for `cli-decisions add`.
87
+ */
88
+ export interface DriftDecisionOption {
89
+ id: string;
90
+ description: string;
91
+ consequences?: string[];
92
+ }
93
+ /**
94
+ * A ready-to-file Decision request. The caller forwards this to the RFC-0035
95
+ * catalog (CLI or in-process). The field names match the catalog's
96
+ * `OpenDecisionInput` so no translation layer is needed.
97
+ */
98
+ export interface DriftDecisionRequest {
99
+ /** RFC-0035 Decision source. Structural=emergent-finding; statistical=framework-calibration. */
100
+ source: 'emergent-finding' | 'framework-calibration';
101
+ scope: string;
102
+ summary: string;
103
+ body?: string;
104
+ /** Statistical drift is reversible (G0 non-blocking); structural is a hard gate. */
105
+ reversible: boolean;
106
+ options: DriftDecisionOption[];
107
+ }
108
+ /**
109
+ * A drift event in the composition model — the side-by-side unit an operator
110
+ * sees. Both structural and statistical events project to this shape so the
111
+ * TUI / catalog can render them together.
112
+ */
113
+ export interface DriftEvent {
114
+ driftClass: DriftClass;
115
+ /** Soul DID the drift applies to. */
116
+ soulId: string;
117
+ /**
118
+ * Structural = HIGH (hard gate). Statistical = advisory (non-blocking, G0).
119
+ */
120
+ severity: 'high' | 'advisory';
121
+ /** Whether this drift class blocks deployment. Structural=true always. */
122
+ blocking: boolean;
123
+ /** One-line operator-facing summary (used as the Decision summary). */
124
+ summary: string;
125
+ /** Free-form detail body for the Decision. */
126
+ detail?: string;
127
+ }
128
+ /**
129
+ * The three (and only three) operator reconciliation paths for a
130
+ * `soul-statistical-drift-detected` Decision, per RFC-0028 §7.2:
131
+ *
132
+ * (a) confirm drift as legitimate evolution → emit DID amendment
133
+ * (b) confirm drift as substrate violation → file fix task
134
+ * (c) defer for the next operator review window
135
+ */
136
+ export declare const STATISTICAL_RECONCILIATION_OPTIONS: readonly DriftDecisionOption[];
137
+ /** Structural-drift reconciliation options mirror the AISDLC-453 CI gate. */
138
+ export declare const STRUCTURAL_RECONCILIATION_OPTIONS: readonly DriftDecisionOption[];
139
+ /**
140
+ * The relevant subset of the structural gate's failure record
141
+ * (`scripts/check-substrate-contract.mjs#AssertionResult`). Re-declared here
142
+ * as a structural type so this module does not import the `.mjs` CI script
143
+ * (which lives outside the orchestrator build graph) — callers pass the
144
+ * gate's result through.
145
+ */
146
+ export interface StructuralGateFailure {
147
+ soulId: string;
148
+ message: string;
149
+ /** The gate's pre-formatted Decision summary, when present. */
150
+ decisionSummary?: string;
151
+ }
152
+ export interface StructuralGateResult {
153
+ /** True when the gate passed (no structural drift). */
154
+ passed: boolean;
155
+ /** True when no contracts exist (cold-start no-op). */
156
+ coldStart: boolean;
157
+ failures: StructuralGateFailure[];
158
+ }
159
+ /**
160
+ * Project the structural CI gate's result into composition `DriftEvent`s.
161
+ *
162
+ * One `DriftEvent` per gate failure. Always `blocking: true` / severity
163
+ * `high` — structural drift is the hard gate (RFC-0028 §7.2 rule 1). Returns
164
+ * `[]` when the gate passed or was a cold-start no-op (no contracts).
165
+ */
166
+ export declare function toStructuralDriftEvents(result: StructuralGateResult): DriftEvent[];
167
+ /**
168
+ * A single dated drift-metric sample for one Soul DID. `value` is the PPA
169
+ * soul-coherence metric in [0, 1]; `at` is the sample timestamp.
170
+ */
171
+ export interface SoulDriftSample {
172
+ /** ISO-8601 timestamp (or any Date-parseable string). */
173
+ at: string;
174
+ /** Coherence metric in [0, 1]; lower = more drift. */
175
+ value: number;
176
+ }
177
+ /**
178
+ * The detector's status. `calibrating` = pre-baseline (< 30d of signal); the
179
+ * detector emits NO statistical Decisions in this state (cold-start, AC-4).
180
+ * `active` = baseline accumulated; drift may fire.
181
+ */
182
+ export type StatisticalDriftStatus = 'calibrating' | 'active';
183
+ export interface StatisticalDriftResult {
184
+ status: StatisticalDriftStatus;
185
+ /** True only when status is `active` AND the drift condition is met. */
186
+ drifted: boolean;
187
+ /** Rolling mean over the baseline window (null while calibrating). */
188
+ rollingMean: number | null;
189
+ /** Rolling population stddev over the window (null while calibrating). */
190
+ rollingStdDev: number | null;
191
+ /** Consecutive sprints the drift condition has held (active state). */
192
+ sustainedSprints: number;
193
+ /** Human-readable reason — used for the Decision detail when drifted. */
194
+ reason: string;
195
+ }
196
+ /**
197
+ * Evaluate statistical drift for one Soul DID over its metric history.
198
+ *
199
+ * Cold-start (AC-4): if the span between the earliest sample and `now` is
200
+ * shorter than {@link BASELINE_WINDOW_DAYS}, the detector is still
201
+ * `calibrating` — it returns `drifted: false` with null statistics and the
202
+ * caller emits no Decision. Structural detection (AISDLC-453) is the sole
203
+ * defense during this window.
204
+ *
205
+ * Once the window is filled the detector is `active`: drift fires when the
206
+ * rolling mean < {@link MEAN_FLOOR} OR the rolling stddev >
207
+ * {@link STDDEV_CEILING}, AND that condition has held for at least
208
+ * {@link SUSTAINED_SPRINTS} consecutive sprint buckets.
209
+ *
210
+ * The cold-start shape mirrors RFC-0030 §13 OQ-13.5's z-score flooding
211
+ * detector (calibrating until the window accumulates, then active).
212
+ *
213
+ * @param samples Metric history (any order). Empty → calibrating.
214
+ * @param sprintFlags Per-sprint booleans (most-recent last) indicating
215
+ * whether the drift condition held in each sprint; used to enforce the
216
+ * "3 sustained sprints" rule independent of raw sample cadence. When
217
+ * omitted, sustained-sprint accounting falls back to whether the current
218
+ * window meets the condition (counts as 1 sprint, so a single-window
219
+ * breach is reported but does not satisfy the 3-sprint rule).
220
+ * @param now Clock override for deterministic tests.
221
+ */
222
+ export declare function evaluateStatisticalDrift(samples: SoulDriftSample[], sprintFlags?: boolean[], now?: Date): StatisticalDriftResult;
223
+ /**
224
+ * Project an `active` + `drifted` statistical result into a composition
225
+ * `DriftEvent`. Returns `null` while calibrating or not drifted — there is
226
+ * nothing to surface to the operator (AC-4: no statistical Decisions during
227
+ * cold-start).
228
+ */
229
+ export declare function toStatisticalDriftEvent(soulId: string, result: StatisticalDriftResult): DriftEvent | null;
230
+ export interface ComposeDriftResult {
231
+ /** All composed drift events (structural + statistical), side-by-side. */
232
+ events: DriftEvent[];
233
+ /**
234
+ * Ready-to-file Decision requests, one per surfaced/blocked event, in the
235
+ * same order as `events`. The caller forwards each to the RFC-0035 catalog
236
+ * (`cli-decisions add` / `makeDecisionOpenedEvent`) — this module does NOT
237
+ * write the event log itself (AC-8).
238
+ */
239
+ requests: DriftDecisionRequest[];
240
+ /** True if any structural (blocking) drift is present — the CI hard gate. */
241
+ blocked: boolean;
242
+ }
243
+ /** Build the catalog request for one composed drift event. */
244
+ export declare function toDecisionRequest(event: DriftEvent): DriftDecisionRequest;
245
+ /**
246
+ * Compose the structural gate outcome with a set of statistical results.
247
+ *
248
+ * - Structural events → `substrate-structural-drift-detected` (HIGH,
249
+ * blocking). Represented from the CI gate result; the gate itself already
250
+ * emits + blocks at CI time (AISDLC-453), so the catalog request here is the
251
+ * composition/audit projection (so structural + statistical sit
252
+ * side-by-side in one scope).
253
+ * - Statistical drifted events → `soul-statistical-drift-detected`
254
+ * (advisory, non-blocking, G0) with the three reconciliation options.
255
+ * - Calibrating / non-drifted statistical results emit NO request (AC-4).
256
+ *
257
+ * The pipeline never halts here: `blocked` reports the structural hard-gate
258
+ * state for the CI caller to act on, but statistical drift never sets it.
259
+ */
260
+ export declare function composeDrift(structural: StructuralGateResult, statistical: Array<{
261
+ soulId: string;
262
+ result: StatisticalDriftResult;
263
+ }>): ComposeDriftResult;
264
+ /**
265
+ * Group composed drift events by Soul DID so an operator can query
266
+ * "show me all drift events for Soul X" and get both classes side-by-side.
267
+ * Returns a map keyed by `soulId` whose values preserve event order.
268
+ */
269
+ export declare function correlateDriftBySoul(events: DriftEvent[]): Map<string, DriftEvent[]>;
270
+ //# sourceMappingURL=drift-composition.d.ts.map