@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,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0009 Phase 2.1 — Tessellation routing for admission composite.
|
|
3
|
+
*
|
|
4
|
+
* Implements the soul-scope routing algorithm from RFC-0009 §6:
|
|
5
|
+
*
|
|
6
|
+
* resolveAffectedSouls(w) = set of Soul DIDs the work item affects,
|
|
7
|
+
* computed from the dependency graph snapshot (RFC-0014).
|
|
8
|
+
*
|
|
9
|
+
* If tessellation absent on the resolved DID:
|
|
10
|
+
* Behavior unchanged from RFC-0008. Single-DID semantics preserved.
|
|
11
|
+
*
|
|
12
|
+
* Else if |resolveAffectedSouls(w)| == 0:
|
|
13
|
+
* // Pure substrate work touching no soul-importing module
|
|
14
|
+
* Sα(w) = min over ALL souls { Sα(w, soul) } (§6 degenerate case)
|
|
15
|
+
*
|
|
16
|
+
* Else if |resolveAffectedSouls(w)| == 1:
|
|
17
|
+
* Sα(w) = Sα(w, targetSoul) // soul's own DSB
|
|
18
|
+
*
|
|
19
|
+
* Else:
|
|
20
|
+
* Sα(w) = crossSoulScoringRule(w, affectedSouls) // default `min`
|
|
21
|
+
*
|
|
22
|
+
* The same resolution applies to Eρ₄ (Design System Readiness) per §6:
|
|
23
|
+
* "The same soul-resolution applies to Eρ₄ which reads against the
|
|
24
|
+
* targeted soul's DSB rather than the platform-aggregate DSB."
|
|
25
|
+
*
|
|
26
|
+
* @see spec/rfcs/RFC-0009-tessellated-design-intent-documents.md §6 + §10
|
|
27
|
+
*/
|
|
28
|
+
import type { Tessellation } from '@ai-sdlc/reference';
|
|
29
|
+
/**
|
|
30
|
+
* A minimal representation of one dep-graph snapshot record's soul scope.
|
|
31
|
+
*
|
|
32
|
+
* Derived from the RFC-0014 snapshot (SnapshotRecord) via the pipeline-cli
|
|
33
|
+
* reader layer. Callers populate this from `snapshot.*.jsonl` records before
|
|
34
|
+
* calling `resolveAffectedSouls`.
|
|
35
|
+
*
|
|
36
|
+
* When `targetedSoulIds` is absent or empty, the work item is treated as
|
|
37
|
+
* substrate-only — affecting the full `min`-over-all-souls degenerate case.
|
|
38
|
+
*/
|
|
39
|
+
export interface DepGraphSoulEntry {
|
|
40
|
+
/**
|
|
41
|
+
* Canonical task ID (case-insensitive match used internally). E.g. "AISDLC-313".
|
|
42
|
+
*/
|
|
43
|
+
id: string;
|
|
44
|
+
/**
|
|
45
|
+
* Soul slugs (soulId values from the Tessellation manifest) that this
|
|
46
|
+
* work item explicitly targets. Empty or absent = substrate-only change.
|
|
47
|
+
*
|
|
48
|
+
* Populated by the pipeline-cli layer reading the dep-graph snapshot; the
|
|
49
|
+
* soulId values must match `tessellation.souls[].soulId` for the lookup to
|
|
50
|
+
* produce useful results.
|
|
51
|
+
*/
|
|
52
|
+
targetedSoulIds?: string[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Per-soul scoring data used by the tessellated admission composite.
|
|
56
|
+
* One entry per active soul in the tessellation.
|
|
57
|
+
*/
|
|
58
|
+
export interface SoulScores {
|
|
59
|
+
/**
|
|
60
|
+
* Soul-specific soul-alignment score in [0, 1].
|
|
61
|
+
* Scored against this soul's DSB and product vertex (§6 + §5.1.1).
|
|
62
|
+
*/
|
|
63
|
+
soulAlignment: number;
|
|
64
|
+
/**
|
|
65
|
+
* Soul-specific Eρ₄ Design System Readiness in [0, 1].
|
|
66
|
+
* Reads from the soul's own DSB at `.ai-sdlc/souls/<slug>/design-system-binding.yaml`
|
|
67
|
+
* rather than the platform-aggregate DSB (§6 last para).
|
|
68
|
+
*/
|
|
69
|
+
er4: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* All tessellation-related inputs needed by the admission composite
|
|
73
|
+
* for RFC-0009 Phase 2.1 soul-scope routing.
|
|
74
|
+
*
|
|
75
|
+
* Callers build this once per pipeline tick and pass it to
|
|
76
|
+
* `computeAdmissionComposite` via `AdmissionCompositeOptions.tessellationContext`.
|
|
77
|
+
*/
|
|
78
|
+
export interface TessellationContext {
|
|
79
|
+
/**
|
|
80
|
+
* The Tessellated DID's `tessellation` field (from `DesignIntentDocumentSpec`).
|
|
81
|
+
* Carries the soul manifest + `crossSoulScoringRule` + `substrateInvariants`.
|
|
82
|
+
*/
|
|
83
|
+
tessellation: Tessellation;
|
|
84
|
+
/**
|
|
85
|
+
* Pre-computed per-soul scores, keyed by `soulId` (matching
|
|
86
|
+
* `tessellation.souls[].soulId`). Must cover at least every active soul.
|
|
87
|
+
*
|
|
88
|
+
* In a full Phase 2 implementation these are computed by reading each
|
|
89
|
+
* soul's DSB at `.ai-sdlc/souls/<slug>/design-system-binding.yaml` and
|
|
90
|
+
* scoring Sα against the soul's product vertex.
|
|
91
|
+
*/
|
|
92
|
+
soulScores: Record<string, SoulScores>;
|
|
93
|
+
/**
|
|
94
|
+
* Dep-graph soul scope entries — one per work item in the active backlog.
|
|
95
|
+
* Read from the latest RFC-0014 snapshot via `pipeline-cli`'s snapshot
|
|
96
|
+
* reader before calling the admission composite.
|
|
97
|
+
*
|
|
98
|
+
* When `undefined` or empty, every work item is treated as substrate-only.
|
|
99
|
+
*/
|
|
100
|
+
depGraphEntries?: DepGraphSoulEntry[];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolve the set of soul IDs affected by a work item.
|
|
104
|
+
*
|
|
105
|
+
* Algorithm (RFC-0009 §6 + OQ-2 sub-decision):
|
|
106
|
+
* 1. Find the work item's dep-graph entry by case-insensitive ID match.
|
|
107
|
+
* 2. Filter its `targetedSoulIds` against souls present in the tessellation.
|
|
108
|
+
* 3. Return the validated intersection.
|
|
109
|
+
* 4. If no entry is found, or `targetedSoulIds` is empty/absent → return `[]`
|
|
110
|
+
* (substrate-only; triggers the `min`-over-all-souls degenerate case in §6).
|
|
111
|
+
*
|
|
112
|
+
* @param workItemId - The work item's canonical ID (e.g. "AISDLC-313").
|
|
113
|
+
* @param depGraphEntries - Soul scope entries from the RFC-0014 snapshot.
|
|
114
|
+
* @param tessellation - The tessellation manifest to validate soul IDs against.
|
|
115
|
+
* @returns Array of valid affected soul IDs (empty = substrate-only).
|
|
116
|
+
*/
|
|
117
|
+
export declare function resolveAffectedSouls(workItemId: string, depGraphEntries: DepGraphSoulEntry[] | undefined, tessellation: Tessellation): string[];
|
|
118
|
+
/**
|
|
119
|
+
* Apply `crossSoulScoringRule` over a per-soul score map.
|
|
120
|
+
*
|
|
121
|
+
* Currently implements `min` (default per OQ-2 resolution) and `max`/`mean`
|
|
122
|
+
* escape valves. `weighted-traffic` and `weighted-revenue` require an external
|
|
123
|
+
* data source and are documented as advanced — they fall through to `min` when
|
|
124
|
+
* no weights are available (safe degenerate).
|
|
125
|
+
*
|
|
126
|
+
* @param soulIds - The soul IDs to aggregate over.
|
|
127
|
+
* @param scores - Per-soul score map (keyed by soulId).
|
|
128
|
+
* @param rule - The aggregation rule from the Tessellated DID.
|
|
129
|
+
* @param fallback - Default score when no soul scores are available (0.5).
|
|
130
|
+
*/
|
|
131
|
+
export declare function applyCrossSoulRule(soulIds: string[], scores: Record<string, number>, rule: Tessellation['crossSoulScoringRule'], fallback?: number): number;
|
|
132
|
+
/**
|
|
133
|
+
* Result of tessellation-based soul-alignment resolution.
|
|
134
|
+
* Exposes routing path for auditability.
|
|
135
|
+
*/
|
|
136
|
+
export interface TessellatedSaResult {
|
|
137
|
+
/** The resolved Sα value in [0, 1]. */
|
|
138
|
+
soulAlignment: number;
|
|
139
|
+
/** The resolved Eρ₄ value in [0, 1]. */
|
|
140
|
+
er4: number;
|
|
141
|
+
/**
|
|
142
|
+
* Routing path taken (matches RFC-0009 §6 case labels).
|
|
143
|
+
*
|
|
144
|
+
* - `'non-tessellated'` — tessellation absent; single-DID path preserved.
|
|
145
|
+
* - `'substrate-only'` — 0 affected souls; `min`-over-ALL-souls degenerate.
|
|
146
|
+
* - `'single-soul'` — 1 affected soul; scored against that soul's DSB.
|
|
147
|
+
* - `'multi-soul'` — N>1 affected souls; crossSoulScoringRule applied.
|
|
148
|
+
*/
|
|
149
|
+
routingPath: 'non-tessellated' | 'substrate-only' | 'single-soul' | 'multi-soul';
|
|
150
|
+
/** Soul IDs used in the aggregation (empty for `non-tessellated`). */
|
|
151
|
+
affectedSoulIds: string[];
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Compute tessellated Sα + Eρ₄ for a work item, implementing RFC-0009 §6.
|
|
155
|
+
*
|
|
156
|
+
* @param workItemId - The canonical work item ID.
|
|
157
|
+
* @param fallbackSa - SA score to use when tessellation is absent (single-DID path).
|
|
158
|
+
* @param fallbackEr4 - Eρ₄ score to use when tessellation is absent.
|
|
159
|
+
* @param tessellationCtx - Tessellation context, or undefined for non-tessellated DID.
|
|
160
|
+
*/
|
|
161
|
+
export declare function computeTessellatedScores(workItemId: string, fallbackSa: number, fallbackEr4: number, tessellationCtx: TessellationContext | undefined): TessellatedSaResult;
|
|
162
|
+
//# sourceMappingURL=tessellation-admission.d.ts.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0009 Phase 2.1 — Tessellation routing for admission composite.
|
|
3
|
+
*
|
|
4
|
+
* Implements the soul-scope routing algorithm from RFC-0009 §6:
|
|
5
|
+
*
|
|
6
|
+
* resolveAffectedSouls(w) = set of Soul DIDs the work item affects,
|
|
7
|
+
* computed from the dependency graph snapshot (RFC-0014).
|
|
8
|
+
*
|
|
9
|
+
* If tessellation absent on the resolved DID:
|
|
10
|
+
* Behavior unchanged from RFC-0008. Single-DID semantics preserved.
|
|
11
|
+
*
|
|
12
|
+
* Else if |resolveAffectedSouls(w)| == 0:
|
|
13
|
+
* // Pure substrate work touching no soul-importing module
|
|
14
|
+
* Sα(w) = min over ALL souls { Sα(w, soul) } (§6 degenerate case)
|
|
15
|
+
*
|
|
16
|
+
* Else if |resolveAffectedSouls(w)| == 1:
|
|
17
|
+
* Sα(w) = Sα(w, targetSoul) // soul's own DSB
|
|
18
|
+
*
|
|
19
|
+
* Else:
|
|
20
|
+
* Sα(w) = crossSoulScoringRule(w, affectedSouls) // default `min`
|
|
21
|
+
*
|
|
22
|
+
* The same resolution applies to Eρ₄ (Design System Readiness) per §6:
|
|
23
|
+
* "The same soul-resolution applies to Eρ₄ which reads against the
|
|
24
|
+
* targeted soul's DSB rather than the platform-aggregate DSB."
|
|
25
|
+
*
|
|
26
|
+
* @see spec/rfcs/RFC-0009-tessellated-design-intent-documents.md §6 + §10
|
|
27
|
+
*/
|
|
28
|
+
// ── Core functions ─────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the set of soul IDs affected by a work item.
|
|
31
|
+
*
|
|
32
|
+
* Algorithm (RFC-0009 §6 + OQ-2 sub-decision):
|
|
33
|
+
* 1. Find the work item's dep-graph entry by case-insensitive ID match.
|
|
34
|
+
* 2. Filter its `targetedSoulIds` against souls present in the tessellation.
|
|
35
|
+
* 3. Return the validated intersection.
|
|
36
|
+
* 4. If no entry is found, or `targetedSoulIds` is empty/absent → return `[]`
|
|
37
|
+
* (substrate-only; triggers the `min`-over-all-souls degenerate case in §6).
|
|
38
|
+
*
|
|
39
|
+
* @param workItemId - The work item's canonical ID (e.g. "AISDLC-313").
|
|
40
|
+
* @param depGraphEntries - Soul scope entries from the RFC-0014 snapshot.
|
|
41
|
+
* @param tessellation - The tessellation manifest to validate soul IDs against.
|
|
42
|
+
* @returns Array of valid affected soul IDs (empty = substrate-only).
|
|
43
|
+
*/
|
|
44
|
+
export function resolveAffectedSouls(workItemId, depGraphEntries, tessellation) {
|
|
45
|
+
if (!depGraphEntries || depGraphEntries.length === 0)
|
|
46
|
+
return [];
|
|
47
|
+
const normalizedId = workItemId.toLowerCase();
|
|
48
|
+
const entry = depGraphEntries.find((e) => e.id.toLowerCase() === normalizedId);
|
|
49
|
+
if (!entry || !entry.targetedSoulIds || entry.targetedSoulIds.length === 0)
|
|
50
|
+
return [];
|
|
51
|
+
// Validate each declared soul ID against the tessellation manifest.
|
|
52
|
+
const validSoulIds = new Set(tessellation.souls.map((s) => s.soulId));
|
|
53
|
+
return entry.targetedSoulIds.filter((id) => validSoulIds.has(id));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Apply `crossSoulScoringRule` over a per-soul score map.
|
|
57
|
+
*
|
|
58
|
+
* Currently implements `min` (default per OQ-2 resolution) and `max`/`mean`
|
|
59
|
+
* escape valves. `weighted-traffic` and `weighted-revenue` require an external
|
|
60
|
+
* data source and are documented as advanced — they fall through to `min` when
|
|
61
|
+
* no weights are available (safe degenerate).
|
|
62
|
+
*
|
|
63
|
+
* @param soulIds - The soul IDs to aggregate over.
|
|
64
|
+
* @param scores - Per-soul score map (keyed by soulId).
|
|
65
|
+
* @param rule - The aggregation rule from the Tessellated DID.
|
|
66
|
+
* @param fallback - Default score when no soul scores are available (0.5).
|
|
67
|
+
*/
|
|
68
|
+
export function applyCrossSoulRule(soulIds, scores, rule, fallback = 0.5) {
|
|
69
|
+
const values = soulIds.map((id) => scores[id]).filter((v) => v !== undefined);
|
|
70
|
+
if (values.length === 0)
|
|
71
|
+
return fallback;
|
|
72
|
+
switch (rule ?? 'min') {
|
|
73
|
+
case 'min':
|
|
74
|
+
return Math.min(...values);
|
|
75
|
+
case 'max':
|
|
76
|
+
return Math.max(...values);
|
|
77
|
+
case 'mean':
|
|
78
|
+
return values.reduce((sum, v) => sum + v, 0) / values.length;
|
|
79
|
+
case 'weighted-traffic':
|
|
80
|
+
case 'weighted-revenue':
|
|
81
|
+
// Advanced variants require an external data source (per RFC-0009 §5.2 note).
|
|
82
|
+
// Degenerate to `min` when no weight data available — safe, conservative.
|
|
83
|
+
return Math.min(...values);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Compute tessellated Sα + Eρ₄ for a work item, implementing RFC-0009 §6.
|
|
88
|
+
*
|
|
89
|
+
* @param workItemId - The canonical work item ID.
|
|
90
|
+
* @param fallbackSa - SA score to use when tessellation is absent (single-DID path).
|
|
91
|
+
* @param fallbackEr4 - Eρ₄ score to use when tessellation is absent.
|
|
92
|
+
* @param tessellationCtx - Tessellation context, or undefined for non-tessellated DID.
|
|
93
|
+
*/
|
|
94
|
+
export function computeTessellatedScores(workItemId, fallbackSa, fallbackEr4, tessellationCtx) {
|
|
95
|
+
// ── Non-tessellated path (RFC-0008 legacy) ─────────────────────
|
|
96
|
+
if (!tessellationCtx) {
|
|
97
|
+
return {
|
|
98
|
+
soulAlignment: fallbackSa,
|
|
99
|
+
er4: fallbackEr4,
|
|
100
|
+
routingPath: 'non-tessellated',
|
|
101
|
+
affectedSoulIds: [],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const { tessellation, soulScores, depGraphEntries } = tessellationCtx;
|
|
105
|
+
const affectedSoulIds = resolveAffectedSouls(workItemId, depGraphEntries, tessellation);
|
|
106
|
+
// Build per-soul score maps for Sα and Eρ₄.
|
|
107
|
+
const soulSaMap = {};
|
|
108
|
+
const soulEr4Map = {};
|
|
109
|
+
for (const soul of tessellation.souls) {
|
|
110
|
+
const scores = soulScores[soul.soulId];
|
|
111
|
+
if (scores) {
|
|
112
|
+
soulSaMap[soul.soulId] = scores.soulAlignment;
|
|
113
|
+
soulEr4Map[soul.soulId] = scores.er4;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const rule = tessellation.crossSoulScoringRule ?? 'min';
|
|
117
|
+
const allSoulIds = tessellation.souls.map((s) => s.soulId);
|
|
118
|
+
// ── Substrate-only path (§6 degenerate) ───────────────────────
|
|
119
|
+
if (affectedSoulIds.length === 0) {
|
|
120
|
+
return {
|
|
121
|
+
soulAlignment: applyCrossSoulRule(allSoulIds, soulSaMap, rule, fallbackSa),
|
|
122
|
+
er4: applyCrossSoulRule(allSoulIds, soulEr4Map, rule, fallbackEr4),
|
|
123
|
+
routingPath: 'substrate-only',
|
|
124
|
+
affectedSoulIds: [],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// ── Single-soul path ───────────────────────────────────────────
|
|
128
|
+
if (affectedSoulIds.length === 1) {
|
|
129
|
+
const soulId = affectedSoulIds[0];
|
|
130
|
+
const scores = soulScores[soulId];
|
|
131
|
+
return {
|
|
132
|
+
soulAlignment: scores?.soulAlignment ?? fallbackSa,
|
|
133
|
+
er4: scores?.er4 ?? fallbackEr4,
|
|
134
|
+
routingPath: 'single-soul',
|
|
135
|
+
affectedSoulIds,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// ── Multi-soul path (crossSoulScoringRule over affected souls) ─
|
|
139
|
+
return {
|
|
140
|
+
soulAlignment: applyCrossSoulRule(affectedSoulIds, soulSaMap, rule, fallbackSa),
|
|
141
|
+
er4: applyCrossSoulRule(affectedSoulIds, soulEr4Map, rule, fallbackEr4),
|
|
142
|
+
routingPath: 'multi-soul',
|
|
143
|
+
affectedSoulIds,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=tessellation-admission.js.map
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-0009 Phase 4.2 — Eτ_tessellation_drift detector (orchestrator-side).
|
|
3
|
+
*
|
|
4
|
+
* Detects design-coherence drift across tessellated souls per RFC-0009 §7.2
|
|
5
|
+
* (OQ-6 resolution: detection is orchestrator-side, not adapter-side).
|
|
6
|
+
*
|
|
7
|
+
* Three detection rules are specified in §7.2:
|
|
8
|
+
*
|
|
9
|
+
* Rule #1 — AST scan for soul-name string literals in shared substrate
|
|
10
|
+
* SHIPS HERE. Static scan over the substrate file set looking for
|
|
11
|
+
* soul-slug string literals and `if (soul === '<slug>')` patterns
|
|
12
|
+
* in modules that are NOT scoped to a single soul.
|
|
13
|
+
*
|
|
14
|
+
* Rule #2 — Embedding distance between Soul DIDs over time
|
|
15
|
+
* EXPLICITLY DEFERRED to RFC-0019 (Embedding Provider Adapter).
|
|
16
|
+
* Not implemented here; would land in a separate detector once
|
|
17
|
+
* `embedDocument(text)` is callable from the orchestrator.
|
|
18
|
+
*
|
|
19
|
+
* Rule #3 — Cross-soul provenance audits
|
|
20
|
+
* SHIPS HERE. Walks the supplied provenance records (RFC-0009 §8.3
|
|
21
|
+
* ProvenanceRecord with `targetedSouls`, `substrateScoped`,
|
|
22
|
+
* `tessellatedSoulRef`, all landed by AISDLC-315) and flags work
|
|
23
|
+
* whose `targetedSouls` set crosses tessellation boundaries
|
|
24
|
+
* without an amendment record; flags substrate work whose
|
|
25
|
+
* downstream provenance shows soul-distinct outcomes diverge.
|
|
26
|
+
*
|
|
27
|
+
* Both shipped rules are gated on adopter opt-in via `enabled` (default
|
|
28
|
+
* `false`) per RFC-0009 §10 Phase 4 promotion convention ("All sub-dimension
|
|
29
|
+
* activations are gated on adopter opt-in initially").
|
|
30
|
+
*
|
|
31
|
+
* Detected drift events emit to `events.jsonl` (the RFC-0015 substrate) via
|
|
32
|
+
* the supplied `emit` callback. Callers wire this to
|
|
33
|
+
* `orchestrator/src/artifacts.appendEvent(artifactsDir, event)`.
|
|
34
|
+
*
|
|
35
|
+
* @see spec/rfcs/RFC-0009-tessellated-design-intent-documents.md §7.2 + §10
|
|
36
|
+
*/
|
|
37
|
+
import type { ProvenanceRecord } from '@ai-sdlc/reference';
|
|
38
|
+
import type { Tessellation } from '@ai-sdlc/reference';
|
|
39
|
+
/**
|
|
40
|
+
* Discriminated rule identifier for an emitted drift event.
|
|
41
|
+
*
|
|
42
|
+
* - `'ast-scan'` — Rule #1 (soul-name leakage in substrate).
|
|
43
|
+
* - `'cross-soul-provenance'` — Rule #3 (provenance crosses soul boundaries
|
|
44
|
+
* without amendment, OR substrate
|
|
45
|
+
* provenance shows divergent soul-
|
|
46
|
+
* distinct outcomes).
|
|
47
|
+
*
|
|
48
|
+
* Rule #2 (`'embedding-distance'`) is reserved for the RFC-0019 follow-on
|
|
49
|
+
* detector and is intentionally NOT a member of this union — exporting it
|
|
50
|
+
* here would invite premature consumers. AISDLC-340 will add it.
|
|
51
|
+
*/
|
|
52
|
+
export type TessellationDriftRule = 'ast-scan' | 'cross-soul-provenance';
|
|
53
|
+
/**
|
|
54
|
+
* The minimal common shape of every drift event written to events.jsonl.
|
|
55
|
+
*
|
|
56
|
+
* Discriminated by `rule` so consumers (operators grepping events.jsonl,
|
|
57
|
+
* cli-status, TUI analytics) can attribute to the originating detector
|
|
58
|
+
* without re-parsing free-form messages.
|
|
59
|
+
*/
|
|
60
|
+
export interface TessellationDriftDetectedEvent {
|
|
61
|
+
type: 'TessellationDriftDetected';
|
|
62
|
+
rule: TessellationDriftRule;
|
|
63
|
+
/** RFC-3339 UTC timestamp at detection time. */
|
|
64
|
+
timestamp: string;
|
|
65
|
+
/**
|
|
66
|
+
* Parent Tessellated DID URI (e.g., `did:platform-x:platform`) the drift
|
|
67
|
+
* was detected against. Sourced from the `tessellation` field's owning
|
|
68
|
+
* DID; callers pass it through so events.jsonl traces back to the DID.
|
|
69
|
+
*/
|
|
70
|
+
tessellatedDid: string;
|
|
71
|
+
/**
|
|
72
|
+
* Soul IDs implicated in the drift (for `ast-scan`: souls whose slugs
|
|
73
|
+
* appeared in shared substrate; for `cross-soul-provenance`: souls
|
|
74
|
+
* crossed). Empty if no specific souls are implicated.
|
|
75
|
+
*/
|
|
76
|
+
involvedSouls: string[];
|
|
77
|
+
/** Human-readable severity label. Currently a single tier; reserved for future expansion. */
|
|
78
|
+
severity: 'warning';
|
|
79
|
+
/** Free-form one-line summary; safe for operator surfaces (TUI, Slack). */
|
|
80
|
+
message: string;
|
|
81
|
+
/**
|
|
82
|
+
* Rule-specific structured payload. Per-rule discriminator is `rule`
|
|
83
|
+
* above; consumers narrow on that before reading `details`.
|
|
84
|
+
*/
|
|
85
|
+
details: AstScanDetails | CrossSoulProvenanceDetails;
|
|
86
|
+
}
|
|
87
|
+
/** Details emitted by Rule #1 (AST scan). */
|
|
88
|
+
export interface AstScanDetails {
|
|
89
|
+
rule: 'ast-scan';
|
|
90
|
+
/** Each finding represents one literal/conditional hit in substrate code. */
|
|
91
|
+
findings: AstScanFinding[];
|
|
92
|
+
}
|
|
93
|
+
/** A single AST-scan finding. */
|
|
94
|
+
export interface AstScanFinding {
|
|
95
|
+
/** Path of the substrate file that contained the soul-leaking literal. */
|
|
96
|
+
filePath: string;
|
|
97
|
+
/** Soul slug whose name leaked into shared substrate. */
|
|
98
|
+
soulSlug: string;
|
|
99
|
+
/** 1-based line number in `filePath`. */
|
|
100
|
+
line: number;
|
|
101
|
+
/**
|
|
102
|
+
* Discriminator for which pattern triggered the finding:
|
|
103
|
+
* - `'string-literal'` — bare `'<slug>'` (or `"<slug>"`) appeared in substrate
|
|
104
|
+
* - `'soul-conditional'` — `if (soul === '<slug>')` / `=== "<slug>"` branched on soul
|
|
105
|
+
*/
|
|
106
|
+
pattern: 'string-literal' | 'soul-conditional';
|
|
107
|
+
/** The raw matching substring (trimmed) for operator inspection. */
|
|
108
|
+
excerpt: string;
|
|
109
|
+
}
|
|
110
|
+
/** Details emitted by Rule #3 (cross-soul provenance audit). */
|
|
111
|
+
export interface CrossSoulProvenanceDetails {
|
|
112
|
+
rule: 'cross-soul-provenance';
|
|
113
|
+
/** Each finding represents one provenance record (or substrate-vs-soul divergence) flagged. */
|
|
114
|
+
findings: CrossSoulProvenanceFinding[];
|
|
115
|
+
}
|
|
116
|
+
/** A single cross-soul provenance finding. */
|
|
117
|
+
export interface CrossSoulProvenanceFinding {
|
|
118
|
+
/**
|
|
119
|
+
* Discriminator:
|
|
120
|
+
* - `'cross-boundary-no-amendment'` — provenance's `targetedSouls` spans
|
|
121
|
+
* >=2 souls and no recorded amendment was supplied for the work.
|
|
122
|
+
* - `'substrate-divergent-outcomes'` — `substrateScoped: true` provenance
|
|
123
|
+
* where downstream soul-distinct outcomes diverge sharply (the caller-
|
|
124
|
+
* supplied `outcomeBySoul` map shows ≥`divergenceThreshold` spread).
|
|
125
|
+
*/
|
|
126
|
+
kind: 'cross-boundary-no-amendment' | 'substrate-divergent-outcomes';
|
|
127
|
+
/**
|
|
128
|
+
* Stable per-work-item identifier extracted from `promptHash` so operators
|
|
129
|
+
* can grep events.jsonl by work item without exposing soul data.
|
|
130
|
+
*/
|
|
131
|
+
workItemRef: string;
|
|
132
|
+
/** Soul IDs crossed (for cross-boundary) or implicated (for substrate-divergent). */
|
|
133
|
+
crossedSouls: string[];
|
|
134
|
+
/**
|
|
135
|
+
* Soul-distinct outcome readings for substrate-divergent findings, keyed
|
|
136
|
+
* by soulId. Absent for cross-boundary findings.
|
|
137
|
+
*/
|
|
138
|
+
outcomeBySoul?: Record<string, number>;
|
|
139
|
+
/** Free-form description; safe for operator surfaces. */
|
|
140
|
+
note: string;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* A single substrate file's contents for Rule #1 to scan.
|
|
144
|
+
*
|
|
145
|
+
* Callers materialize this from the dependency graph + filesystem before
|
|
146
|
+
* invoking the detector. Only files NOT scoped to a single soul should be
|
|
147
|
+
* passed in (files under `.ai-sdlc/souls/<slug>/` or other soul-scoped
|
|
148
|
+
* trees are by-definition allowed to mention their own soul slug).
|
|
149
|
+
*/
|
|
150
|
+
export interface SubstrateFile {
|
|
151
|
+
/** Workspace-relative path (use forward slashes; informational only). */
|
|
152
|
+
path: string;
|
|
153
|
+
/** Full file contents as UTF-8. */
|
|
154
|
+
contents: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* One provenance record paired with the optional cross-soul amendment ref +
|
|
158
|
+
* the optional downstream soul-outcome readings.
|
|
159
|
+
*
|
|
160
|
+
* `amendmentRecorded` is true when the work item carried an explicit
|
|
161
|
+
* cross-tessellation amendment (operator-acknowledged the cross-soul span).
|
|
162
|
+
* `outcomeBySoul` is the optional downstream calibration cell readout per
|
|
163
|
+
* soul, supplied for substrate-scoped provenance so Rule #3 can detect
|
|
164
|
+
* sharp divergence in soul-distinct outcomes.
|
|
165
|
+
*/
|
|
166
|
+
export interface ProvenanceAuditEntry {
|
|
167
|
+
/** The provenance record itself (RFC-0009 §8.3 extended shape). */
|
|
168
|
+
record: ProvenanceRecord;
|
|
169
|
+
/** True iff the operator recorded a cross-tessellation amendment for this work item. */
|
|
170
|
+
amendmentRecorded?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Soul-distinct outcome readout, keyed by soulId. Only meaningful when
|
|
173
|
+
* `record.substrateScoped === true`. Values are caller-supplied outcome
|
|
174
|
+
* scores in [0, 1]; the detector flags when the spread exceeds
|
|
175
|
+
* `divergenceThreshold`.
|
|
176
|
+
*/
|
|
177
|
+
outcomeBySoul?: Record<string, number>;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Detector configuration. All fields optional with safe defaults; the only
|
|
181
|
+
* required toggle is `enabled` (default `false`, honoring RFC-0009 §10
|
|
182
|
+
* Phase 4 opt-in default).
|
|
183
|
+
*/
|
|
184
|
+
export interface TessellationDriftConfig {
|
|
185
|
+
/**
|
|
186
|
+
* Master opt-in switch. Per RFC-0009 §10 Phase 4 "All sub-dimension
|
|
187
|
+
* activations are gated on adopter opt-in initially". Default `false`;
|
|
188
|
+
* the detector short-circuits and emits nothing when disabled.
|
|
189
|
+
*/
|
|
190
|
+
enabled?: boolean;
|
|
191
|
+
/**
|
|
192
|
+
* Per-rule kill switches. Useful for staged rollout (e.g., enable rule
|
|
193
|
+
* #1 first, observe noise levels, then enable rule #3). Defaults: both
|
|
194
|
+
* `true` (subject to `enabled` master gate).
|
|
195
|
+
*/
|
|
196
|
+
rules?: {
|
|
197
|
+
astScan?: boolean;
|
|
198
|
+
crossSoulProvenance?: boolean;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Spread threshold for substrate-divergent-outcomes detection. When the
|
|
202
|
+
* max-min of `outcomeBySoul` values exceeds this number, the detector
|
|
203
|
+
* emits a `substrate-divergent-outcomes` finding. Defaults to 0.3 (a
|
|
204
|
+
* 30-point spread on a 0..1 outcome scale).
|
|
205
|
+
*/
|
|
206
|
+
divergenceThreshold?: number;
|
|
207
|
+
}
|
|
208
|
+
export declare const DEFAULT_DIVERGENCE_THRESHOLD = 0.3;
|
|
209
|
+
export interface TessellationDriftInput {
|
|
210
|
+
/** The Tessellated DID URI the scan runs against (for event provenance). */
|
|
211
|
+
tessellatedDid: string;
|
|
212
|
+
/** The tessellation manifest (souls + substrate invariants). */
|
|
213
|
+
tessellation: Tessellation;
|
|
214
|
+
/** Substrate file contents to scan with Rule #1. Empty/absent = rule #1 no-op. */
|
|
215
|
+
substrateFiles?: SubstrateFile[];
|
|
216
|
+
/** Provenance entries to scan with Rule #3. Empty/absent = rule #3 no-op. */
|
|
217
|
+
provenance?: ProvenanceAuditEntry[];
|
|
218
|
+
}
|
|
219
|
+
export interface TessellationDriftResult {
|
|
220
|
+
/** Every drift event emitted during this run (also forwarded to `emit`). */
|
|
221
|
+
events: TessellationDriftDetectedEvent[];
|
|
222
|
+
/** True when the detector short-circuited because `enabled === false`. */
|
|
223
|
+
optedOut: boolean;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Run Eτ_tessellation_drift detection against the supplied inputs.
|
|
227
|
+
*
|
|
228
|
+
* The detector is **read-only** — it does not mutate the tessellation,
|
|
229
|
+
* the provenance records, or the substrate files. It computes events and
|
|
230
|
+
* forwards each via the optional `emit` callback (callers wire this to
|
|
231
|
+
* `appendEvent(artifactsDir, ev)`).
|
|
232
|
+
*
|
|
233
|
+
* When `config.enabled !== true` the detector short-circuits immediately
|
|
234
|
+
* and returns `{ events: [], optedOut: true }`. This honors the RFC-0009
|
|
235
|
+
* §10 Phase 4 "adopter opt-in initially" convention; the detector exists
|
|
236
|
+
* in the surface but produces zero side effects until explicitly enabled.
|
|
237
|
+
*
|
|
238
|
+
* @param input Detection inputs (tessellation + optional substrate + provenance).
|
|
239
|
+
* @param config Detector configuration (master `enabled` flag + per-rule toggles).
|
|
240
|
+
* @param emit Optional event sink; called once per detected event. Errors
|
|
241
|
+
* from `emit` are propagated to the caller (intentional — the
|
|
242
|
+
* detector is sync-pure with respect to its inputs; the caller
|
|
243
|
+
* decides how to handle event-stream failures).
|
|
244
|
+
*/
|
|
245
|
+
export declare function detectTessellationDrift(input: TessellationDriftInput, config?: TessellationDriftConfig, emit?: (event: TessellationDriftDetectedEvent) => Promise<void> | void): Promise<TessellationDriftResult>;
|
|
246
|
+
//# sourceMappingURL=tessellation-drift.d.ts.map
|