@ai-sdlc/orchestrator 0.10.0 → 0.14.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/adapters.d.ts +42 -3
- package/dist/adapters.js +133 -3
- package/dist/admission-composite.d.ts +112 -1
- package/dist/admission-composite.js +85 -4
- package/dist/admission-enrichment.d.ts +12 -3
- package/dist/admission-enrichment.js +64 -13
- package/dist/admission-score.d.ts +30 -0
- package/dist/admission-score.js +4 -1
- package/dist/analysis/file-walker.js +5 -0
- 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.js +1 -1
- package/dist/cli/commands/init-features.d.ts +301 -2
- package/dist/cli/commands/init-features.js +647 -7
- package/dist/cli/commands/init-templates.d.ts +198 -1
- package/dist/cli/commands/init-templates.js +943 -1
- package/dist/cli/commands/init.d.ts +45 -0
- package/dist/cli/commands/init.js +147 -5
- 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/cycle-utils.js +14 -1
- package/dist/database/adapters/external.js +5 -1
- 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 +200 -38
- package/dist/fix-review.js +1 -1
- 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/metric-snapshot.d.ts +403 -0
- package/dist/journey/metric-snapshot.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/otel-exporter.js +0 -3
- package/dist/runners/claude-code.js +3 -3
- 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 +173 -13
- package/dist/runtime/attestations.js +265 -43
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/sa-scoring/exemplar-bank.js +3 -1
- 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/shared.d.ts +28 -0
- package/dist/shared.js +37 -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/dist/webhook-manager.js +7 -1
- package/package.json +15 -12
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical `identityClass` taxonomy for Substrate Contract fields.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 of RFC-0028 §7.1 v0.2 resolution. Defines the framework-level
|
|
5
|
+
* taxonomy `core | evolving` together with bucket assignments, a novel-field
|
|
6
|
+
* default helper (conservative `core`), and the type-level tightening-only
|
|
7
|
+
* primitives used by Substrate Contract authors.
|
|
8
|
+
*
|
|
9
|
+
* Harmonizes with the already-shipped `'core' | 'evolving'` discriminant in
|
|
10
|
+
* `orchestrator/src/sa-scoring/layer1-deterministic.ts` — see
|
|
11
|
+
* {@link auditLayer1DeterministicClassifications} for the cross-check and
|
|
12
|
+
* {@link IdentityClassDiscrepancy} for the discrepancy shape filed against the
|
|
13
|
+
* Decision Catalog.
|
|
14
|
+
*
|
|
15
|
+
* @see spec/rfcs/RFC-0028-engineering-axis-substrate-enforcement.md §6, §7.1
|
|
16
|
+
*/
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
import { dirname, join } from 'node:path';
|
|
20
|
+
/** Runtime-enumerable list of every taxonomy bucket. */
|
|
21
|
+
export const IDENTITY_CLASSES = ['core', 'evolving'];
|
|
22
|
+
// ── Bucket assignments (canonical taxonomy, RFC-0028 §7.1) ───────────
|
|
23
|
+
/**
|
|
24
|
+
* Substrate Contract field names that are CANONICAL `core` per RFC-0028 §7.1.
|
|
25
|
+
*
|
|
26
|
+
* Child Soul DIDs CANNOT loosen any value declared on these fields. A pivot
|
|
27
|
+
* rescoring fires whenever any of these fields change.
|
|
28
|
+
*/
|
|
29
|
+
export const CORE_BUCKET = {
|
|
30
|
+
/** Categorical compliance locks — `boolean` locks typed as `true` literal when locked. */
|
|
31
|
+
categoricalComplianceLocks: [
|
|
32
|
+
'requiresTenantPhysicalIsolation',
|
|
33
|
+
'requiresVulnerableAudienceLockout',
|
|
34
|
+
],
|
|
35
|
+
/** Compliance regime declarations — categorical, tightening-only. */
|
|
36
|
+
complianceRegimeDeclarations: ['HIPAA', 'PCI-DSS', 'SOC2', 'FedRAMP', 'GDPR'],
|
|
37
|
+
/** Director / orchestrator agent identifier — changing the director IS a Soul-level event. */
|
|
38
|
+
directorIdentifiers: ['director', 'orchestratorAgentId'],
|
|
39
|
+
/** §6 tightening-only `complianceFloor: inherit` lock. */
|
|
40
|
+
complianceFloorLock: ['complianceFloor'],
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Substrate Contract field names that are CANONICAL `evolving` per RFC-0028 §7.1.
|
|
44
|
+
*
|
|
45
|
+
* Free movement within tightening-only bounds (a `cadence` may shorten but
|
|
46
|
+
* not lengthen past the parent; a similarity threshold may tighten but not
|
|
47
|
+
* loosen). Admission-queue rescoring only — no Soul pivot.
|
|
48
|
+
*/
|
|
49
|
+
export const EVOLVING_BUCKET = {
|
|
50
|
+
/** Operational cadence — observer cooldown / cadence minimum interval. */
|
|
51
|
+
operationalCadence: ['observerCooldownMs', 'cadenceMinIntervalDays'],
|
|
52
|
+
/** Scoring tuning weights — bid diversity weight, recency half-life. */
|
|
53
|
+
scoringTuningWeights: ['bidDiversityWeight', 'recencyHalfLife'],
|
|
54
|
+
/** Similarity thresholds — `clustering.similarityThreshold`. */
|
|
55
|
+
similarityThresholds: ['clustering.similarityThreshold'],
|
|
56
|
+
/** Quota quantities — `tenantQuotaShare`. */
|
|
57
|
+
quotaQuantities: ['tenantQuotaShare'],
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Reverse-lookup table: field name → canonical `IdentityClass`.
|
|
61
|
+
* Built from {@link CORE_BUCKET} + {@link EVOLVING_BUCKET}. Fields not listed
|
|
62
|
+
* here are NOVEL and resolve via {@link defaultIdentityClassForNovelField}.
|
|
63
|
+
*/
|
|
64
|
+
export const CANONICAL_FIELD_CLASSIFICATIONS = Object.freeze({
|
|
65
|
+
...Object.fromEntries(Object.values(CORE_BUCKET)
|
|
66
|
+
.flat()
|
|
67
|
+
.map((name) => [name, 'core'])),
|
|
68
|
+
...Object.fromEntries(Object.values(EVOLVING_BUCKET)
|
|
69
|
+
.flat()
|
|
70
|
+
.map((name) => [name, 'evolving'])),
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the canonical `IdentityClass` for a Substrate Contract field.
|
|
74
|
+
*
|
|
75
|
+
* - Listed in {@link CANONICAL_FIELD_CLASSIFICATIONS} → returns that bucket.
|
|
76
|
+
* - Otherwise NOVEL → returns `'core'` (per RFC-0028 §7.1 v0.2 conservative
|
|
77
|
+
* default; promotion to `evolving` needs an RFC amendment with Design +
|
|
78
|
+
* Engineering sign-off — burden-of-proof is "argue why operational").
|
|
79
|
+
*
|
|
80
|
+
* When defaulting fires AND a `warn` hook is supplied, the hook is invoked
|
|
81
|
+
* synchronously so contract authors get a visible signal that a field has
|
|
82
|
+
* not yet been classified canonically.
|
|
83
|
+
*/
|
|
84
|
+
export function defaultIdentityClassForNovelField(fieldName, options = {}) {
|
|
85
|
+
// Use Object.prototype.hasOwnProperty.call to prevent prototype-pollution
|
|
86
|
+
// lookups — without this guard a field named `toString` or `constructor`
|
|
87
|
+
// would resolve to inherited Object prototype values (a function typed as
|
|
88
|
+
// IdentityClass) instead of defaulting to 'core'.
|
|
89
|
+
const canonical = Object.prototype.hasOwnProperty.call(CANONICAL_FIELD_CLASSIFICATIONS, fieldName)
|
|
90
|
+
? CANONICAL_FIELD_CLASSIFICATIONS[fieldName]
|
|
91
|
+
: undefined;
|
|
92
|
+
if (canonical !== undefined)
|
|
93
|
+
return canonical;
|
|
94
|
+
const defaulted = 'core';
|
|
95
|
+
options.warn?.(fieldName, defaulted);
|
|
96
|
+
return defaulted;
|
|
97
|
+
}
|
|
98
|
+
/** Run-time assertion that a {@link BoundedNumericCap} tightening is valid. */
|
|
99
|
+
export function assertTightenedCap(cap) {
|
|
100
|
+
if (cap.kind === 'tightened' && cap.max > cap.previousMax) {
|
|
101
|
+
throw new IdentityClassError(`Tightening-only violation: max=${cap.max} > previousMax=${cap.previousMax}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Audit the shipped `orchestrator/src/sa-scoring/layer1-deterministic.ts`
|
|
106
|
+
* (and its compiler `did-compiler.ts`) identityClass classifications against
|
|
107
|
+
* the canonical RFC-0028 §7.1 taxonomy.
|
|
108
|
+
*
|
|
109
|
+
* RFC-0028 §7.1 canonical taxonomy classifies *Substrate Contract* fields.
|
|
110
|
+
* `layer1-deterministic.ts` applies the same `'core' | 'evolving'`
|
|
111
|
+
* discriminant to *DID scoring entries* (scope-gate terms, constraint rules,
|
|
112
|
+
* anti-patterns, measurable signals). The discriminant is reused across two
|
|
113
|
+
* layers; the taxonomy was only formally defined for the substrate layer.
|
|
114
|
+
*
|
|
115
|
+
* The defensible cross-layer discrepancy is the **default fallback**: the
|
|
116
|
+
* shipped `ic()` helper in `did-compiler.ts` returns `'evolving'` for fields
|
|
117
|
+
* with no explicit classification, but the canonical taxonomy says novel
|
|
118
|
+
* fields default to `'core'`. This is filed as a Decision rather than
|
|
119
|
+
* inline-resolved because the DID-scoring domain may legitimately prefer
|
|
120
|
+
* a different default than the substrate-contract domain — operator
|
|
121
|
+
* routing required.
|
|
122
|
+
*
|
|
123
|
+
* Returns the list of discrepancies (may be empty). Callers are responsible
|
|
124
|
+
* for piping each into `cli-decisions add --scope ... --option ...`.
|
|
125
|
+
*/
|
|
126
|
+
export function auditLayer1DeterministicClassifications(options = {}) {
|
|
127
|
+
const readFile = options.readFile ?? ((p) => readFileSync(p, 'utf8'));
|
|
128
|
+
// Resolve sibling paths relative to THIS module's location, not cwd —
|
|
129
|
+
// tests run from the package dir, dogfood callers run from the repo root;
|
|
130
|
+
// both must find the shipped source files.
|
|
131
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
132
|
+
const saScoringDir = join(here, '..', 'sa-scoring');
|
|
133
|
+
const filesToAudit = [
|
|
134
|
+
{
|
|
135
|
+
file: 'orchestrator/src/sa-scoring/did-compiler.ts',
|
|
136
|
+
absolutePath: join(saScoringDir, 'did-compiler.ts'),
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
file: 'orchestrator/src/sa-scoring/layer1-deterministic.ts',
|
|
140
|
+
absolutePath: join(saScoringDir, 'layer1-deterministic.ts'),
|
|
141
|
+
},
|
|
142
|
+
];
|
|
143
|
+
const discrepancies = [];
|
|
144
|
+
for (const { file, absolutePath } of filesToAudit) {
|
|
145
|
+
let source;
|
|
146
|
+
try {
|
|
147
|
+
source = readFile(absolutePath);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// File missing from the working tree — skip, do not throw. The audit
|
|
151
|
+
// is best-effort; absent source is itself surfaced via the empty result
|
|
152
|
+
// and the test suite ensures the canonical path exists.
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const lines = source.split('\n');
|
|
156
|
+
lines.forEach((line, idx) => {
|
|
157
|
+
const lineNumber = idx + 1;
|
|
158
|
+
// Pattern 1: `?? 'evolving'` or `?? "evolving"` — explicit default
|
|
159
|
+
// fallback to evolving. Canonical taxonomy says novel fields default
|
|
160
|
+
// to core, so any such fallback IS a discrepancy.
|
|
161
|
+
const defaultMatch = /\?\?\s*['"](evolving|core)['"]/.exec(line);
|
|
162
|
+
if (defaultMatch) {
|
|
163
|
+
const observed = defaultMatch[1];
|
|
164
|
+
if (observed !== 'core') {
|
|
165
|
+
discrepancies.push({
|
|
166
|
+
file,
|
|
167
|
+
symbol: `line ${lineNumber} default fallback`,
|
|
168
|
+
field: 'identityClass (novel default)',
|
|
169
|
+
observed,
|
|
170
|
+
canonical: 'core',
|
|
171
|
+
rationale: `${file}:${lineNumber} defaults missing identityClass to '${observed}' via \`?? '${observed}'\`. ` +
|
|
172
|
+
`Canonical RFC-0028 §7.1 taxonomy specifies novel fields default to 'core' (conservative; ` +
|
|
173
|
+
`promotion to evolving requires RFC amendment). The DID-scoring domain may legitimately ` +
|
|
174
|
+
`defend a different default — operator decision required to (a) align to canonical 'core', ` +
|
|
175
|
+
`(b) carve a documented cross-layer exemption, or (c) revise the canonical taxonomy.`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Pattern 2 (explicit `identityClass: 'evolving'` literal flagging)
|
|
180
|
+
// was REMOVED — it produced false positives for legitimate
|
|
181
|
+
// canonical-evolving fields (`observerCooldownMs`,
|
|
182
|
+
// `cadenceMinIntervalDays`, `clustering.similarityThreshold`,
|
|
183
|
+
// `tenantQuotaShare`) which correctly assign `identityClass:
|
|
184
|
+
// 'evolving'`. Cross-referencing the receiving field name from a
|
|
185
|
+
// raw text scan is too error-prone for an audit signal that flows
|
|
186
|
+
// into the Decision Catalog. Pattern 1 (`?? 'evolving'`
|
|
187
|
+
// default-fallback) is field-agnostic-safe and is the sole
|
|
188
|
+
// discrepancy class this scanner emits.
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return discrepancies;
|
|
192
|
+
}
|
|
193
|
+
// ── Errors ───────────────────────────────────────────────────────────
|
|
194
|
+
/** Thrown by {@link assertTightenedCap} when a child loosens a numeric cap. */
|
|
195
|
+
export class IdentityClassError extends Error {
|
|
196
|
+
constructor(message) {
|
|
197
|
+
super(message);
|
|
198
|
+
this.name = 'IdentityClassError';
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=identity-class.js.map
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0009 §13 Rule #3 — CrossSoulProvenanceRule.
|
|
3
|
+
*
|
|
4
|
+
* Implements `TessellationRule` for the Tessellation§13RuleRegistry so Rule #3
|
|
5
|
+
* is dispatchable via `registry.register(rule)` (AISDLC-489, AISDLC-467 AC#3
|
|
6
|
+
* follow-up).
|
|
7
|
+
*
|
|
8
|
+
* Wraps the existing cross-soul provenance audit logic from
|
|
9
|
+
* `tessellation-drift.ts` as a first-class `TessellationRule` instance.
|
|
10
|
+
* The detection semantics are preserved unchanged:
|
|
11
|
+
*
|
|
12
|
+
* **Detection A** — `cross-boundary-no-amendment`: provenance's `targetedSouls`
|
|
13
|
+
* spans >=2 souls present in the tessellation without a recorded cross-
|
|
14
|
+
* tessellation amendment.
|
|
15
|
+
*
|
|
16
|
+
* **Detection B** — `substrate-divergent-outcomes`: `substrateScoped: true`
|
|
17
|
+
* provenance where the max-min spread of `outcomeBySoul` values meets or
|
|
18
|
+
* exceeds `divergenceThreshold`.
|
|
19
|
+
*
|
|
20
|
+
* ### Provenance input via RuleScanTarget
|
|
21
|
+
*
|
|
22
|
+
* `RuleScanTarget.provenance` carries `unknown[]` for forward-compatibility.
|
|
23
|
+
* `CrossSoulProvenanceRule` narrows each entry to `CrossSoulProvenanceEntry`
|
|
24
|
+
* (the shape understood by the rule) using a runtime type-guard. Entries that
|
|
25
|
+
* do not match the expected shape are silently skipped — this preserves
|
|
26
|
+
* backward-compat when callers pass mixed provenance arrays.
|
|
27
|
+
*
|
|
28
|
+
* Callers should pass `ProvenanceAuditEntry[]` from `tessellation-drift.ts`
|
|
29
|
+
* as `target.provenance` — `CrossSoulProvenanceEntry` is structurally
|
|
30
|
+
* compatible with `ProvenanceAuditEntry` (same fields, re-typed to avoid
|
|
31
|
+
* a cross-module import cycle).
|
|
32
|
+
*
|
|
33
|
+
* @see spec/rfcs/RFC-0009-tessellated-design-intent-documents.md §7.2 Rule #3 + §8.3
|
|
34
|
+
* @see orchestrator/src/tessellation-drift.ts (original Rule #3 logic)
|
|
35
|
+
*/
|
|
36
|
+
import type { TessellationRule, DriftEvent, DriftSeverity, RuleScanTarget } from './rule-registry.js';
|
|
37
|
+
/**
|
|
38
|
+
* Minimal provenance record shape required by CrossSoulProvenanceRule.
|
|
39
|
+
*
|
|
40
|
+
* Structurally compatible with `ProvenanceRecord` from `@ai-sdlc/reference`
|
|
41
|
+
* (the fields used by the rule). Defined here to avoid a cross-module import
|
|
42
|
+
* cycle between the registry package and the tessellation-drift package.
|
|
43
|
+
*/
|
|
44
|
+
interface MinimalProvenanceRecord {
|
|
45
|
+
promptHash?: string;
|
|
46
|
+
timestamp: string;
|
|
47
|
+
targetedSouls?: string[];
|
|
48
|
+
substrateScoped?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* One provenance record paired with the optional cross-soul amendment ref +
|
|
52
|
+
* the optional downstream soul-outcome readings.
|
|
53
|
+
*
|
|
54
|
+
* Structurally compatible with `ProvenanceAuditEntry` from `tessellation-drift.ts`.
|
|
55
|
+
*/
|
|
56
|
+
export interface CrossSoulProvenanceEntry {
|
|
57
|
+
record: MinimalProvenanceRecord;
|
|
58
|
+
amendmentRecorded?: boolean;
|
|
59
|
+
outcomeBySoul?: Record<string, number>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A single cross-soul provenance finding (mirrors `CrossSoulProvenanceFinding`
|
|
63
|
+
* from `tessellation-drift.ts`).
|
|
64
|
+
*/
|
|
65
|
+
export interface CrossSoulProvenanceFinding {
|
|
66
|
+
kind: 'cross-boundary-no-amendment' | 'substrate-divergent-outcomes';
|
|
67
|
+
workItemRef: string;
|
|
68
|
+
crossedSouls: string[];
|
|
69
|
+
outcomeBySoul?: Record<string, number>;
|
|
70
|
+
note: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Structured details payload for cross-soul-provenance drift events.
|
|
74
|
+
*/
|
|
75
|
+
export interface CrossSoulProvenanceDetails {
|
|
76
|
+
rule: 'cross-soul-provenance';
|
|
77
|
+
findings: CrossSoulProvenanceFinding[];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Configuration for `CrossSoulProvenanceRule`.
|
|
81
|
+
*/
|
|
82
|
+
export interface CrossSoulProvenanceConfig {
|
|
83
|
+
/**
|
|
84
|
+
* Spread threshold for substrate-divergent-outcomes detection.
|
|
85
|
+
* Defaults to 0.3 (30-point spread on a 0..1 outcome scale).
|
|
86
|
+
*/
|
|
87
|
+
divergenceThreshold?: number;
|
|
88
|
+
/**
|
|
89
|
+
* Severity override. Default `'warning'` (matches the original
|
|
90
|
+
* `TessellationDriftDetectedEvent severity: 'warning'` in `tessellation-drift.ts`).
|
|
91
|
+
*/
|
|
92
|
+
severity?: DriftSeverity;
|
|
93
|
+
}
|
|
94
|
+
export declare const DEFAULT_DIVERGENCE_THRESHOLD = 0.3;
|
|
95
|
+
/**
|
|
96
|
+
* CrossSoulProvenanceRule — RFC-0009 §13 Rule #3.
|
|
97
|
+
*
|
|
98
|
+
* Audits provenance records for cross-soul boundary violations and
|
|
99
|
+
* substrate-divergent outcomes. Emits a `DriftEvent` when:
|
|
100
|
+
*
|
|
101
|
+
* - A work item targets >=2 tessellation souls without a recorded amendment, OR
|
|
102
|
+
* - A substrate-scoped work item shows divergent soul-distinct outcomes.
|
|
103
|
+
*
|
|
104
|
+
* Provenance entries arrive via `target.provenance` (typed `unknown[]` in
|
|
105
|
+
* `RuleScanTarget`). The rule narrows each entry via `isCrossSoulProvenanceEntry`
|
|
106
|
+
* and skips entries that don't match.
|
|
107
|
+
*
|
|
108
|
+
* Soul slugs for boundary validation arrive via `target.soulSlugs` (forward-
|
|
109
|
+
* compat field on `RuleScanTarget`). When absent, all `targetedSouls` in the
|
|
110
|
+
* provenance records are treated as valid tessellation members (permissive mode).
|
|
111
|
+
*
|
|
112
|
+
* ### Registration
|
|
113
|
+
*
|
|
114
|
+
* ```ts
|
|
115
|
+
* const registry = createTessellation13Registry();
|
|
116
|
+
* registry.register(new CrossSoulProvenanceRule());
|
|
117
|
+
* // With config:
|
|
118
|
+
* registry.register(new CrossSoulProvenanceRule({ divergenceThreshold: 0.5 }));
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare class CrossSoulProvenanceRule implements TessellationRule {
|
|
122
|
+
readonly name = "cross-soul-provenance";
|
|
123
|
+
readonly description = "Audits provenance records for cross-soul boundary violations and substrate-divergent soul outcomes (RFC-0009 \u00A77.2 Rule #3)";
|
|
124
|
+
readonly severity: DriftSeverity;
|
|
125
|
+
private readonly divergenceThreshold;
|
|
126
|
+
/**
|
|
127
|
+
* @param config Optional configuration overrides.
|
|
128
|
+
*/
|
|
129
|
+
constructor(config?: CrossSoulProvenanceConfig);
|
|
130
|
+
scan(target: RuleScanTarget): DriftEvent[];
|
|
131
|
+
}
|
|
132
|
+
export {};
|
|
133
|
+
//# sourceMappingURL=cross-soul-provenance-rule.d.ts.map
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0009 §13 Rule #3 — CrossSoulProvenanceRule.
|
|
3
|
+
*
|
|
4
|
+
* Implements `TessellationRule` for the Tessellation§13RuleRegistry so Rule #3
|
|
5
|
+
* is dispatchable via `registry.register(rule)` (AISDLC-489, AISDLC-467 AC#3
|
|
6
|
+
* follow-up).
|
|
7
|
+
*
|
|
8
|
+
* Wraps the existing cross-soul provenance audit logic from
|
|
9
|
+
* `tessellation-drift.ts` as a first-class `TessellationRule` instance.
|
|
10
|
+
* The detection semantics are preserved unchanged:
|
|
11
|
+
*
|
|
12
|
+
* **Detection A** — `cross-boundary-no-amendment`: provenance's `targetedSouls`
|
|
13
|
+
* spans >=2 souls present in the tessellation without a recorded cross-
|
|
14
|
+
* tessellation amendment.
|
|
15
|
+
*
|
|
16
|
+
* **Detection B** — `substrate-divergent-outcomes`: `substrateScoped: true`
|
|
17
|
+
* provenance where the max-min spread of `outcomeBySoul` values meets or
|
|
18
|
+
* exceeds `divergenceThreshold`.
|
|
19
|
+
*
|
|
20
|
+
* ### Provenance input via RuleScanTarget
|
|
21
|
+
*
|
|
22
|
+
* `RuleScanTarget.provenance` carries `unknown[]` for forward-compatibility.
|
|
23
|
+
* `CrossSoulProvenanceRule` narrows each entry to `CrossSoulProvenanceEntry`
|
|
24
|
+
* (the shape understood by the rule) using a runtime type-guard. Entries that
|
|
25
|
+
* do not match the expected shape are silently skipped — this preserves
|
|
26
|
+
* backward-compat when callers pass mixed provenance arrays.
|
|
27
|
+
*
|
|
28
|
+
* Callers should pass `ProvenanceAuditEntry[]` from `tessellation-drift.ts`
|
|
29
|
+
* as `target.provenance` — `CrossSoulProvenanceEntry` is structurally
|
|
30
|
+
* compatible with `ProvenanceAuditEntry` (same fields, re-typed to avoid
|
|
31
|
+
* a cross-module import cycle).
|
|
32
|
+
*
|
|
33
|
+
* @see spec/rfcs/RFC-0009-tessellated-design-intent-documents.md §7.2 Rule #3 + §8.3
|
|
34
|
+
* @see orchestrator/src/tessellation-drift.ts (original Rule #3 logic)
|
|
35
|
+
*/
|
|
36
|
+
export const DEFAULT_DIVERGENCE_THRESHOLD = 0.3;
|
|
37
|
+
// ── Internal helpers ───────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Derive a short stable work-item reference from a provenance record's
|
|
40
|
+
* `promptHash`. Mirrors `deriveWorkItemRef` in `tessellation-drift.ts`.
|
|
41
|
+
*/
|
|
42
|
+
function deriveWorkItemRef(record) {
|
|
43
|
+
if (record.promptHash && record.promptHash.length > 0) {
|
|
44
|
+
return record.promptHash.slice(0, 16);
|
|
45
|
+
}
|
|
46
|
+
return record.timestamp;
|
|
47
|
+
}
|
|
48
|
+
/** Compute the max-min spread of an outcome map. Returns 0 for <2 souls. */
|
|
49
|
+
function outcomeSpread(outcomeBySoul) {
|
|
50
|
+
const values = Object.values(outcomeBySoul).filter((v) => typeof v === 'number');
|
|
51
|
+
if (values.length < 2)
|
|
52
|
+
return 0;
|
|
53
|
+
return Math.max(...values) - Math.min(...values);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Type-guard for a `CrossSoulProvenanceEntry`.
|
|
57
|
+
*
|
|
58
|
+
* Accepts any object that has a `record` field with a `timestamp` string —
|
|
59
|
+
* the minimum shape required for the rule to operate safely. Extra fields
|
|
60
|
+
* are tolerated (structural subtyping).
|
|
61
|
+
*/
|
|
62
|
+
function isCrossSoulProvenanceEntry(v) {
|
|
63
|
+
if (typeof v !== 'object' || v === null)
|
|
64
|
+
return false;
|
|
65
|
+
const obj = v;
|
|
66
|
+
if (typeof obj['record'] !== 'object' || obj['record'] === null)
|
|
67
|
+
return false;
|
|
68
|
+
const rec = obj['record'];
|
|
69
|
+
return typeof rec['timestamp'] === 'string';
|
|
70
|
+
}
|
|
71
|
+
// ── Rule implementation ────────────────────────────────────────────────
|
|
72
|
+
/**
|
|
73
|
+
* CrossSoulProvenanceRule — RFC-0009 §13 Rule #3.
|
|
74
|
+
*
|
|
75
|
+
* Audits provenance records for cross-soul boundary violations and
|
|
76
|
+
* substrate-divergent outcomes. Emits a `DriftEvent` when:
|
|
77
|
+
*
|
|
78
|
+
* - A work item targets >=2 tessellation souls without a recorded amendment, OR
|
|
79
|
+
* - A substrate-scoped work item shows divergent soul-distinct outcomes.
|
|
80
|
+
*
|
|
81
|
+
* Provenance entries arrive via `target.provenance` (typed `unknown[]` in
|
|
82
|
+
* `RuleScanTarget`). The rule narrows each entry via `isCrossSoulProvenanceEntry`
|
|
83
|
+
* and skips entries that don't match.
|
|
84
|
+
*
|
|
85
|
+
* Soul slugs for boundary validation arrive via `target.soulSlugs` (forward-
|
|
86
|
+
* compat field on `RuleScanTarget`). When absent, all `targetedSouls` in the
|
|
87
|
+
* provenance records are treated as valid tessellation members (permissive mode).
|
|
88
|
+
*
|
|
89
|
+
* ### Registration
|
|
90
|
+
*
|
|
91
|
+
* ```ts
|
|
92
|
+
* const registry = createTessellation13Registry();
|
|
93
|
+
* registry.register(new CrossSoulProvenanceRule());
|
|
94
|
+
* // With config:
|
|
95
|
+
* registry.register(new CrossSoulProvenanceRule({ divergenceThreshold: 0.5 }));
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export class CrossSoulProvenanceRule {
|
|
99
|
+
name = 'cross-soul-provenance';
|
|
100
|
+
description = 'Audits provenance records for cross-soul boundary violations and substrate-divergent soul outcomes (RFC-0009 §7.2 Rule #3)';
|
|
101
|
+
severity;
|
|
102
|
+
divergenceThreshold;
|
|
103
|
+
/**
|
|
104
|
+
* @param config Optional configuration overrides.
|
|
105
|
+
*/
|
|
106
|
+
constructor(config = {}) {
|
|
107
|
+
this.severity = config.severity ?? 'warning';
|
|
108
|
+
this.divergenceThreshold = config.divergenceThreshold ?? DEFAULT_DIVERGENCE_THRESHOLD;
|
|
109
|
+
}
|
|
110
|
+
scan(target) {
|
|
111
|
+
const { tessellatedDid, provenance } = target;
|
|
112
|
+
// No-op when no provenance entries.
|
|
113
|
+
if (!provenance || provenance.length === 0)
|
|
114
|
+
return [];
|
|
115
|
+
const now = new Date().toISOString();
|
|
116
|
+
// Soul slug set for boundary-filtering. Accept from `target.soulSlugs`
|
|
117
|
+
// (forward-compat field). When absent, treat all souls as valid (permissive).
|
|
118
|
+
const soulSlugsRaw = target.soulSlugs;
|
|
119
|
+
const soulSlugSet = soulSlugsRaw ? new Set(soulSlugsRaw) : null;
|
|
120
|
+
const findings = [];
|
|
121
|
+
for (const entry of provenance) {
|
|
122
|
+
// Skip entries that don't match the expected shape.
|
|
123
|
+
if (!isCrossSoulProvenanceEntry(entry))
|
|
124
|
+
continue;
|
|
125
|
+
const { record, amendmentRecorded, outcomeBySoul } = entry;
|
|
126
|
+
// Filter targetedSouls to souls in the tessellation (when soulSlugSet is known).
|
|
127
|
+
const raw = record.targetedSouls ?? [];
|
|
128
|
+
const valid = soulSlugSet ? raw.filter((s) => soulSlugSet.has(s)) : raw;
|
|
129
|
+
// Detection A: cross-boundary without amendment.
|
|
130
|
+
if (valid.length >= 2 && amendmentRecorded !== true) {
|
|
131
|
+
findings.push({
|
|
132
|
+
kind: 'cross-boundary-no-amendment',
|
|
133
|
+
workItemRef: deriveWorkItemRef(record),
|
|
134
|
+
crossedSouls: [...valid].sort(),
|
|
135
|
+
note: `work item targeted ${valid.length} souls without a recorded cross-tessellation amendment`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// Detection B: substrate-scoped with divergent outcomes.
|
|
139
|
+
if (record.substrateScoped === true &&
|
|
140
|
+
outcomeBySoul &&
|
|
141
|
+
Object.keys(outcomeBySoul).length >= 2) {
|
|
142
|
+
const spread = outcomeSpread(outcomeBySoul);
|
|
143
|
+
if (spread >= this.divergenceThreshold) {
|
|
144
|
+
findings.push({
|
|
145
|
+
kind: 'substrate-divergent-outcomes',
|
|
146
|
+
workItemRef: deriveWorkItemRef(record),
|
|
147
|
+
crossedSouls: Object.keys(outcomeBySoul).sort(),
|
|
148
|
+
outcomeBySoul: { ...outcomeBySoul },
|
|
149
|
+
note: `substrate provenance shows soul-distinct outcome spread ${spread.toFixed(3)} ≥ threshold ${this.divergenceThreshold}`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (findings.length === 0)
|
|
155
|
+
return [];
|
|
156
|
+
const involved = new Set(findings.flatMap((f) => f.crossedSouls));
|
|
157
|
+
return [
|
|
158
|
+
{
|
|
159
|
+
rule: this.name,
|
|
160
|
+
timestamp: now,
|
|
161
|
+
message: `Cross-soul provenance: ${findings.length} finding(s) across ${involved.size} soul(s) (tessellation: ${tessellatedDid})`,
|
|
162
|
+
severity: this.severity,
|
|
163
|
+
details: {
|
|
164
|
+
rule: 'cross-soul-provenance',
|
|
165
|
+
findings,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=cross-soul-provenance-rule.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0009 §13 Rule #2 — InterSoulEmbeddingDistanceRule (interface stub).
|
|
3
|
+
*
|
|
4
|
+
* Implements `TessellationRule` for the Tessellation§13RuleRegistry so Rule #2
|
|
5
|
+
* is registerable via `registry.register(rule)` (AISDLC-489, AISDLC-467 AC#3
|
|
6
|
+
* follow-up).
|
|
7
|
+
*
|
|
8
|
+
* Rule #2 (embedding distance between Soul DIDs over time) is **explicitly
|
|
9
|
+
* deferred to RFC-0019** (Embedding Provider Adapter). This class ships as a
|
|
10
|
+
* registered interface stub — it satisfies `TessellationRule`, is registerable,
|
|
11
|
+
* and returns an empty `DriftEvent[]` on every `scan()` call until RFC-0019
|
|
12
|
+
* provides an `embedDocument(text)` callable from the orchestrator.
|
|
13
|
+
*
|
|
14
|
+
* ### Rationale for stub registration
|
|
15
|
+
*
|
|
16
|
+
* Registering the stub now (rather than leaving Rule #2 entirely absent) means:
|
|
17
|
+
* - `registry.getRegisteredRules()` includes `'inter-soul-embedding-distance'`
|
|
18
|
+
* in the standard 3-rule enumeration, making the §13 rule set queryable/
|
|
19
|
+
* observable by operator tooling (TUI, Slack digests) without an RFC-0019 gap.
|
|
20
|
+
* - The RFC-0019 implementation lands by replacing this stub class with the
|
|
21
|
+
* real embedding-distance implementation — NO registration-site changes needed.
|
|
22
|
+
*
|
|
23
|
+
* ### Upgrading to the real rule
|
|
24
|
+
*
|
|
25
|
+
* Per RFC-0019: replace this stub with the real embedding-distance rule once
|
|
26
|
+
* `embedDocument(text): Promise<number[]>` is callable from the orchestrator.
|
|
27
|
+
* The name `'inter-soul-embedding-distance'` is the stable canonical rule name;
|
|
28
|
+
* do NOT change it when swapping in the real implementation.
|
|
29
|
+
*
|
|
30
|
+
* @see spec/rfcs/RFC-0009-tessellated-design-intent-documents.md §7.2 Rule #2
|
|
31
|
+
* @see spec/rfcs/RFC-0019-embedding-provider-adapter.md (implementation target)
|
|
32
|
+
*/
|
|
33
|
+
import type { TessellationRule, DriftEvent, DriftSeverity, RuleScanTarget } from './rule-registry.js';
|
|
34
|
+
/**
|
|
35
|
+
* InterSoulEmbeddingDistanceRule — RFC-0009 §13 Rule #2 (deferred stub).
|
|
36
|
+
*
|
|
37
|
+
* Detects embedding distance drift between Soul DIDs over time. Implementation
|
|
38
|
+
* is deferred to RFC-0019; this stub fulfils the `TessellationRule` interface
|
|
39
|
+
* and can be registered in the Tessellation§13RuleRegistry.
|
|
40
|
+
*
|
|
41
|
+
* `scan()` always returns `[]` until the RFC-0019 embedding provider is wired.
|
|
42
|
+
*
|
|
43
|
+
* ### Registration
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const registry = createTessellation13Registry();
|
|
47
|
+
* registry.register(new InterSoulEmbeddingDistanceRule());
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare class InterSoulEmbeddingDistanceRule implements TessellationRule {
|
|
51
|
+
readonly name = "inter-soul-embedding-distance";
|
|
52
|
+
readonly description = "Detects embedding distance drift between Soul DIDs over time (RFC-0009 \u00A77.2 Rule #2, deferred to RFC-0019 \u2014 stub returns empty until embedding provider is available)";
|
|
53
|
+
readonly severity: DriftSeverity;
|
|
54
|
+
/**
|
|
55
|
+
* @param severity Default `'medium'` (reserved for the real implementation;
|
|
56
|
+
* configurable now so adopters can set it before RFC-0019 ships).
|
|
57
|
+
*/
|
|
58
|
+
constructor(severity?: DriftSeverity);
|
|
59
|
+
scan(_target: RuleScanTarget): DriftEvent[];
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=inter-soul-embedding-distance-rule.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0009 §13 Rule #2 — InterSoulEmbeddingDistanceRule (interface stub).
|
|
3
|
+
*
|
|
4
|
+
* Implements `TessellationRule` for the Tessellation§13RuleRegistry so Rule #2
|
|
5
|
+
* is registerable via `registry.register(rule)` (AISDLC-489, AISDLC-467 AC#3
|
|
6
|
+
* follow-up).
|
|
7
|
+
*
|
|
8
|
+
* Rule #2 (embedding distance between Soul DIDs over time) is **explicitly
|
|
9
|
+
* deferred to RFC-0019** (Embedding Provider Adapter). This class ships as a
|
|
10
|
+
* registered interface stub — it satisfies `TessellationRule`, is registerable,
|
|
11
|
+
* and returns an empty `DriftEvent[]` on every `scan()` call until RFC-0019
|
|
12
|
+
* provides an `embedDocument(text)` callable from the orchestrator.
|
|
13
|
+
*
|
|
14
|
+
* ### Rationale for stub registration
|
|
15
|
+
*
|
|
16
|
+
* Registering the stub now (rather than leaving Rule #2 entirely absent) means:
|
|
17
|
+
* - `registry.getRegisteredRules()` includes `'inter-soul-embedding-distance'`
|
|
18
|
+
* in the standard 3-rule enumeration, making the §13 rule set queryable/
|
|
19
|
+
* observable by operator tooling (TUI, Slack digests) without an RFC-0019 gap.
|
|
20
|
+
* - The RFC-0019 implementation lands by replacing this stub class with the
|
|
21
|
+
* real embedding-distance implementation — NO registration-site changes needed.
|
|
22
|
+
*
|
|
23
|
+
* ### Upgrading to the real rule
|
|
24
|
+
*
|
|
25
|
+
* Per RFC-0019: replace this stub with the real embedding-distance rule once
|
|
26
|
+
* `embedDocument(text): Promise<number[]>` is callable from the orchestrator.
|
|
27
|
+
* The name `'inter-soul-embedding-distance'` is the stable canonical rule name;
|
|
28
|
+
* do NOT change it when swapping in the real implementation.
|
|
29
|
+
*
|
|
30
|
+
* @see spec/rfcs/RFC-0009-tessellated-design-intent-documents.md §7.2 Rule #2
|
|
31
|
+
* @see spec/rfcs/RFC-0019-embedding-provider-adapter.md (implementation target)
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* InterSoulEmbeddingDistanceRule — RFC-0009 §13 Rule #2 (deferred stub).
|
|
35
|
+
*
|
|
36
|
+
* Detects embedding distance drift between Soul DIDs over time. Implementation
|
|
37
|
+
* is deferred to RFC-0019; this stub fulfils the `TessellationRule` interface
|
|
38
|
+
* and can be registered in the Tessellation§13RuleRegistry.
|
|
39
|
+
*
|
|
40
|
+
* `scan()` always returns `[]` until the RFC-0019 embedding provider is wired.
|
|
41
|
+
*
|
|
42
|
+
* ### Registration
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* const registry = createTessellation13Registry();
|
|
46
|
+
* registry.register(new InterSoulEmbeddingDistanceRule());
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export class InterSoulEmbeddingDistanceRule {
|
|
50
|
+
name = 'inter-soul-embedding-distance';
|
|
51
|
+
description = 'Detects embedding distance drift between Soul DIDs over time (RFC-0009 §7.2 Rule #2, deferred to RFC-0019 — stub returns empty until embedding provider is available)';
|
|
52
|
+
severity;
|
|
53
|
+
/**
|
|
54
|
+
* @param severity Default `'medium'` (reserved for the real implementation;
|
|
55
|
+
* configurable now so adopters can set it before RFC-0019 ships).
|
|
56
|
+
*/
|
|
57
|
+
constructor(severity = 'medium') {
|
|
58
|
+
this.severity = severity;
|
|
59
|
+
}
|
|
60
|
+
scan(_target) {
|
|
61
|
+
// Rule #2 is deferred to RFC-0019. This stub intentionally returns empty.
|
|
62
|
+
// When RFC-0019 lands, replace this body with the real embedding-distance
|
|
63
|
+
// scan logic. The rule name and interface contract are stable.
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=inter-soul-embedding-distance-rule.js.map
|