@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,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default embedding adapter: openai-text-embedding-3-small per RFC-0019 §7.
|
|
3
|
+
*
|
|
4
|
+
* Model: text-embedding-3-small (OpenAI, snapshot 2024-01-25)
|
|
5
|
+
* Dimensions: 1536
|
|
6
|
+
* Max input: 8191 tokens
|
|
7
|
+
* Batch: up to 2048 inputs per call
|
|
8
|
+
* Billing: pay-per-token at ~$0.02 / 1M tokens
|
|
9
|
+
*
|
|
10
|
+
* Why text-embedding-3-small over -large:
|
|
11
|
+
* At $0.02/1M tokens, a 10K-token corpus re-embed costs ~$0.0002. The -large
|
|
12
|
+
* variant is 6.5x more expensive for marginal quality improvement on the
|
|
13
|
+
* short-text drift detection use case (RFC-0009 OQ-6). Adopters with
|
|
14
|
+
* quality-sensitive use cases MAY register the -large variant.
|
|
15
|
+
*
|
|
16
|
+
* Why snapshot 2024-01-25:
|
|
17
|
+
* Most recent stable snapshot as of RFC-0019 authoring. Pinning the snapshot
|
|
18
|
+
* date makes adapter upgrades a code change (visible in PR review) rather
|
|
19
|
+
* than a silent provider-side rollout. OpenAI has silently changed
|
|
20
|
+
* text-embedding-ada-002 behavior in the past — explicit pinning prevents that.
|
|
21
|
+
*/
|
|
22
|
+
import { createHash } from 'node:crypto';
|
|
23
|
+
import { EmbeddingProviderError, EmbeddingDimensionMismatch } from '../errors.js';
|
|
24
|
+
/** Cost rate for text-embedding-3-small as of 2024-01-25. */
|
|
25
|
+
const COST_PER_TOKEN_USD = 0.02 / 1_000_000; // $0.02 per 1M tokens
|
|
26
|
+
/** Maximum inputs per batch call (OpenAI API limit). */
|
|
27
|
+
const MAX_BATCH_SIZE = 2048;
|
|
28
|
+
export class OpenAITextEmbedding3Small {
|
|
29
|
+
name = 'openai-text-embedding-3-small';
|
|
30
|
+
modelId = 'text-embedding-3-small';
|
|
31
|
+
modelVersion = '2024-01-25';
|
|
32
|
+
dimensions = 1536;
|
|
33
|
+
capabilities = {
|
|
34
|
+
dimensions: 1536,
|
|
35
|
+
maxInputTokens: 8191,
|
|
36
|
+
supportsBatching: true,
|
|
37
|
+
selfHosted: false,
|
|
38
|
+
billingModel: 'pay-per-token',
|
|
39
|
+
approxCostPer1MTokens: 0.02,
|
|
40
|
+
};
|
|
41
|
+
requires = {
|
|
42
|
+
envVar: 'OPENAI_API_KEY',
|
|
43
|
+
};
|
|
44
|
+
/** Optional cost-tracking callback. Set by the orchestrator after adapter instantiation. */
|
|
45
|
+
costCallback;
|
|
46
|
+
constructor(costCallback) {
|
|
47
|
+
this.costCallback = costCallback;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Wire a cost-tracking callback after construction.
|
|
51
|
+
* Called by the orchestrator when it has a CostTracker available.
|
|
52
|
+
*/
|
|
53
|
+
setCostCallback(callback) {
|
|
54
|
+
this.costCallback = callback;
|
|
55
|
+
}
|
|
56
|
+
async isAvailable() {
|
|
57
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
58
|
+
return {
|
|
59
|
+
available: false,
|
|
60
|
+
reason: 'env-var-missing',
|
|
61
|
+
detail: 'OPENAI_API_KEY not set; openai-text-embedding-3-small requires it.',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return { available: true };
|
|
65
|
+
}
|
|
66
|
+
async getAccountId() {
|
|
67
|
+
const key = process.env.OPENAI_API_KEY;
|
|
68
|
+
if (!key)
|
|
69
|
+
return null;
|
|
70
|
+
// One-way derivation: SHA-256 of '<adapter-name>:<api-key>'.
|
|
71
|
+
// MUST NOT leak the credential.
|
|
72
|
+
return createHash('sha256').update(`${this.name}:${key}`).digest('hex');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Embed a single text string.
|
|
76
|
+
*
|
|
77
|
+
* @param text - Source text. MUST be non-empty.
|
|
78
|
+
* @param consumerLabel - Cost attribution label (default: 'unspecified').
|
|
79
|
+
* Examples: 'rfc-0009-tessellation-drift', 'rfc-0008-ppa-similarity'.
|
|
80
|
+
*/
|
|
81
|
+
async embed(text, consumerLabel = 'unspecified') {
|
|
82
|
+
if (!text || text.trim().length === 0) {
|
|
83
|
+
throw new EmbeddingProviderError(this.name, 'embed(): empty input rejected — pass non-empty text.');
|
|
84
|
+
}
|
|
85
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
86
|
+
if (!apiKey) {
|
|
87
|
+
throw new EmbeddingProviderError(this.name, 'OPENAI_API_KEY is not set. Call isAvailable() before embed().');
|
|
88
|
+
}
|
|
89
|
+
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
headers: {
|
|
92
|
+
Authorization: `Bearer ${apiKey}`,
|
|
93
|
+
'Content-Type': 'application/json',
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify({
|
|
96
|
+
model: this.modelId,
|
|
97
|
+
input: text,
|
|
98
|
+
encoding_format: 'float',
|
|
99
|
+
}),
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
const body = await response.text().catch(() => '(unreadable)');
|
|
103
|
+
throw new EmbeddingProviderError(this.name, `OpenAI /v1/embeddings returned HTTP ${response.status}: ${body}`);
|
|
104
|
+
}
|
|
105
|
+
const data = (await response.json());
|
|
106
|
+
const vector = data.data[0]?.embedding;
|
|
107
|
+
if (!vector) {
|
|
108
|
+
throw new EmbeddingProviderError(this.name, 'OpenAI /v1/embeddings response contained no embedding in data[0].');
|
|
109
|
+
}
|
|
110
|
+
if (vector.length !== this.dimensions) {
|
|
111
|
+
throw new EmbeddingDimensionMismatch(this.name, this.dimensions, vector.length);
|
|
112
|
+
}
|
|
113
|
+
await this._recordCost(data.usage.total_tokens, consumerLabel);
|
|
114
|
+
return vector;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Embed a batch of texts.
|
|
118
|
+
* OpenAI accepts up to 2048 inputs per call; this method chunks above that.
|
|
119
|
+
* Input order is preserved in the returned array.
|
|
120
|
+
*
|
|
121
|
+
* @param texts - Array of source texts. Each MUST be non-empty.
|
|
122
|
+
* @param consumerLabel - Cost attribution label (applies to all texts in batch).
|
|
123
|
+
*/
|
|
124
|
+
async embedBatch(texts, consumerLabel = 'unspecified') {
|
|
125
|
+
if (texts.length === 0) {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
for (const t of texts) {
|
|
129
|
+
if (!t || t.trim().length === 0) {
|
|
130
|
+
throw new EmbeddingProviderError(this.name, 'embedBatch(): empty string in input array rejected — all texts must be non-empty.');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
134
|
+
if (!apiKey) {
|
|
135
|
+
throw new EmbeddingProviderError(this.name, 'OPENAI_API_KEY is not set. Call isAvailable() before embedBatch().');
|
|
136
|
+
}
|
|
137
|
+
const results = [];
|
|
138
|
+
// Chunk into MAX_BATCH_SIZE slices to respect the OpenAI API limit.
|
|
139
|
+
for (let i = 0; i < texts.length; i += MAX_BATCH_SIZE) {
|
|
140
|
+
const chunk = texts.slice(i, i + MAX_BATCH_SIZE);
|
|
141
|
+
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
142
|
+
method: 'POST',
|
|
143
|
+
headers: {
|
|
144
|
+
Authorization: `Bearer ${apiKey}`,
|
|
145
|
+
'Content-Type': 'application/json',
|
|
146
|
+
},
|
|
147
|
+
body: JSON.stringify({
|
|
148
|
+
model: this.modelId,
|
|
149
|
+
input: chunk,
|
|
150
|
+
encoding_format: 'float',
|
|
151
|
+
}),
|
|
152
|
+
});
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
const body = await response.text().catch(() => '(unreadable)');
|
|
155
|
+
throw new EmbeddingProviderError(this.name, `OpenAI /v1/embeddings returned HTTP ${response.status} on batch chunk [${i}, ${i + chunk.length}): ${body}`);
|
|
156
|
+
}
|
|
157
|
+
const data = (await response.json());
|
|
158
|
+
// OpenAI returns data sorted by index — preserve input order.
|
|
159
|
+
const sorted = [...data.data].sort((a, b) => a.index - b.index);
|
|
160
|
+
for (const item of sorted) {
|
|
161
|
+
if (item.embedding.length !== this.dimensions) {
|
|
162
|
+
throw new EmbeddingDimensionMismatch(this.name, this.dimensions, item.embedding.length);
|
|
163
|
+
}
|
|
164
|
+
results.push(item.embedding);
|
|
165
|
+
}
|
|
166
|
+
await this._recordCost(data.usage.total_tokens, consumerLabel);
|
|
167
|
+
}
|
|
168
|
+
return results;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Record a cost event via the cost callback.
|
|
172
|
+
* No-op when no callback is wired (e.g., in unit tests without a CostTracker).
|
|
173
|
+
*/
|
|
174
|
+
async _recordCost(tokens, consumerLabel) {
|
|
175
|
+
if (!this.costCallback)
|
|
176
|
+
return;
|
|
177
|
+
const accountId = await this.getAccountId();
|
|
178
|
+
const costRecord = {
|
|
179
|
+
provider: this.name,
|
|
180
|
+
modelVersion: this.modelVersion,
|
|
181
|
+
accountId,
|
|
182
|
+
consumerLabel,
|
|
183
|
+
tokens,
|
|
184
|
+
costUsd: tokens * COST_PER_TOKEN_USD,
|
|
185
|
+
billingModel: 'pay-per-token',
|
|
186
|
+
};
|
|
187
|
+
this.costCallback(costRecord);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=openai-text-embedding-3-small.js.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec-level wiring for the `Eτ_tessellation_drift` rule consumer per
|
|
3
|
+
* RFC-0009 Phase 4.2 / RFC-0019 Phase 4 (AISDLC-340).
|
|
4
|
+
*
|
|
5
|
+
* Runtime usage activates when RFC-0009 Phase 4.2 ships (AISDLC-317). The
|
|
6
|
+
* code here is the load-bearing API stub the runtime hooks call:
|
|
7
|
+
*
|
|
8
|
+
* - `TESSELLATION_DRIFT_CONSUMER_LABEL` is the canonical `consumerLabel`
|
|
9
|
+
* passed to `adapter.embed()` so cost-tracker records the
|
|
10
|
+
* drift-attribution dimension per OQ-6 re-walkthrough.
|
|
11
|
+
*
|
|
12
|
+
* - `TESSELLATION_DRIFT_STALE_VECTOR_POLICY` is the API-site override
|
|
13
|
+
* per OQ-2 re-walkthrough: drift reads historical trajectory across
|
|
14
|
+
* successive document revisions; lazy-re-embed is actively destructive
|
|
15
|
+
* of that signal (silently overwrites old vectors → loses time-series
|
|
16
|
+
* fidelity). The consumer pins `'fail-loud'` regardless of org default
|
|
17
|
+
* to preserve historical-trajectory fidelity.
|
|
18
|
+
*
|
|
19
|
+
* - `embedDriftSignal()` is the consumer-facing helper that wraps the
|
|
20
|
+
* adapter's embed() call with the consumer label baked in. RFC-0009's
|
|
21
|
+
* drift-computation pipeline calls THIS function, never adapter.embed()
|
|
22
|
+
* directly, so the consumerLabel is impossible to forget at the call site.
|
|
23
|
+
*
|
|
24
|
+
* Tests: `tessellation-drift.test.ts`
|
|
25
|
+
*/
|
|
26
|
+
import type { EmbeddingAdapter } from '../types.js';
|
|
27
|
+
import type { EmbeddingStaleVectorPolicy } from '../storage/types.js';
|
|
28
|
+
/**
|
|
29
|
+
* Canonical consumer label for cost-tracker attribution. Per OQ-6
|
|
30
|
+
* re-walkthrough, callers pass this string so cost-tracker records the
|
|
31
|
+
* `(provider, modelVersion, accountId, consumerLabel='rfc-0009-tessellation-drift')`
|
|
32
|
+
* dimension and finance can answer "drift cost vs PPA cost" without
|
|
33
|
+
* re-instrumentation.
|
|
34
|
+
*/
|
|
35
|
+
export declare const TESSELLATION_DRIFT_CONSUMER_LABEL = "rfc-0009-tessellation-drift";
|
|
36
|
+
/**
|
|
37
|
+
* API-site stale-vector policy override per OQ-2 re-walkthrough. The drift
|
|
38
|
+
* consumer pins `fail-loud` regardless of org default — silent re-embedding
|
|
39
|
+
* destroys the historical-trajectory signal the rule is measuring.
|
|
40
|
+
*
|
|
41
|
+
* Treat this constant as load-bearing: every drift-signal read site MUST
|
|
42
|
+
* read THIS value, not the org default, when deciding policy.
|
|
43
|
+
*/
|
|
44
|
+
export declare const TESSELLATION_DRIFT_STALE_VECTOR_POLICY: EmbeddingStaleVectorPolicy;
|
|
45
|
+
/**
|
|
46
|
+
* Embed a single source text for the Eτ_tessellation_drift rule.
|
|
47
|
+
*
|
|
48
|
+
* RFC-0009's drift-computation pipeline (AISDLC-317, pending) calls THIS
|
|
49
|
+
* helper rather than `adapter.embed()` directly. The helper bakes in the
|
|
50
|
+
* consumer label so cost attribution is correct by construction.
|
|
51
|
+
*
|
|
52
|
+
* The adapter is passed in (not resolved here) because the orchestrator
|
|
53
|
+
* may have a fallback chain — the caller (pipeline runtime) decides which
|
|
54
|
+
* adapter to use; the consumer decides the LABEL and POLICY.
|
|
55
|
+
*
|
|
56
|
+
* @param adapter - Resolved embedding adapter (from `loadEmbeddingFromPipelineSpec`).
|
|
57
|
+
* @param text - Source text to embed (a tessellation shard, typically).
|
|
58
|
+
* @returns - Vector emitted by the adapter, length === adapter.dimensions.
|
|
59
|
+
*/
|
|
60
|
+
export declare function embedDriftSignal(adapter: EmbeddingAdapter, text: string): Promise<number[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Consumer descriptor exported for cross-cutting docs/registry purposes.
|
|
63
|
+
* Other consumers (PPA similarity, classifier embeddings, etc.) SHOULD
|
|
64
|
+
* export a similar descriptor so a future `cli-embedding-consumers list`
|
|
65
|
+
* can enumerate every consumer + its pinned policy.
|
|
66
|
+
*/
|
|
67
|
+
export declare const TESSELLATION_DRIFT_CONSUMER: {
|
|
68
|
+
readonly label: "rfc-0009-tessellation-drift";
|
|
69
|
+
readonly staleVectorPolicy: "fail-loud";
|
|
70
|
+
readonly rationale: string;
|
|
71
|
+
readonly rfc: "RFC-0009";
|
|
72
|
+
readonly task: "AISDLC-340";
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=tessellation-drift.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec-level wiring for the `Eτ_tessellation_drift` rule consumer per
|
|
3
|
+
* RFC-0009 Phase 4.2 / RFC-0019 Phase 4 (AISDLC-340).
|
|
4
|
+
*
|
|
5
|
+
* Runtime usage activates when RFC-0009 Phase 4.2 ships (AISDLC-317). The
|
|
6
|
+
* code here is the load-bearing API stub the runtime hooks call:
|
|
7
|
+
*
|
|
8
|
+
* - `TESSELLATION_DRIFT_CONSUMER_LABEL` is the canonical `consumerLabel`
|
|
9
|
+
* passed to `adapter.embed()` so cost-tracker records the
|
|
10
|
+
* drift-attribution dimension per OQ-6 re-walkthrough.
|
|
11
|
+
*
|
|
12
|
+
* - `TESSELLATION_DRIFT_STALE_VECTOR_POLICY` is the API-site override
|
|
13
|
+
* per OQ-2 re-walkthrough: drift reads historical trajectory across
|
|
14
|
+
* successive document revisions; lazy-re-embed is actively destructive
|
|
15
|
+
* of that signal (silently overwrites old vectors → loses time-series
|
|
16
|
+
* fidelity). The consumer pins `'fail-loud'` regardless of org default
|
|
17
|
+
* to preserve historical-trajectory fidelity.
|
|
18
|
+
*
|
|
19
|
+
* - `embedDriftSignal()` is the consumer-facing helper that wraps the
|
|
20
|
+
* adapter's embed() call with the consumer label baked in. RFC-0009's
|
|
21
|
+
* drift-computation pipeline calls THIS function, never adapter.embed()
|
|
22
|
+
* directly, so the consumerLabel is impossible to forget at the call site.
|
|
23
|
+
*
|
|
24
|
+
* Tests: `tessellation-drift.test.ts`
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Canonical consumer label for cost-tracker attribution. Per OQ-6
|
|
28
|
+
* re-walkthrough, callers pass this string so cost-tracker records the
|
|
29
|
+
* `(provider, modelVersion, accountId, consumerLabel='rfc-0009-tessellation-drift')`
|
|
30
|
+
* dimension and finance can answer "drift cost vs PPA cost" without
|
|
31
|
+
* re-instrumentation.
|
|
32
|
+
*/
|
|
33
|
+
export const TESSELLATION_DRIFT_CONSUMER_LABEL = 'rfc-0009-tessellation-drift';
|
|
34
|
+
/**
|
|
35
|
+
* API-site stale-vector policy override per OQ-2 re-walkthrough. The drift
|
|
36
|
+
* consumer pins `fail-loud` regardless of org default — silent re-embedding
|
|
37
|
+
* destroys the historical-trajectory signal the rule is measuring.
|
|
38
|
+
*
|
|
39
|
+
* Treat this constant as load-bearing: every drift-signal read site MUST
|
|
40
|
+
* read THIS value, not the org default, when deciding policy.
|
|
41
|
+
*/
|
|
42
|
+
export const TESSELLATION_DRIFT_STALE_VECTOR_POLICY = 'fail-loud';
|
|
43
|
+
/**
|
|
44
|
+
* Embed a single source text for the Eτ_tessellation_drift rule.
|
|
45
|
+
*
|
|
46
|
+
* RFC-0009's drift-computation pipeline (AISDLC-317, pending) calls THIS
|
|
47
|
+
* helper rather than `adapter.embed()` directly. The helper bakes in the
|
|
48
|
+
* consumer label so cost attribution is correct by construction.
|
|
49
|
+
*
|
|
50
|
+
* The adapter is passed in (not resolved here) because the orchestrator
|
|
51
|
+
* may have a fallback chain — the caller (pipeline runtime) decides which
|
|
52
|
+
* adapter to use; the consumer decides the LABEL and POLICY.
|
|
53
|
+
*
|
|
54
|
+
* @param adapter - Resolved embedding adapter (from `loadEmbeddingFromPipelineSpec`).
|
|
55
|
+
* @param text - Source text to embed (a tessellation shard, typically).
|
|
56
|
+
* @returns - Vector emitted by the adapter, length === adapter.dimensions.
|
|
57
|
+
*/
|
|
58
|
+
export async function embedDriftSignal(adapter, text) {
|
|
59
|
+
return adapter.embed(text, TESSELLATION_DRIFT_CONSUMER_LABEL);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Consumer descriptor exported for cross-cutting docs/registry purposes.
|
|
63
|
+
* Other consumers (PPA similarity, classifier embeddings, etc.) SHOULD
|
|
64
|
+
* export a similar descriptor so a future `cli-embedding-consumers list`
|
|
65
|
+
* can enumerate every consumer + its pinned policy.
|
|
66
|
+
*/
|
|
67
|
+
export const TESSELLATION_DRIFT_CONSUMER = {
|
|
68
|
+
label: TESSELLATION_DRIFT_CONSUMER_LABEL,
|
|
69
|
+
staleVectorPolicy: TESSELLATION_DRIFT_STALE_VECTOR_POLICY,
|
|
70
|
+
rationale: 'Eτ drift reads historical trajectory across successive document revisions; ' +
|
|
71
|
+
'lazy-re-embed silently overwrites old vectors and destroys the time-series signal. ' +
|
|
72
|
+
'Pin fail-loud at the API site (RFC-0019 OQ-2 re-walkthrough).',
|
|
73
|
+
rfc: 'RFC-0009',
|
|
74
|
+
task: 'AISDLC-340',
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=tessellation-drift.js.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-provider compatibility per RFC-0019 §9.3 + OQ-3 re-walkthrough split.
|
|
3
|
+
*
|
|
4
|
+
* The OQ-3 re-walkthrough resolution surfaces a critical distinction that
|
|
5
|
+
* v0.2 missed: cross-PROVIDER comparisons (openai vs cohere) are NEVER valid
|
|
6
|
+
* because the math is genuinely undefined — vectors in different embedding
|
|
7
|
+
* spaces have no metrically-valid distance. cross-VERSION-within-provider
|
|
8
|
+
* comparisons (3-small@2024-01-25 vs 3-small@2025-01-25) DELEGATE to the
|
|
9
|
+
* stale-vector policy because closely-correlated embedding spaces support
|
|
10
|
+
* lazy re-embed.
|
|
11
|
+
*
|
|
12
|
+
* Policy mapping:
|
|
13
|
+
*
|
|
14
|
+
* stored.provider != current.provider → ALWAYS REFUSE + emit
|
|
15
|
+
* `Decision: cross-provider-comparison-attempted`
|
|
16
|
+
* → auto-action: emit cli-embedding-bump
|
|
17
|
+
* migration task
|
|
18
|
+
*
|
|
19
|
+
* stored.provider == current.provider
|
|
20
|
+
* AND
|
|
21
|
+
* stored.modelVersion != current.modelVersion → DELEGATE to staleVectorPolicy
|
|
22
|
+
*
|
|
23
|
+
* stored matches current entirely → COMPATIBLE (no policy)
|
|
24
|
+
*
|
|
25
|
+
* This resolves v0.2's logical conflict where both cases were lumped under
|
|
26
|
+
* "strict no-op" contradicting OQ-2's lazy-re-embed default.
|
|
27
|
+
*
|
|
28
|
+
* @module embedding/cross-provider
|
|
29
|
+
*/
|
|
30
|
+
import { EmbeddingError } from './errors.js';
|
|
31
|
+
/**
|
|
32
|
+
* The three possible outcomes of a provider-compatibility check.
|
|
33
|
+
*
|
|
34
|
+
* - `compatible` — same provider AND same model version. Caller
|
|
35
|
+
* may compare vectors directly.
|
|
36
|
+
* - `cross-version` — same provider, different model version.
|
|
37
|
+
* Caller MUST consult the stale-vector policy.
|
|
38
|
+
* - `cross-provider` — different provider. Caller MUST refuse the
|
|
39
|
+
* comparison and emit a catalog Decision +
|
|
40
|
+
* migration task.
|
|
41
|
+
*/
|
|
42
|
+
export type ProviderCompatibility = 'compatible' | 'cross-version' | 'cross-provider';
|
|
43
|
+
/**
|
|
44
|
+
* Compare a stored entry's provenance against the currently configured adapter.
|
|
45
|
+
* Pure function — no side effects, no event emission. Callers wrap the result
|
|
46
|
+
* with their own catalog logging.
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkProviderCompatibility(storedProvider: string, storedModelVersion: string, currentProvider: string, currentModelVersion: string): ProviderCompatibility;
|
|
49
|
+
/**
|
|
50
|
+
* Thrown when a cross-PROVIDER comparison is attempted (e.g., openai vs cohere).
|
|
51
|
+
* Always fatal — the math is undefined and there is no auto-migration path.
|
|
52
|
+
* Operators must run cli-embedding-bump to re-embed the entire corpus on the
|
|
53
|
+
* new provider.
|
|
54
|
+
*/
|
|
55
|
+
export declare class CrossProviderComparisonError extends EmbeddingError {
|
|
56
|
+
readonly storedProvider: string;
|
|
57
|
+
readonly currentProvider: string;
|
|
58
|
+
readonly textHash?: string | undefined;
|
|
59
|
+
constructor(storedProvider: string, currentProvider: string, textHash?: string | undefined);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build the catalog Decision payload for a cross-provider attempt per
|
|
63
|
+
* RFC-0019 §9.3 OQ-3 re-walkthrough. The caller forwards this to
|
|
64
|
+
* `appendDecisionEvent()` so a `Decision: cross-provider-comparison-attempted`
|
|
65
|
+
* lands in the catalog and the operator gets a migration task.
|
|
66
|
+
*/
|
|
67
|
+
export interface CrossProviderDecisionPayload {
|
|
68
|
+
/** Stable summary used as the catalog Decision summary. */
|
|
69
|
+
summary: string;
|
|
70
|
+
/** Suggested migration command. */
|
|
71
|
+
migrationCommand: string;
|
|
72
|
+
/** Severity — always high for cross-provider. */
|
|
73
|
+
severity: 'high';
|
|
74
|
+
/** Auto-action — always emit a cli-embedding-bump migration task. */
|
|
75
|
+
autoAction: 'emit-migration-task';
|
|
76
|
+
}
|
|
77
|
+
export declare function buildCrossProviderDecisionPayload(storedProvider: string, currentProvider: string): CrossProviderDecisionPayload;
|
|
78
|
+
//# sourceMappingURL=cross-provider.d.ts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-provider compatibility per RFC-0019 §9.3 + OQ-3 re-walkthrough split.
|
|
3
|
+
*
|
|
4
|
+
* The OQ-3 re-walkthrough resolution surfaces a critical distinction that
|
|
5
|
+
* v0.2 missed: cross-PROVIDER comparisons (openai vs cohere) are NEVER valid
|
|
6
|
+
* because the math is genuinely undefined — vectors in different embedding
|
|
7
|
+
* spaces have no metrically-valid distance. cross-VERSION-within-provider
|
|
8
|
+
* comparisons (3-small@2024-01-25 vs 3-small@2025-01-25) DELEGATE to the
|
|
9
|
+
* stale-vector policy because closely-correlated embedding spaces support
|
|
10
|
+
* lazy re-embed.
|
|
11
|
+
*
|
|
12
|
+
* Policy mapping:
|
|
13
|
+
*
|
|
14
|
+
* stored.provider != current.provider → ALWAYS REFUSE + emit
|
|
15
|
+
* `Decision: cross-provider-comparison-attempted`
|
|
16
|
+
* → auto-action: emit cli-embedding-bump
|
|
17
|
+
* migration task
|
|
18
|
+
*
|
|
19
|
+
* stored.provider == current.provider
|
|
20
|
+
* AND
|
|
21
|
+
* stored.modelVersion != current.modelVersion → DELEGATE to staleVectorPolicy
|
|
22
|
+
*
|
|
23
|
+
* stored matches current entirely → COMPATIBLE (no policy)
|
|
24
|
+
*
|
|
25
|
+
* This resolves v0.2's logical conflict where both cases were lumped under
|
|
26
|
+
* "strict no-op" contradicting OQ-2's lazy-re-embed default.
|
|
27
|
+
*
|
|
28
|
+
* @module embedding/cross-provider
|
|
29
|
+
*/
|
|
30
|
+
import { EmbeddingError } from './errors.js';
|
|
31
|
+
/**
|
|
32
|
+
* Compare a stored entry's provenance against the currently configured adapter.
|
|
33
|
+
* Pure function — no side effects, no event emission. Callers wrap the result
|
|
34
|
+
* with their own catalog logging.
|
|
35
|
+
*/
|
|
36
|
+
export function checkProviderCompatibility(storedProvider, storedModelVersion, currentProvider, currentModelVersion) {
|
|
37
|
+
if (storedProvider !== currentProvider) {
|
|
38
|
+
return 'cross-provider';
|
|
39
|
+
}
|
|
40
|
+
if (storedModelVersion !== currentModelVersion) {
|
|
41
|
+
return 'cross-version';
|
|
42
|
+
}
|
|
43
|
+
return 'compatible';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Thrown when a cross-PROVIDER comparison is attempted (e.g., openai vs cohere).
|
|
47
|
+
* Always fatal — the math is undefined and there is no auto-migration path.
|
|
48
|
+
* Operators must run cli-embedding-bump to re-embed the entire corpus on the
|
|
49
|
+
* new provider.
|
|
50
|
+
*/
|
|
51
|
+
export class CrossProviderComparisonError extends EmbeddingError {
|
|
52
|
+
storedProvider;
|
|
53
|
+
currentProvider;
|
|
54
|
+
textHash;
|
|
55
|
+
constructor(storedProvider, currentProvider, textHash) {
|
|
56
|
+
super(`Cross-provider comparison refused: stored vector is from '${storedProvider}', ` +
|
|
57
|
+
`current adapter is '${currentProvider}'. Embedding spaces are not metrically ` +
|
|
58
|
+
`comparable across providers. Migrate via: cli-embedding-bump --to ${currentProvider}` +
|
|
59
|
+
(textHash ? ` (offending textHash: ${textHash})` : ''));
|
|
60
|
+
this.storedProvider = storedProvider;
|
|
61
|
+
this.currentProvider = currentProvider;
|
|
62
|
+
this.textHash = textHash;
|
|
63
|
+
this.name = 'CrossProviderComparisonError';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function buildCrossProviderDecisionPayload(storedProvider, currentProvider) {
|
|
67
|
+
return {
|
|
68
|
+
summary: `Cross-provider comparison attempted: '${storedProvider}' vs '${currentProvider}'. ` +
|
|
69
|
+
`Refused (math undefined). Run cli-embedding-bump to migrate.`,
|
|
70
|
+
migrationCommand: `cli-embedding-bump --to ${currentProvider}`,
|
|
71
|
+
severity: 'high',
|
|
72
|
+
autoAction: 'emit-migration-task',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=cross-provider.js.map
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deprecation lifecycle per RFC-0019 §9.1 + OQ-4 re-walkthrough.
|
|
3
|
+
*
|
|
4
|
+
* Three-layer grace-period precedence (highest → lowest):
|
|
5
|
+
* 1. per-org `gracePeriodDays` from `.ai-sdlc/embedding-config.yaml`
|
|
6
|
+
* 2. adapter-declared `defaultGracePeriodDays` (capability matrix)
|
|
7
|
+
* 3. framework default — 90 days
|
|
8
|
+
*
|
|
9
|
+
* Catalog dedup via per-Decision-key counter prevents Decision flood under
|
|
10
|
+
* orchestrator-driven loads: emit `Decision: embedding-provider-deprecated`
|
|
11
|
+
* at MILESTONES (89/60/30/7/1 days before deprecatedAt), NOT per-load. The
|
|
12
|
+
* dedup key is `embedding-provider-deprecated:<adapter-name>:<deprecatedAt>`.
|
|
13
|
+
*
|
|
14
|
+
* Lifecycle phases:
|
|
15
|
+
* - Pre-warning : today < (deprecatedAt - gracePeriod) → silent
|
|
16
|
+
* - Warning : today ∈ [deprecatedAt - gracePeriod, deprecatedAt) → milestone events
|
|
17
|
+
* - Deprecated : today ∈ [deprecatedAt, removedAt) → continued warnings; HIGH in strict mode
|
|
18
|
+
* - Removed : today ≥ removedAt → emit `Decision: embedding-provider-removed`
|
|
19
|
+
* + auto-action: emit cli-embedding-bump migration task.
|
|
20
|
+
* Pipeline NEVER halts — downstream consumers degrade.
|
|
21
|
+
*
|
|
22
|
+
* @module embedding/deprecation
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Framework default grace-period length per OQ-4 re-walkthrough.
|
|
26
|
+
* Conservative within OpenAI's typical 12-15 month deprecation window.
|
|
27
|
+
*/
|
|
28
|
+
export declare const FRAMEWORK_DEFAULT_GRACE_PERIOD_DAYS = 90;
|
|
29
|
+
/**
|
|
30
|
+
* Days-before-deprecatedAt at which a catalog Decision is emitted.
|
|
31
|
+
* Dedup counter ensures one event per milestone per (adapter, deprecatedAt) tuple.
|
|
32
|
+
*
|
|
33
|
+
* Sorted DESCENDING — when computing "next-due milestone" we walk from
|
|
34
|
+
* largest to smallest and pick the first one we have crossed.
|
|
35
|
+
*/
|
|
36
|
+
export declare const DEPRECATION_MILESTONE_DAYS: ReadonlyArray<number>;
|
|
37
|
+
/**
|
|
38
|
+
* Inputs to the deprecation lifecycle evaluator.
|
|
39
|
+
* `today` defaults to the current date; callers pass an explicit Date in tests.
|
|
40
|
+
*/
|
|
41
|
+
export interface DeprecationLifecycleInput {
|
|
42
|
+
/** Canonical adapter name (e.g., 'openai-text-embedding-ada-002'). */
|
|
43
|
+
adapterName: string;
|
|
44
|
+
/** ISO date when the deprecation warning period starts (adapter.deprecatedAt). */
|
|
45
|
+
deprecatedAt?: string;
|
|
46
|
+
/** ISO date when the adapter is removed (adapter.removedAt). */
|
|
47
|
+
removedAt?: string;
|
|
48
|
+
/** Canonical replacement alias for migration messaging. */
|
|
49
|
+
replacementAlias?: string;
|
|
50
|
+
/** Adapter-declared default grace period override. */
|
|
51
|
+
adapterDefaultGracePeriodDays?: number;
|
|
52
|
+
/** Per-org override from embedding-config.yaml. */
|
|
53
|
+
orgGracePeriodDays?: number;
|
|
54
|
+
/** Whether the operator runs in strict mode (escalate severity at deprecatedAt). */
|
|
55
|
+
strictModeAtDeprecatedAt?: boolean;
|
|
56
|
+
/** Override "today" for deterministic tests. */
|
|
57
|
+
today?: Date;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Lifecycle phase the adapter is currently in.
|
|
61
|
+
*/
|
|
62
|
+
export type DeprecationPhase = 'pre-warning' | 'warning' | 'deprecated' | 'removed' | 'inactive';
|
|
63
|
+
/**
|
|
64
|
+
* One catalog Decision event the caller should append.
|
|
65
|
+
*/
|
|
66
|
+
export interface DeprecationDecisionEvent {
|
|
67
|
+
/** RFC-0035 catalog Decision type. */
|
|
68
|
+
decisionType: 'embedding-provider-deprecated' | 'embedding-provider-removed';
|
|
69
|
+
/** Dedup key — caller MUST refuse duplicate emissions for the same key. */
|
|
70
|
+
dedupKey: string;
|
|
71
|
+
/** Catalog severity. */
|
|
72
|
+
severity: 'info' | 'high';
|
|
73
|
+
/** Human-readable summary used as the Decision summary. */
|
|
74
|
+
summary: string;
|
|
75
|
+
/** Milestone reached, in days-before-deprecatedAt. Null for `removed` events. */
|
|
76
|
+
milestoneDaysBefore: number | null;
|
|
77
|
+
/**
|
|
78
|
+
* Auto-action the orchestrator MUST perform when this event lands.
|
|
79
|
+
* `null` for milestone events that don't auto-trigger anything.
|
|
80
|
+
*/
|
|
81
|
+
autoAction: 'emit-migration-task' | null;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Result of evaluating the deprecation lifecycle for one adapter at one point
|
|
85
|
+
* in time.
|
|
86
|
+
*/
|
|
87
|
+
export interface DeprecationLifecycleResult {
|
|
88
|
+
/** Current phase. */
|
|
89
|
+
phase: DeprecationPhase;
|
|
90
|
+
/** Effective grace period used (after three-layer precedence). */
|
|
91
|
+
effectiveGracePeriodDays: number;
|
|
92
|
+
/** Days from today to deprecatedAt (negative if past). Null when undeclared. */
|
|
93
|
+
daysToDeprecatedAt: number | null;
|
|
94
|
+
/** Days from today to removedAt (negative if past). Null when undeclared. */
|
|
95
|
+
daysToRemovedAt: number | null;
|
|
96
|
+
/**
|
|
97
|
+
* Decision events the caller should emit. May be empty (phase == pre-warning
|
|
98
|
+
* OR no milestone was crossed in the current load).
|
|
99
|
+
*
|
|
100
|
+
* The caller is responsible for catalog dedup — DO NOT emit when the dedup
|
|
101
|
+
* key has already been seen. See {@link DeprecationDecisionEvent.dedupKey}.
|
|
102
|
+
*/
|
|
103
|
+
decisionEvents: DeprecationDecisionEvent[];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the effective grace period using the three-layer precedence chain
|
|
107
|
+
* per OQ-4 re-walkthrough.
|
|
108
|
+
*/
|
|
109
|
+
export declare function resolveGracePeriodDays(orgOverride: number | undefined, adapterDefault: number | undefined): number;
|
|
110
|
+
/**
|
|
111
|
+
* Find the most-recently-crossed milestone at the current moment — i.e., the
|
|
112
|
+
* SMALLEST milestone the caller is at-or-under. Returns `null` when no
|
|
113
|
+
* milestone is due (today is BEFORE the largest milestone OR adapter has no
|
|
114
|
+
* deprecatedAt).
|
|
115
|
+
*
|
|
116
|
+
* "Crossed" = `daysToDeprecatedAt <= milestone`. We want the smallest such
|
|
117
|
+
* milestone so each emission represents a NEW threshold crossed:
|
|
118
|
+
*
|
|
119
|
+
* 90 days out → no milestone due
|
|
120
|
+
* 89 days out → milestone 89 (largest threshold first crossed)
|
|
121
|
+
* 75 days out → milestone 89 (still inside 89 window, 60 not yet crossed)
|
|
122
|
+
* 60 days out → milestone 60 (newly crossed)
|
|
123
|
+
* 50 days out → milestone 60 (still inside 60, 30 not yet crossed)
|
|
124
|
+
* 30 days out → milestone 30
|
|
125
|
+
* ...
|
|
126
|
+
*
|
|
127
|
+
* The dedup counter then collapses repeated emissions at the same milestone
|
|
128
|
+
* to exactly one event per (adapter, deprecatedAt, milestone) tuple.
|
|
129
|
+
*
|
|
130
|
+
* @param daysToDeprecatedAt - Result from `daysBetween(today, deprecatedAt)`.
|
|
131
|
+
* Positive when deprecatedAt is in the future, negative when past.
|
|
132
|
+
*/
|
|
133
|
+
export declare function nextDueMilestone(daysToDeprecatedAt: number): number | null;
|
|
134
|
+
/**
|
|
135
|
+
* Build the catalog dedup key for a deprecation event at a given milestone.
|
|
136
|
+
* Same key across pipeline loads → caller refuses to emit a second time.
|
|
137
|
+
*/
|
|
138
|
+
export declare function buildDedupKey(decisionType: DeprecationDecisionEvent['decisionType'], adapterName: string, deprecatedAt: string | undefined, milestoneDaysBefore: number | null): string;
|
|
139
|
+
/**
|
|
140
|
+
* Evaluate the deprecation lifecycle for one adapter.
|
|
141
|
+
*
|
|
142
|
+
* Returns the phase, resolved grace period, and any catalog Decision events
|
|
143
|
+
* the caller should emit. Pipeline-load NEVER halts on the result; downstream
|
|
144
|
+
* consumers degrade gracefully per the RFC-0035 G0 non-blocking contract.
|
|
145
|
+
*
|
|
146
|
+
* Dedup contract: the returned `decisionEvents` always carry the dedup key.
|
|
147
|
+
* The caller MUST consult its dedup store before appending — re-emitting the
|
|
148
|
+
* same `(adapter, deprecatedAt, milestone)` triple is a bug.
|
|
149
|
+
*/
|
|
150
|
+
export declare function evaluateDeprecationLifecycle(input: DeprecationLifecycleInput): DeprecationLifecycleResult;
|
|
151
|
+
//# sourceMappingURL=deprecation.d.ts.map
|