@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.
- package/dist/__test-helpers/git-env.d.ts +40 -0
- package/dist/__test-helpers/git-env.js +73 -0
- package/dist/adapters.d.ts +42 -3
- package/dist/adapters.js +133 -3
- package/dist/admission-composite.d.ts +134 -1
- package/dist/admission-composite.js +170 -6
- package/dist/admission-enrichment.d.ts +12 -3
- package/dist/admission-enrichment.js +71 -10
- package/dist/admission-hc.d.ts +20 -1
- package/dist/admission-hc.js +12 -1
- package/dist/admission-score.d.ts +44 -0
- package/dist/admission-score.js +11 -2
- package/dist/backlog-adapter.d.ts +45 -0
- package/dist/backlog-adapter.js +145 -1
- package/dist/calibration.d.ts +81 -0
- package/dist/calibration.js +76 -0
- package/dist/cli/commands/git-remote.d.ts +25 -0
- package/dist/cli/commands/git-remote.js +80 -1
- package/dist/cli/commands/init-features.d.ts +507 -0
- package/dist/cli/commands/init-features.js +1100 -0
- package/dist/cli/commands/init-templates.d.ts +301 -0
- package/dist/cli/commands/init-templates.js +1341 -0
- package/dist/cli/commands/init.d.ts +67 -0
- package/dist/cli/commands/init.js +301 -2
- package/dist/cli/commands/run.js +9 -1
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.js +42 -8
- package/dist/compliance/composer.d.ts +79 -0
- package/dist/compliance/composer.js +258 -0
- package/dist/compliance/errors.d.ts +64 -0
- package/dist/compliance/errors.js +85 -0
- package/dist/compliance/loader.d.ts +52 -0
- package/dist/compliance/loader.js +124 -0
- package/dist/compliance/types.d.ts +184 -0
- package/dist/compliance/types.js +41 -0
- package/dist/compliance-clearance.d.ts +269 -0
- package/dist/compliance-clearance.js +269 -0
- package/dist/config.js +17 -0
- package/dist/cost-tracker.d.ts +22 -0
- package/dist/cost-tracker.js +41 -0
- package/dist/database/adapters/external.js +5 -1
- package/dist/design-authority.d.ts +13 -0
- package/dist/design-authority.js +13 -0
- package/dist/embedding/adapters/openai-text-embedding-3-small.d.ts +71 -0
- package/dist/embedding/adapters/openai-text-embedding-3-small.js +190 -0
- package/dist/embedding/consumers/tessellation-drift.d.ts +74 -0
- package/dist/embedding/consumers/tessellation-drift.js +76 -0
- package/dist/embedding/cross-provider.d.ts +78 -0
- package/dist/embedding/cross-provider.js +75 -0
- package/dist/embedding/deprecation.d.ts +151 -0
- package/dist/embedding/deprecation.js +229 -0
- package/dist/embedding/errors.d.ts +90 -0
- package/dist/embedding/errors.js +150 -0
- package/dist/embedding/index.d.ts +29 -0
- package/dist/embedding/index.js +24 -0
- package/dist/embedding/pipeline-load.d.ts +146 -0
- package/dist/embedding/pipeline-load.js +178 -0
- package/dist/embedding/registry.d.ts +45 -0
- package/dist/embedding/registry.js +61 -0
- package/dist/embedding/stale-vector.d.ts +110 -0
- package/dist/embedding/stale-vector.js +92 -0
- package/dist/embedding/storage/index.d.ts +51 -0
- package/dist/embedding/storage/index.js +43 -0
- package/dist/embedding/storage/jsonl-backend.d.ts +150 -0
- package/dist/embedding/storage/jsonl-backend.js +332 -0
- package/dist/embedding/storage/types.d.ts +135 -0
- package/dist/embedding/storage/types.js +13 -0
- package/dist/embedding/types.d.ts +180 -0
- package/dist/embedding/types.js +10 -0
- package/dist/execute.d.ts +29 -2
- package/dist/execute.js +179 -35
- package/dist/index.d.ts +14 -2
- package/dist/index.js +19 -2
- package/dist/journey/inheritance-validator.d.ts +396 -0
- package/dist/journey/inheritance-validator.js +370 -0
- package/dist/journey/state-id-drift-rule.d.ts +137 -0
- package/dist/journey/state-id-drift-rule.js +245 -0
- package/dist/journey-sa2-router.d.ts +395 -0
- package/dist/journey-sa2-router.js +308 -0
- package/dist/models/classifier.d.ts +3 -1
- package/dist/models/classifier.js +61 -5
- package/dist/pillar-breakdown.d.ts +23 -1
- package/dist/pillar-breakdown.js +9 -0
- package/dist/runners/review-agent.js +6 -2
- package/dist/runners/runner-registry.d.ts +36 -0
- package/dist/runners/runner-registry.js +90 -0
- package/dist/runtime/attestations.d.ts +663 -11
- package/dist/runtime/attestations.js +971 -24
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/parallelism-flag.d.ts +21 -3
- package/dist/runtime/parallelism-flag.js +27 -6
- package/dist/runtime/port-allocator.d.ts +11 -0
- package/dist/runtime/port-allocator.js +30 -0
- package/dist/sa-scoring/layer3-llm.js +6 -1
- package/dist/sa-scoring/revision-proposal-config.d.ts +178 -0
- package/dist/sa-scoring/revision-proposal-config.js +198 -0
- package/dist/sa-scoring/revision-proposal.d.ts +285 -0
- package/dist/sa-scoring/revision-proposal.js +417 -0
- package/dist/signal-ingestion/adapters/community-thread.d.ts +43 -0
- package/dist/signal-ingestion/adapters/community-thread.js +55 -0
- package/dist/signal-ingestion/adapters/in-app-feedback.d.ts +67 -0
- package/dist/signal-ingestion/adapters/in-app-feedback.js +51 -0
- package/dist/signal-ingestion/adapters/manual.d.ts +78 -0
- package/dist/signal-ingestion/adapters/manual.js +112 -0
- package/dist/signal-ingestion/adapters/support-ticket.d.ts +47 -0
- package/dist/signal-ingestion/adapters/support-ticket.js +51 -0
- package/dist/signal-ingestion/classifier.d.ts +205 -0
- package/dist/signal-ingestion/classifier.js +494 -0
- package/dist/signal-ingestion/clustering-types.d.ts +36 -0
- package/dist/signal-ingestion/clustering-types.js +14 -0
- package/dist/signal-ingestion/clustering.d.ts +200 -0
- package/dist/signal-ingestion/clustering.js +413 -0
- package/dist/signal-ingestion/config.d.ts +351 -0
- package/dist/signal-ingestion/config.js +587 -0
- package/dist/signal-ingestion/d1.d.ts +252 -0
- package/dist/signal-ingestion/d1.js +235 -0
- package/dist/signal-ingestion/errors.d.ts +73 -0
- package/dist/signal-ingestion/errors.js +108 -0
- package/dist/signal-ingestion/governance-events.d.ts +181 -0
- package/dist/signal-ingestion/governance-events.js +189 -0
- package/dist/signal-ingestion/index.d.ts +35 -0
- package/dist/signal-ingestion/index.js +53 -0
- package/dist/signal-ingestion/manual-share-metric.d.ts +93 -0
- package/dist/signal-ingestion/manual-share-metric.js +106 -0
- package/dist/signal-ingestion/registry.d.ts +40 -0
- package/dist/signal-ingestion/registry.js +137 -0
- package/dist/signal-ingestion/residency.d.ts +227 -0
- package/dist/signal-ingestion/residency.js +238 -0
- package/dist/signal-ingestion/significance.d.ts +554 -0
- package/dist/signal-ingestion/significance.js +555 -0
- package/dist/signal-ingestion/types.d.ts +191 -0
- package/dist/signal-ingestion/types.js +8 -0
- package/dist/substrate/drift-composition.d.ts +270 -0
- package/dist/substrate/drift-composition.js +306 -0
- package/dist/substrate/drift-tui-surface.d.ts +61 -0
- package/dist/substrate/drift-tui-surface.js +102 -0
- package/dist/substrate/identity-class.d.ts +176 -0
- package/dist/substrate/identity-class.js +201 -0
- package/dist/tessellation/cross-soul-provenance-rule.d.ts +133 -0
- package/dist/tessellation/cross-soul-provenance-rule.js +171 -0
- package/dist/tessellation/inter-soul-embedding-distance-rule.d.ts +61 -0
- package/dist/tessellation/inter-soul-embedding-distance-rule.js +67 -0
- package/dist/tessellation/rule-registry.d.ts +269 -0
- package/dist/tessellation/rule-registry.js +92 -0
- package/dist/tessellation/soul-slug-ast-scan-rule.d.ts +90 -0
- package/dist/tessellation/soul-slug-ast-scan-rule.js +158 -0
- package/dist/tessellation-admission.d.ts +162 -0
- package/dist/tessellation-admission.js +146 -0
- package/dist/tessellation-drift.d.ts +246 -0
- package/dist/tessellation-drift.js +250 -0
- package/dist/validate-config.js +13 -0
- package/dist/validate-issue.js +2 -2
- package/dist/variant/cardinality-activation.d.ts +126 -0
- package/dist/variant/cardinality-activation.js +101 -0
- package/dist/variant/deprecation-lifecycle.d.ts +184 -0
- package/dist/variant/deprecation-lifecycle.js +208 -0
- package/dist/variant/drift-extension.d.ts +136 -0
- package/dist/variant/drift-extension.js +164 -0
- package/dist/variant/engineering-review.d.ts +185 -0
- package/dist/variant/engineering-review.js +142 -0
- package/dist/variant/index.d.ts +32 -0
- package/dist/variant/index.js +32 -0
- package/dist/variant/inheritance-validator.d.ts +165 -0
- package/dist/variant/inheritance-validator.js +139 -0
- package/dist/variant/internal-adopter/index.d.ts +11 -0
- package/dist/variant/internal-adopter/index.js +10 -0
- package/dist/variant/internal-adopter/products.d.ts +156 -0
- package/dist/variant/internal-adopter/products.js +366 -0
- package/dist/variant-admission.d.ts +316 -0
- package/dist/variant-admission.js +247 -0
- package/package.json +11 -8
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0030 Phase 5 — D1 formula reformulation + RFC-0008 PPA integration.
|
|
3
|
+
*
|
|
4
|
+
* Reformulates the existing PPA D1 (Demand Pressure) input to consume
|
|
5
|
+
* cluster-level demand from the signal-ingestion pipeline per RFC-0030 §10:
|
|
6
|
+
*
|
|
7
|
+
* ```
|
|
8
|
+
* D1(cluster) = Σ over signals in cluster:
|
|
9
|
+
* signal.baseWeight # 1.0 Tier 1; 0.3 Tier 2 above threshold; 0 below
|
|
10
|
+
* × signal.tierMultiplier # configurable per deployment (§6.1)
|
|
11
|
+
* × signal.icpResonance # configurable per deployment (§6.2)
|
|
12
|
+
* × signal.recencyDecay # exp(-age_days × ln(2) / half_life_days)
|
|
13
|
+
* × cluster.saResonance # filter per §9 (applied via the SA bucket multiplier)
|
|
14
|
+
*
|
|
15
|
+
* D1 is then normalized across all active clusters to [0, 1] and fed into the
|
|
16
|
+
* existing PPA D formula (PPA v1.1 §3.1).
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* **Non-replacement contract (AC #2 + AC #4)**: human-authored backlog items
|
|
20
|
+
* continue to feed D1 alongside signal-pipeline-derived demand. The pipeline
|
|
21
|
+
* adds a parallel input path; the existing path is preserved. When the
|
|
22
|
+
* pipeline is disabled (`config.enabled === false`, the default), this module
|
|
23
|
+
* contributes zero signal-pipeline demand — the composed D1 reduces to the
|
|
24
|
+
* backlog-item input unchanged. When both inputs are active, weights from
|
|
25
|
+
* `config.d1Composition` blend them (default 50/50).
|
|
26
|
+
*
|
|
27
|
+
* **RFC-0008 PPA Triad integration (AC #3)**: the resulting per-item composed
|
|
28
|
+
* D1 score is consumed by the `enrichDemandSignalFromClusters()` helper which
|
|
29
|
+
* overlays it onto a `PriorityInput.demandSignal` field — the same field the
|
|
30
|
+
* admission composite (`admission-composite.ts`) reads via `mapIssueToPriorityInput`
|
|
31
|
+
* for the Sα₁ × Dπ_adjusted × Eρ₅ admission gate per RFC-0008 §A.6.
|
|
32
|
+
*
|
|
33
|
+
* **Cluster-to-item routing**: the pipeline produces cluster-level demand;
|
|
34
|
+
* admission scoring is per-item (per backlog task / GitHub issue). The
|
|
35
|
+
* composition treats the pipeline-derived signal as a *deployment-level
|
|
36
|
+
* demand floor* that lifts the demand signal for items whose subject
|
|
37
|
+
* matches an active cluster theme (cluster-to-item matching is left to a
|
|
38
|
+
* caller-supplied lookup in v1; v2 will wire to RFC-0024 capture matching).
|
|
39
|
+
*
|
|
40
|
+
* @module signal-ingestion/d1
|
|
41
|
+
*/
|
|
42
|
+
import type { SignalIngestionConfig } from './config.js';
|
|
43
|
+
import type { QuarantineStore, SignificanceAssessedCluster } from './significance.js';
|
|
44
|
+
/**
|
|
45
|
+
* Options for `computeClusterD1()` / `aggregateD1FromClusters()` per
|
|
46
|
+
* AISDLC-433. The optional `quarantineStore` lets the D1 path consult the
|
|
47
|
+
* z-score detector's quarantine state and EXCLUDE quarantined signals from
|
|
48
|
+
* cluster scoring (AC #6). Back-compat: when omitted, no signals are treated
|
|
49
|
+
* as quarantined — pre-AISDLC-433 callers continue to work unchanged.
|
|
50
|
+
*/
|
|
51
|
+
export interface ComputeClusterD1Options {
|
|
52
|
+
quarantineStore?: QuarantineStore;
|
|
53
|
+
/** Clock override for quarantine expiry checks. Defaults to `new Date()`. */
|
|
54
|
+
asOf?: Date;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Per-cluster D1 score breakdown — produced by `computeClusterD1()`.
|
|
58
|
+
*
|
|
59
|
+
* `rawScore` is the §10 formula output BEFORE normalisation (sum across
|
|
60
|
+
* cluster members × the SA bucket multiplier). `normalizedScore` is filled
|
|
61
|
+
* in by `aggregateD1FromClusters()` after the full population is known.
|
|
62
|
+
*/
|
|
63
|
+
export interface ClusterD1Score {
|
|
64
|
+
clusterId: string;
|
|
65
|
+
/** Sum of per-signal weights × cluster SA multiplier; pre-normalisation. */
|
|
66
|
+
rawScore: number;
|
|
67
|
+
/**
|
|
68
|
+
* Filled by `aggregateD1FromClusters()` — `rawScore / max(rawScore across
|
|
69
|
+
* eligible clusters)`. Range [0, 1]. `0` when the cluster is ineligible
|
|
70
|
+
* (significance gate failed or SA bucket excludes it).
|
|
71
|
+
*/
|
|
72
|
+
normalizedScore: number;
|
|
73
|
+
/** Whether the cluster contributes to D1 at all. Mirrors `eligibleForD1`. */
|
|
74
|
+
eligible: boolean;
|
|
75
|
+
/** Cluster size (member count) — useful for downstream auditing. */
|
|
76
|
+
signalCount: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Result of aggregating per-cluster D1 scores into a deployment-level
|
|
80
|
+
* pipeline-derived demand input.
|
|
81
|
+
*/
|
|
82
|
+
export interface AggregatedD1Result {
|
|
83
|
+
/** Per-cluster scores, with normalised values populated. */
|
|
84
|
+
clusters: ClusterD1Score[];
|
|
85
|
+
/**
|
|
86
|
+
* Maximum raw score across eligible clusters (the normalisation denominator).
|
|
87
|
+
* `0` when no clusters are eligible.
|
|
88
|
+
*/
|
|
89
|
+
maxRawScore: number;
|
|
90
|
+
/**
|
|
91
|
+
* Population-level summary — the mean normalised score across eligible
|
|
92
|
+
* clusters. Range [0, 1]. Useful as a deployment-level "ambient pipeline
|
|
93
|
+
* demand" indicator when no per-item cluster match exists.
|
|
94
|
+
*/
|
|
95
|
+
meanNormalizedScore: number;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Inputs to `composeD1Inputs()` per RFC-0030 §10 non-replacement contract.
|
|
99
|
+
*/
|
|
100
|
+
export interface ComposeD1InputsArgs {
|
|
101
|
+
/**
|
|
102
|
+
* Pipeline-derived per-item demand score (post-`enrichDemandSignalFromClusters`
|
|
103
|
+
* matching). Range expected [0, 1]. `undefined` when no cluster match exists
|
|
104
|
+
* — composition then falls back to `backlogItemD1` alone.
|
|
105
|
+
*/
|
|
106
|
+
signalPipelineD1?: number;
|
|
107
|
+
/**
|
|
108
|
+
* Human-authored backlog-item demand score from the existing PPA path
|
|
109
|
+
* (`mapIssueToPriorityInput().demandSignal`). Range [0, 1]. `undefined`
|
|
110
|
+
* when the backlog has no demand for the item (rare; treated as 0).
|
|
111
|
+
*/
|
|
112
|
+
backlogItemD1?: number;
|
|
113
|
+
/**
|
|
114
|
+
* Signal-ingestion config — `d1Composition` weights + `enabled` flag drive
|
|
115
|
+
* the blend. Defaults to `DEFAULT_SIGNAL_INGESTION_CONFIG` (pipeline disabled).
|
|
116
|
+
*/
|
|
117
|
+
config?: SignalIngestionConfig;
|
|
118
|
+
}
|
|
119
|
+
/** Result of composing the two D1 input streams. */
|
|
120
|
+
export interface ComposedD1Result {
|
|
121
|
+
/** The final blended D1 input. Range [0, 1]. */
|
|
122
|
+
composedScore: number;
|
|
123
|
+
/** Normalised weight actually applied to the pipeline input. */
|
|
124
|
+
signalPipelineWeightApplied: number;
|
|
125
|
+
/** Normalised weight actually applied to the backlog input. */
|
|
126
|
+
backlogItemWeightApplied: number;
|
|
127
|
+
/**
|
|
128
|
+
* Audit trail — what each branch contributed before weighting:
|
|
129
|
+
* - `signalPipelineContribution` = `signalPipelineD1 × signalPipelineWeightApplied`
|
|
130
|
+
* - `backlogItemContribution` = `backlogItemD1 × backlogItemWeightApplied`
|
|
131
|
+
*/
|
|
132
|
+
signalPipelineContribution: number;
|
|
133
|
+
backlogItemContribution: number;
|
|
134
|
+
/**
|
|
135
|
+
* Backward-compat indicator — `true` when the pipeline was disabled OR no
|
|
136
|
+
* pipeline-derived signal was provided, so the result is the backlog input
|
|
137
|
+
* unchanged. AC #4 audit hook.
|
|
138
|
+
*/
|
|
139
|
+
pipelineBypass: boolean;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Apply RFC-0030 §10 D1 formula to a single significance-assessed cluster.
|
|
143
|
+
*
|
|
144
|
+
* `rawScore` is the sum of per-member weights × the cluster's SA bucket
|
|
145
|
+
* multiplier (§10 line 5 — the SA filter applied at cluster level).
|
|
146
|
+
*
|
|
147
|
+
* When the cluster is ineligible (`assessment.eligibleForD1 === false` —
|
|
148
|
+
* Tier 2 threshold failed OR SA bucket is `out-of-scope` / `pending`), the
|
|
149
|
+
* raw score is forced to 0 per §8 / §9 contract.
|
|
150
|
+
*/
|
|
151
|
+
export declare function computeClusterD1(assessment: SignificanceAssessedCluster, config?: SignalIngestionConfig, options?: ComputeClusterD1Options): ClusterD1Score;
|
|
152
|
+
/**
|
|
153
|
+
* Aggregate per-cluster D1 scores into a deployment-level result with
|
|
154
|
+
* normalised scores per §10 final line ("D1 is normalized across all active
|
|
155
|
+
* clusters to [0, 1]").
|
|
156
|
+
*
|
|
157
|
+
* Normalisation divides each `rawScore` by the population max — keeps the
|
|
158
|
+
* eligible cluster with the strongest demand at 1.0 and orders the rest
|
|
159
|
+
* proportionally. When no clusters are eligible, all `normalizedScore` are 0
|
|
160
|
+
* and `meanNormalizedScore` is 0 — D1 cleanly degrades to "no pipeline-derived
|
|
161
|
+
* demand" without surfacing NaNs.
|
|
162
|
+
*
|
|
163
|
+
* `meanNormalizedScore` is the mean across **eligible** clusters only —
|
|
164
|
+
* ineligible clusters (rawScore = 0) don't pull the population mean down.
|
|
165
|
+
*/
|
|
166
|
+
export declare function aggregateD1FromClusters(assessments: SignificanceAssessedCluster[], config?: SignalIngestionConfig, options?: ComputeClusterD1Options): AggregatedD1Result;
|
|
167
|
+
/**
|
|
168
|
+
* Blend signal-pipeline-derived demand with the existing backlog-item demand
|
|
169
|
+
* input per RFC-0030 §10 non-replacement contract.
|
|
170
|
+
*
|
|
171
|
+
* **Backward compatibility (AC #4)**: when `config.enabled === false` the
|
|
172
|
+
* function bypasses the pipeline entirely and returns `composedScore =
|
|
173
|
+
* backlogItemD1` (or 0 when absent). `pipelineBypass = true` so callers /
|
|
174
|
+
* tests can audit the bypass branch.
|
|
175
|
+
*
|
|
176
|
+
* **Weight balancing (AC #5)**: when both inputs are present and the pipeline
|
|
177
|
+
* is enabled, weights from `config.d1Composition` are normalised to sum to 1
|
|
178
|
+
* and applied as a linear blend. Negative weights are clamped to 0 by the
|
|
179
|
+
* config validator; if both weights are 0 (operator misconfiguration), the
|
|
180
|
+
* function falls back to the unweighted average to avoid emitting NaN.
|
|
181
|
+
*
|
|
182
|
+
* **Single-input cases**: when only one input is present, the other is
|
|
183
|
+
* treated as 0; weights still apply so an operator who configured
|
|
184
|
+
* `{signalPipelineWeight: 0.8, backlogItemWeight: 0.2}` and supplies only
|
|
185
|
+
* `backlogItemD1` gets `0.2 × backlogItemD1` (which is documented behaviour —
|
|
186
|
+
* the missing input is genuinely missing demand). If you want "use this one
|
|
187
|
+
* unweighted when the other is absent" semantics, omit the absent field AND
|
|
188
|
+
* set the other input's weight to 1.0.
|
|
189
|
+
*/
|
|
190
|
+
export declare function composeD1Inputs(args: ComposeD1InputsArgs): ComposedD1Result;
|
|
191
|
+
/**
|
|
192
|
+
* Pluggable matcher: resolve a backlog work item to the most relevant cluster
|
|
193
|
+
* D1 score (if any). Callers supply this so the cluster-to-item match policy
|
|
194
|
+
* can be swapped per deployment without rewriting the core composition.
|
|
195
|
+
*
|
|
196
|
+
* v1 contract: the matcher receives a free-form `itemKey` (typically the
|
|
197
|
+
* task title or a normalised slug); returns the best-matching `ClusterD1Score`
|
|
198
|
+
* or `undefined` when no cluster is a meaningful match. The matcher is
|
|
199
|
+
* intentionally NOT given write access to the score — it only chooses which
|
|
200
|
+
* cluster the item maps onto. RFC-0024 capture matching wires this in v2.
|
|
201
|
+
*/
|
|
202
|
+
export interface ClusterMatcher {
|
|
203
|
+
(itemKey: string, aggregated: AggregatedD1Result): ClusterD1Score | undefined;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* RFC-0008 PPA Triad integration helper — applies the composed D1 to a
|
|
207
|
+
* `PriorityInput` so the admission composite consumes pipeline-derived
|
|
208
|
+
* demand through the same `demandSignal` field it already reads.
|
|
209
|
+
*
|
|
210
|
+
* The returned object is a NEW `PriorityInput` (input is not mutated). When
|
|
211
|
+
* the pipeline is disabled OR no cluster match exists, the returned object
|
|
212
|
+
* carries the input's original `demandSignal` unchanged — backward-compatible
|
|
213
|
+
* (AC #4).
|
|
214
|
+
*
|
|
215
|
+
* Composition algorithm:
|
|
216
|
+
* 1. Resolve `signalPipelineD1` via `matcher(itemKey, aggregated)` →
|
|
217
|
+
* `match?.normalizedScore` (range [0, 1]); when matcher returns
|
|
218
|
+
* `undefined`, no pipeline contribution.
|
|
219
|
+
* 2. Read `backlogItemD1` from `priorityInput.demandSignal` (already the
|
|
220
|
+
* output of `mapIssueToPriorityInput()` per existing path).
|
|
221
|
+
* 3. Compose via `composeD1Inputs()` with the configured weights.
|
|
222
|
+
* 4. Override `demandSignal` on a shallow clone of the input.
|
|
223
|
+
*
|
|
224
|
+
* The composed result and its audit fields are also returned so callers can
|
|
225
|
+
* surface the pipeline contribution in pillar-breakdown logs.
|
|
226
|
+
*/
|
|
227
|
+
export interface EnrichDemandSignalArgs<T extends {
|
|
228
|
+
demandSignal?: number;
|
|
229
|
+
}> {
|
|
230
|
+
/** The PriorityInput-shaped object to enrich. NOT mutated. */
|
|
231
|
+
priorityInput: T;
|
|
232
|
+
/** A short key the matcher uses to find a cluster (title, slug, or item ID). */
|
|
233
|
+
itemKey: string;
|
|
234
|
+
/** The aggregation result from `aggregateD1FromClusters()`. */
|
|
235
|
+
aggregated: AggregatedD1Result;
|
|
236
|
+
/** Cluster-to-item matcher; see `ClusterMatcher` docstring. */
|
|
237
|
+
matcher: ClusterMatcher;
|
|
238
|
+
/** Signal ingestion config. Defaults to `DEFAULT_SIGNAL_INGESTION_CONFIG`. */
|
|
239
|
+
config?: SignalIngestionConfig;
|
|
240
|
+
}
|
|
241
|
+
export interface EnrichDemandSignalResult<T> {
|
|
242
|
+
/** The enriched PriorityInput (shallow clone with `demandSignal` overlaid). */
|
|
243
|
+
enriched: T;
|
|
244
|
+
/** Full composition result for audit / breakdown surfacing. */
|
|
245
|
+
composition: ComposedD1Result;
|
|
246
|
+
/** Which cluster matched, when any. `undefined` when matcher returned none. */
|
|
247
|
+
matchedCluster: ClusterD1Score | undefined;
|
|
248
|
+
}
|
|
249
|
+
export declare function enrichDemandSignalFromClusters<T extends {
|
|
250
|
+
demandSignal?: number;
|
|
251
|
+
}>(args: EnrichDemandSignalArgs<T>): EnrichDemandSignalResult<T>;
|
|
252
|
+
//# sourceMappingURL=d1.d.ts.map
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0030 Phase 5 — D1 formula reformulation + RFC-0008 PPA integration.
|
|
3
|
+
*
|
|
4
|
+
* Reformulates the existing PPA D1 (Demand Pressure) input to consume
|
|
5
|
+
* cluster-level demand from the signal-ingestion pipeline per RFC-0030 §10:
|
|
6
|
+
*
|
|
7
|
+
* ```
|
|
8
|
+
* D1(cluster) = Σ over signals in cluster:
|
|
9
|
+
* signal.baseWeight # 1.0 Tier 1; 0.3 Tier 2 above threshold; 0 below
|
|
10
|
+
* × signal.tierMultiplier # configurable per deployment (§6.1)
|
|
11
|
+
* × signal.icpResonance # configurable per deployment (§6.2)
|
|
12
|
+
* × signal.recencyDecay # exp(-age_days × ln(2) / half_life_days)
|
|
13
|
+
* × cluster.saResonance # filter per §9 (applied via the SA bucket multiplier)
|
|
14
|
+
*
|
|
15
|
+
* D1 is then normalized across all active clusters to [0, 1] and fed into the
|
|
16
|
+
* existing PPA D formula (PPA v1.1 §3.1).
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* **Non-replacement contract (AC #2 + AC #4)**: human-authored backlog items
|
|
20
|
+
* continue to feed D1 alongside signal-pipeline-derived demand. The pipeline
|
|
21
|
+
* adds a parallel input path; the existing path is preserved. When the
|
|
22
|
+
* pipeline is disabled (`config.enabled === false`, the default), this module
|
|
23
|
+
* contributes zero signal-pipeline demand — the composed D1 reduces to the
|
|
24
|
+
* backlog-item input unchanged. When both inputs are active, weights from
|
|
25
|
+
* `config.d1Composition` blend them (default 50/50).
|
|
26
|
+
*
|
|
27
|
+
* **RFC-0008 PPA Triad integration (AC #3)**: the resulting per-item composed
|
|
28
|
+
* D1 score is consumed by the `enrichDemandSignalFromClusters()` helper which
|
|
29
|
+
* overlays it onto a `PriorityInput.demandSignal` field — the same field the
|
|
30
|
+
* admission composite (`admission-composite.ts`) reads via `mapIssueToPriorityInput`
|
|
31
|
+
* for the Sα₁ × Dπ_adjusted × Eρ₅ admission gate per RFC-0008 §A.6.
|
|
32
|
+
*
|
|
33
|
+
* **Cluster-to-item routing**: the pipeline produces cluster-level demand;
|
|
34
|
+
* admission scoring is per-item (per backlog task / GitHub issue). The
|
|
35
|
+
* composition treats the pipeline-derived signal as a *deployment-level
|
|
36
|
+
* demand floor* that lifts the demand signal for items whose subject
|
|
37
|
+
* matches an active cluster theme (cluster-to-item matching is left to a
|
|
38
|
+
* caller-supplied lookup in v1; v2 will wire to RFC-0024 capture matching).
|
|
39
|
+
*
|
|
40
|
+
* @module signal-ingestion/d1
|
|
41
|
+
*/
|
|
42
|
+
import { DEFAULT_SIGNAL_INGESTION_CONFIG } from './config.js';
|
|
43
|
+
import { isSignalQuarantined } from './significance.js';
|
|
44
|
+
// ── §10 formula — per cluster ───────────────────────────────────────────────
|
|
45
|
+
/**
|
|
46
|
+
* Compute the per-signal weight from a cluster member's `ClusteredSignalInput`
|
|
47
|
+
* + config-derived multipliers. Mirrors `classifier.computeSignalWeight()` but
|
|
48
|
+
* operates on the Phase-3 cluster-member shape (which dropped the
|
|
49
|
+
* `tierMultiplier` / `icpResonanceWeight` convenience fields the classifier
|
|
50
|
+
* carried for Phase-4 use).
|
|
51
|
+
*
|
|
52
|
+
* Order: `baseWeight × tierMultiplier × icpResonanceWeight × recencyDecay`
|
|
53
|
+
* exactly per §10 lines 1-4 of the formula. The cluster-level
|
|
54
|
+
* `saResonance` factor (§10 line 5) is applied OUTSIDE this function, in
|
|
55
|
+
* `computeClusterD1()`, since it's a cluster-wide property.
|
|
56
|
+
*/
|
|
57
|
+
function computeClusterMemberWeight(member, config) {
|
|
58
|
+
// Tier 1 sources base weight = 1.0; Tier 2 = 0.3 (matches classifier convention
|
|
59
|
+
// — Phase 4 significance gate independently zeros out below-threshold clusters
|
|
60
|
+
// via SA_WEIGHT_MULTIPLIERS, so we don't double-discount here).
|
|
61
|
+
const adapterTier = member.adapterTier ?? 1;
|
|
62
|
+
const baseWeight = adapterTier === 1 ? 1.0 : 0.3;
|
|
63
|
+
const tierMultiplier = config.tierMultipliers[member.customerTier];
|
|
64
|
+
const icpWeight = config.icpResonanceWeights[member.icpResonance];
|
|
65
|
+
return baseWeight * tierMultiplier * icpWeight * member.recencyDecay;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Apply RFC-0030 §10 D1 formula to a single significance-assessed cluster.
|
|
69
|
+
*
|
|
70
|
+
* `rawScore` is the sum of per-member weights × the cluster's SA bucket
|
|
71
|
+
* multiplier (§10 line 5 — the SA filter applied at cluster level).
|
|
72
|
+
*
|
|
73
|
+
* When the cluster is ineligible (`assessment.eligibleForD1 === false` —
|
|
74
|
+
* Tier 2 threshold failed OR SA bucket is `out-of-scope` / `pending`), the
|
|
75
|
+
* raw score is forced to 0 per §8 / §9 contract.
|
|
76
|
+
*/
|
|
77
|
+
export function computeClusterD1(assessment, config = DEFAULT_SIGNAL_INGESTION_CONFIG, options = {}) {
|
|
78
|
+
if (!assessment.eligibleForD1) {
|
|
79
|
+
return {
|
|
80
|
+
clusterId: assessment.cluster.clusterId,
|
|
81
|
+
rawScore: 0,
|
|
82
|
+
normalizedScore: 0,
|
|
83
|
+
eligible: false,
|
|
84
|
+
signalCount: assessment.cluster.signalCount,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// AC #6: signals currently in quarantine (flooding-flagged with active
|
|
88
|
+
// expiresAt) are excluded from the D1(cluster) formula. The exclusion is
|
|
89
|
+
// member-level — a cluster mixing quarantined + clean signals still
|
|
90
|
+
// contributes the clean members' weight; clusters whose entire membership
|
|
91
|
+
// is quarantined effectively score 0 even though they're "eligible" per
|
|
92
|
+
// significance + SA.
|
|
93
|
+
const asOf = options.asOf ?? new Date();
|
|
94
|
+
const memberSum = assessment.cluster.members.reduce((acc, member) => {
|
|
95
|
+
if (isSignalQuarantined(member.signal, options.quarantineStore, asOf))
|
|
96
|
+
return acc;
|
|
97
|
+
return acc + computeClusterMemberWeight(member, config);
|
|
98
|
+
}, 0);
|
|
99
|
+
// `assessment.d1WeightMultiplier` is the precomputed combined multiplier
|
|
100
|
+
// from Phase 4: `significanceMultiplier × SA_WEIGHT_MULTIPLIERS[bucket]`.
|
|
101
|
+
// For any eligible cluster, significanceMultiplier === 1.0 (qualified) and
|
|
102
|
+
// the bucket is one of `full` / `discounted` / `low-sa-review`, so this
|
|
103
|
+
// value is simply the §10 line-5 SA factor (range 0.3..1.0). Multiplying
|
|
104
|
+
// through it preserves the spec algebra `members × cluster.saResonance`
|
|
105
|
+
// while letting the Phase 4 single source of truth drive the math.
|
|
106
|
+
const rawScore = memberSum * assessment.d1WeightMultiplier;
|
|
107
|
+
return {
|
|
108
|
+
clusterId: assessment.cluster.clusterId,
|
|
109
|
+
rawScore,
|
|
110
|
+
normalizedScore: 0, // filled by aggregateD1FromClusters
|
|
111
|
+
eligible: true,
|
|
112
|
+
signalCount: assessment.cluster.signalCount,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Aggregate per-cluster D1 scores into a deployment-level result with
|
|
117
|
+
* normalised scores per §10 final line ("D1 is normalized across all active
|
|
118
|
+
* clusters to [0, 1]").
|
|
119
|
+
*
|
|
120
|
+
* Normalisation divides each `rawScore` by the population max — keeps the
|
|
121
|
+
* eligible cluster with the strongest demand at 1.0 and orders the rest
|
|
122
|
+
* proportionally. When no clusters are eligible, all `normalizedScore` are 0
|
|
123
|
+
* and `meanNormalizedScore` is 0 — D1 cleanly degrades to "no pipeline-derived
|
|
124
|
+
* demand" without surfacing NaNs.
|
|
125
|
+
*
|
|
126
|
+
* `meanNormalizedScore` is the mean across **eligible** clusters only —
|
|
127
|
+
* ineligible clusters (rawScore = 0) don't pull the population mean down.
|
|
128
|
+
*/
|
|
129
|
+
export function aggregateD1FromClusters(assessments, config = DEFAULT_SIGNAL_INGESTION_CONFIG, options = {}) {
|
|
130
|
+
const perCluster = assessments.map((a) => computeClusterD1(a, config, options));
|
|
131
|
+
const eligibleScores = perCluster.filter((c) => c.eligible);
|
|
132
|
+
const maxRawScore = eligibleScores.reduce((max, c) => Math.max(max, c.rawScore), 0);
|
|
133
|
+
// Populate normalisedScore in-place. When maxRawScore is 0 (no eligible
|
|
134
|
+
// clusters OR all eligible clusters had zero weight — possible if every
|
|
135
|
+
// member has icpResonance × tierMultiplier × recencyDecay = 0), normalised
|
|
136
|
+
// scores stay at 0 by short-circuiting.
|
|
137
|
+
for (const c of perCluster) {
|
|
138
|
+
c.normalizedScore = maxRawScore > 0 && c.eligible ? c.rawScore / maxRawScore : 0;
|
|
139
|
+
}
|
|
140
|
+
const meanNormalizedScore = eligibleScores.length > 0
|
|
141
|
+
? eligibleScores.reduce((sum, c) => sum + c.normalizedScore, 0) / eligibleScores.length
|
|
142
|
+
: 0;
|
|
143
|
+
return {
|
|
144
|
+
clusters: perCluster,
|
|
145
|
+
maxRawScore,
|
|
146
|
+
meanNormalizedScore,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// ── Non-replacement composition (§10.4 spirit; AC #2, #4, #5) ───────────────
|
|
150
|
+
/**
|
|
151
|
+
* Blend signal-pipeline-derived demand with the existing backlog-item demand
|
|
152
|
+
* input per RFC-0030 §10 non-replacement contract.
|
|
153
|
+
*
|
|
154
|
+
* **Backward compatibility (AC #4)**: when `config.enabled === false` the
|
|
155
|
+
* function bypasses the pipeline entirely and returns `composedScore =
|
|
156
|
+
* backlogItemD1` (or 0 when absent). `pipelineBypass = true` so callers /
|
|
157
|
+
* tests can audit the bypass branch.
|
|
158
|
+
*
|
|
159
|
+
* **Weight balancing (AC #5)**: when both inputs are present and the pipeline
|
|
160
|
+
* is enabled, weights from `config.d1Composition` are normalised to sum to 1
|
|
161
|
+
* and applied as a linear blend. Negative weights are clamped to 0 by the
|
|
162
|
+
* config validator; if both weights are 0 (operator misconfiguration), the
|
|
163
|
+
* function falls back to the unweighted average to avoid emitting NaN.
|
|
164
|
+
*
|
|
165
|
+
* **Single-input cases**: when only one input is present, the other is
|
|
166
|
+
* treated as 0; weights still apply so an operator who configured
|
|
167
|
+
* `{signalPipelineWeight: 0.8, backlogItemWeight: 0.2}` and supplies only
|
|
168
|
+
* `backlogItemD1` gets `0.2 × backlogItemD1` (which is documented behaviour —
|
|
169
|
+
* the missing input is genuinely missing demand). If you want "use this one
|
|
170
|
+
* unweighted when the other is absent" semantics, omit the absent field AND
|
|
171
|
+
* set the other input's weight to 1.0.
|
|
172
|
+
*/
|
|
173
|
+
export function composeD1Inputs(args) {
|
|
174
|
+
const config = args.config ?? DEFAULT_SIGNAL_INGESTION_CONFIG;
|
|
175
|
+
const backlog = args.backlogItemD1 ?? 0;
|
|
176
|
+
const pipeline = args.signalPipelineD1 ?? 0;
|
|
177
|
+
// Backward-compat fast path: pipeline disabled OR no pipeline input.
|
|
178
|
+
if (!config.enabled || args.signalPipelineD1 === undefined) {
|
|
179
|
+
return {
|
|
180
|
+
composedScore: clamp01(backlog),
|
|
181
|
+
signalPipelineWeightApplied: 0,
|
|
182
|
+
backlogItemWeightApplied: 1,
|
|
183
|
+
signalPipelineContribution: 0,
|
|
184
|
+
backlogItemContribution: clamp01(backlog),
|
|
185
|
+
pipelineBypass: true,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const { signalPipelineWeightApplied, backlogItemWeightApplied } = normaliseWeights(config.d1Composition);
|
|
189
|
+
const pipelineContribution = pipeline * signalPipelineWeightApplied;
|
|
190
|
+
const backlogContribution = backlog * backlogItemWeightApplied;
|
|
191
|
+
const composedScore = clamp01(pipelineContribution + backlogContribution);
|
|
192
|
+
return {
|
|
193
|
+
composedScore,
|
|
194
|
+
signalPipelineWeightApplied,
|
|
195
|
+
backlogItemWeightApplied,
|
|
196
|
+
signalPipelineContribution: pipelineContribution,
|
|
197
|
+
backlogItemContribution: backlogContribution,
|
|
198
|
+
pipelineBypass: false,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Normalise the configured weights so they sum to 1. When both are 0
|
|
203
|
+
* (degenerate operator config), fall back to a 50/50 split so the function
|
|
204
|
+
* never returns NaN downstream.
|
|
205
|
+
*/
|
|
206
|
+
function normaliseWeights(weights) {
|
|
207
|
+
const sum = weights.signalPipelineWeight + weights.backlogItemWeight;
|
|
208
|
+
if (sum <= 0) {
|
|
209
|
+
return { signalPipelineWeightApplied: 0.5, backlogItemWeightApplied: 0.5 };
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
signalPipelineWeightApplied: weights.signalPipelineWeight / sum,
|
|
213
|
+
backlogItemWeightApplied: weights.backlogItemWeight / sum,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function clamp01(n) {
|
|
217
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
218
|
+
return 0;
|
|
219
|
+
if (n >= 1)
|
|
220
|
+
return 1;
|
|
221
|
+
return n;
|
|
222
|
+
}
|
|
223
|
+
export function enrichDemandSignalFromClusters(args) {
|
|
224
|
+
const config = args.config ?? DEFAULT_SIGNAL_INGESTION_CONFIG;
|
|
225
|
+
const matchedCluster = args.matcher(args.itemKey, args.aggregated);
|
|
226
|
+
const signalPipelineD1 = matchedCluster?.normalizedScore;
|
|
227
|
+
const backlogItemD1 = args.priorityInput.demandSignal;
|
|
228
|
+
const composition = composeD1Inputs({ signalPipelineD1, backlogItemD1, config });
|
|
229
|
+
const enriched = {
|
|
230
|
+
...args.priorityInput,
|
|
231
|
+
demandSignal: composition.composedScore,
|
|
232
|
+
};
|
|
233
|
+
return { enriched, composition, matchedCluster };
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=d1.js.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { SignalSourceName } from './types.js';
|
|
2
|
+
export declare class UnknownSignalSource extends Error {
|
|
3
|
+
readonly source: string;
|
|
4
|
+
constructor(source: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class SignalSourceUnavailable extends Error {
|
|
7
|
+
readonly source: SignalSourceName;
|
|
8
|
+
constructor(source: SignalSourceName, message?: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class AdapterCredentialInvalid extends Error {
|
|
11
|
+
readonly source: SignalSourceName;
|
|
12
|
+
constructor(source: SignalSourceName, message?: string);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* RFC-0030 OQ-13.1 v0.3 re-walkthrough: distinct from `AdapterCredentialInvalid`.
|
|
16
|
+
*
|
|
17
|
+
* Raised when an adapter probes its environment for the required credential
|
|
18
|
+
* env var (e.g. `SIGNAL_ZENDESK_PAT`) and the var is missing or empty.
|
|
19
|
+
* Downstream: emit `Decision: adapter-credential-not-configured` and surface
|
|
20
|
+
* an operator SETUP task ("create + set this env var"). Pipeline continues
|
|
21
|
+
* with the remaining valid adapters (AC #4).
|
|
22
|
+
*/
|
|
23
|
+
export declare class AdapterCredentialNotConfigured extends Error {
|
|
24
|
+
readonly source: SignalSourceName;
|
|
25
|
+
readonly envVarName: string;
|
|
26
|
+
constructor(source: SignalSourceName, envVarName: string, message?: string);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* RFC-0030 OQ-13.1 v0.3 re-walkthrough: distinct from `AdapterCredentialInvalid`.
|
|
30
|
+
*
|
|
31
|
+
* Raised when an adapter has the credential env var present BUT the auth call
|
|
32
|
+
* against the upstream service is rejected (401 / 403). Downstream: emit
|
|
33
|
+
* `Decision: adapter-credential-rejected` and surface an operator ROTATION
|
|
34
|
+
* task ("rotate / re-generate this credential"). Pipeline continues with the
|
|
35
|
+
* remaining valid adapters (AC #4).
|
|
36
|
+
*/
|
|
37
|
+
export declare class AdapterCredentialRejected extends Error {
|
|
38
|
+
readonly source: SignalSourceName;
|
|
39
|
+
constructor(source: SignalSourceName, message?: string);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* RFC-0030 OQ-13.1 v0.3 re-walkthrough: refuse OAuth-required adapters at
|
|
43
|
+
* registration. Phase 1 ships ENV-VAR-ONLY adapters; OAuth-required adapters
|
|
44
|
+
* (full Salesforce / HubSpot integrations, Zendesk-with-OAuth-scopes) wait
|
|
45
|
+
* for the future credential-management RFC. Adapters that declare
|
|
46
|
+
* `requiresOAuth = true` cannot register; the registry returns a Decision
|
|
47
|
+
* pointing the operator at the pending RFC.
|
|
48
|
+
*/
|
|
49
|
+
export declare class AdapterRequiresCredentialMgmtRfc extends Error {
|
|
50
|
+
readonly source: SignalSourceName;
|
|
51
|
+
constructor(source: SignalSourceName, message?: string);
|
|
52
|
+
}
|
|
53
|
+
export declare class ManualSignalIncomplete extends Error {
|
|
54
|
+
readonly sourceId?: string | undefined;
|
|
55
|
+
readonly source: "signal-source-manual";
|
|
56
|
+
constructor(sourceId?: string | undefined, message?: string);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* RFC-0030 OQ-13.4 v0.3 re-walkthrough: per-operator rate-limit at signal
|
|
60
|
+
* entry. When a manual signal would exceed `manualEntry.dailyCapPerOperator`
|
|
61
|
+
* for the attested operator (in UTC-day buckets), the adapter raises this
|
|
62
|
+
* error. Downstream: emit `Decision: manual-signal-rate-limit-exceeded` and
|
|
63
|
+
* surface an operator BATCH-REVIEW escalation path.
|
|
64
|
+
*/
|
|
65
|
+
export declare class ManualSignalRateLimitExceeded extends Error {
|
|
66
|
+
readonly attestedBy: string;
|
|
67
|
+
readonly dailyCap: number;
|
|
68
|
+
readonly utcDate: string;
|
|
69
|
+
readonly sourceId?: string | undefined;
|
|
70
|
+
readonly source: "signal-source-manual";
|
|
71
|
+
constructor(attestedBy: string, dailyCap: number, utcDate: string, sourceId?: string | undefined, message?: string);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export class UnknownSignalSource extends Error {
|
|
2
|
+
source;
|
|
3
|
+
constructor(source) {
|
|
4
|
+
super(`Unknown signal source adapter: ${source}`);
|
|
5
|
+
this.source = source;
|
|
6
|
+
this.name = 'UnknownSignalSource';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class SignalSourceUnavailable extends Error {
|
|
10
|
+
source;
|
|
11
|
+
constructor(source, message = `Signal source adapter unavailable: ${source}`) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.source = source;
|
|
14
|
+
this.name = 'SignalSourceUnavailable';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class AdapterCredentialInvalid extends Error {
|
|
18
|
+
source;
|
|
19
|
+
constructor(source, message = `Signal source adapter credentials invalid: ${source}`) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.source = source;
|
|
22
|
+
this.name = 'AdapterCredentialInvalid';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* RFC-0030 OQ-13.1 v0.3 re-walkthrough: distinct from `AdapterCredentialInvalid`.
|
|
27
|
+
*
|
|
28
|
+
* Raised when an adapter probes its environment for the required credential
|
|
29
|
+
* env var (e.g. `SIGNAL_ZENDESK_PAT`) and the var is missing or empty.
|
|
30
|
+
* Downstream: emit `Decision: adapter-credential-not-configured` and surface
|
|
31
|
+
* an operator SETUP task ("create + set this env var"). Pipeline continues
|
|
32
|
+
* with the remaining valid adapters (AC #4).
|
|
33
|
+
*/
|
|
34
|
+
export class AdapterCredentialNotConfigured extends Error {
|
|
35
|
+
source;
|
|
36
|
+
envVarName;
|
|
37
|
+
constructor(source, envVarName, message = `Signal source adapter credential not configured: ${source} (missing env var ${envVarName})`) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.source = source;
|
|
40
|
+
this.envVarName = envVarName;
|
|
41
|
+
this.name = 'AdapterCredentialNotConfigured';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* RFC-0030 OQ-13.1 v0.3 re-walkthrough: distinct from `AdapterCredentialInvalid`.
|
|
46
|
+
*
|
|
47
|
+
* Raised when an adapter has the credential env var present BUT the auth call
|
|
48
|
+
* against the upstream service is rejected (401 / 403). Downstream: emit
|
|
49
|
+
* `Decision: adapter-credential-rejected` and surface an operator ROTATION
|
|
50
|
+
* task ("rotate / re-generate this credential"). Pipeline continues with the
|
|
51
|
+
* remaining valid adapters (AC #4).
|
|
52
|
+
*/
|
|
53
|
+
export class AdapterCredentialRejected extends Error {
|
|
54
|
+
source;
|
|
55
|
+
constructor(source, message = `Signal source adapter credentials rejected by upstream: ${source}`) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.source = source;
|
|
58
|
+
this.name = 'AdapterCredentialRejected';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* RFC-0030 OQ-13.1 v0.3 re-walkthrough: refuse OAuth-required adapters at
|
|
63
|
+
* registration. Phase 1 ships ENV-VAR-ONLY adapters; OAuth-required adapters
|
|
64
|
+
* (full Salesforce / HubSpot integrations, Zendesk-with-OAuth-scopes) wait
|
|
65
|
+
* for the future credential-management RFC. Adapters that declare
|
|
66
|
+
* `requiresOAuth = true` cannot register; the registry returns a Decision
|
|
67
|
+
* pointing the operator at the pending RFC.
|
|
68
|
+
*/
|
|
69
|
+
export class AdapterRequiresCredentialMgmtRfc extends Error {
|
|
70
|
+
source;
|
|
71
|
+
constructor(source, message = `Adapter ${source} requires OAuth credential management; deferred to future RFC`) {
|
|
72
|
+
super(message);
|
|
73
|
+
this.source = source;
|
|
74
|
+
this.name = 'AdapterRequiresCredentialMgmtRfc';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export class ManualSignalIncomplete extends Error {
|
|
78
|
+
sourceId;
|
|
79
|
+
source = 'signal-source-manual';
|
|
80
|
+
constructor(sourceId, message = 'manual signal missing required attestation fields') {
|
|
81
|
+
super(message);
|
|
82
|
+
this.sourceId = sourceId;
|
|
83
|
+
this.name = 'ManualSignalIncomplete';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* RFC-0030 OQ-13.4 v0.3 re-walkthrough: per-operator rate-limit at signal
|
|
88
|
+
* entry. When a manual signal would exceed `manualEntry.dailyCapPerOperator`
|
|
89
|
+
* for the attested operator (in UTC-day buckets), the adapter raises this
|
|
90
|
+
* error. Downstream: emit `Decision: manual-signal-rate-limit-exceeded` and
|
|
91
|
+
* surface an operator BATCH-REVIEW escalation path.
|
|
92
|
+
*/
|
|
93
|
+
export class ManualSignalRateLimitExceeded extends Error {
|
|
94
|
+
attestedBy;
|
|
95
|
+
dailyCap;
|
|
96
|
+
utcDate;
|
|
97
|
+
sourceId;
|
|
98
|
+
source = 'signal-source-manual';
|
|
99
|
+
constructor(attestedBy, dailyCap, utcDate, sourceId, message = `Manual signal rate limit exceeded for ${attestedBy} on ${utcDate} (cap: ${dailyCap}/day)`) {
|
|
100
|
+
super(message);
|
|
101
|
+
this.attestedBy = attestedBy;
|
|
102
|
+
this.dailyCap = dailyCap;
|
|
103
|
+
this.utcDate = utcDate;
|
|
104
|
+
this.sourceId = sourceId;
|
|
105
|
+
this.name = 'ManualSignalRateLimitExceeded';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=errors.js.map
|