@ai-sdlc/orchestrator 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/dist/admission-composite.d.ts +67 -0
  2. package/dist/admission-composite.js +158 -0
  3. package/dist/admission-enrichment.d.ts +142 -0
  4. package/dist/admission-enrichment.js +331 -0
  5. package/dist/admission-hc.d.ts +62 -0
  6. package/dist/admission-hc.js +83 -0
  7. package/dist/admission-score.d.ts +95 -5
  8. package/dist/admission-score.js +84 -11
  9. package/dist/analysis/analyzer.js +3 -2
  10. package/dist/analysis/convention-detector.d.ts +85 -2
  11. package/dist/analysis/convention-detector.js +375 -70
  12. package/dist/analysis/diff-analyzer.d.ts +33 -0
  13. package/dist/analysis/diff-analyzer.js +122 -0
  14. package/dist/analysis/hotspot-analyzer.js +3 -1
  15. package/dist/analysis/index.d.ts +2 -1
  16. package/dist/analysis/index.js +2 -1
  17. package/dist/artifacts/index.d.ts +65 -0
  18. package/dist/artifacts/index.js +142 -0
  19. package/dist/backlog-adapter.d.ts +121 -0
  20. package/dist/backlog-adapter.js +438 -0
  21. package/dist/calibration.d.ts +43 -0
  22. package/dist/calibration.js +76 -0
  23. package/dist/cli/commands/agents.d.ts +24 -0
  24. package/dist/cli/commands/agents.js +66 -1
  25. package/dist/cli/commands/git-remote.d.ts +49 -0
  26. package/dist/cli/commands/git-remote.js +91 -0
  27. package/dist/cli/commands/health.d.ts +4 -0
  28. package/dist/cli/commands/health.js +13 -1
  29. package/dist/cli/commands/init.d.ts +26 -0
  30. package/dist/cli/commands/init.js +164 -22
  31. package/dist/cli/commands/mcp-setup.d.ts +31 -0
  32. package/dist/cli/commands/mcp-setup.js +78 -8
  33. package/dist/cli/formatters/table.js +15 -2
  34. package/dist/cli/index.d.ts +14 -1
  35. package/dist/cli/index.js +81 -20
  36. package/dist/cli/versions.d.ts +57 -0
  37. package/dist/cli/versions.js +128 -0
  38. package/dist/code-area-classifier.d.ts +21 -0
  39. package/dist/code-area-classifier.js +48 -0
  40. package/dist/config.d.ts +33 -1
  41. package/dist/config.js +78 -8
  42. package/dist/database/adapters/external.d.ts +24 -0
  43. package/dist/database/adapters/external.js +80 -0
  44. package/dist/database/adapters/neon.d.ts +41 -0
  45. package/dist/database/adapters/neon.js +98 -0
  46. package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
  47. package/dist/database/adapters/pg-snapshot-restore.js +68 -0
  48. package/dist/database/adapters/sqlite-copy.d.ts +32 -0
  49. package/dist/database/adapters/sqlite-copy.js +145 -0
  50. package/dist/database/connection-injection.d.ts +35 -0
  51. package/dist/database/connection-injection.js +93 -0
  52. package/dist/database/index.d.ts +12 -0
  53. package/dist/database/index.js +23 -0
  54. package/dist/database/registry.d.ts +13 -0
  55. package/dist/database/registry.js +27 -0
  56. package/dist/database/topology.d.ts +52 -0
  57. package/dist/database/topology.js +44 -0
  58. package/dist/database/types.d.ts +89 -0
  59. package/dist/database/types.js +26 -0
  60. package/dist/design-authority.d.ts +40 -0
  61. package/dist/design-authority.js +71 -0
  62. package/dist/design-lookahead.d.ts +64 -0
  63. package/dist/design-lookahead.js +86 -0
  64. package/dist/design-quality-trend.d.ts +87 -0
  65. package/dist/design-quality-trend.js +190 -0
  66. package/dist/design-system-context.d.ts +46 -0
  67. package/dist/design-system-context.js +80 -0
  68. package/dist/design-system-correction-loop.d.ts +64 -0
  69. package/dist/design-system-correction-loop.js +128 -0
  70. package/dist/design-system-metrics.d.ts +61 -0
  71. package/dist/design-system-metrics.js +104 -0
  72. package/dist/design-system-stewardship.d.ts +22 -0
  73. package/dist/design-system-stewardship.js +85 -0
  74. package/dist/design-system-validation.d.ts +37 -0
  75. package/dist/design-system-validation.js +88 -0
  76. package/dist/dispatch/index.d.ts +4 -0
  77. package/dist/dispatch/index.js +4 -0
  78. package/dist/dispatch/merge-gate.d.ts +46 -0
  79. package/dist/dispatch/merge-gate.js +90 -0
  80. package/dist/dispatch/requeue.d.ts +57 -0
  81. package/dist/dispatch/requeue.js +131 -0
  82. package/dist/dispatch/worker-pool.d.ts +62 -0
  83. package/dist/dispatch/worker-pool.js +60 -0
  84. package/dist/execute.d.ts +40 -0
  85. package/dist/execute.js +185 -15
  86. package/dist/fix-ci.js +8 -1
  87. package/dist/fix-review.js +8 -1
  88. package/dist/harness/adapters/claude-code.d.ts +29 -0
  89. package/dist/harness/adapters/claude-code.js +191 -0
  90. package/dist/harness/adapters/codex.d.ts +25 -0
  91. package/dist/harness/adapters/codex.js +61 -0
  92. package/dist/harness/independence.d.ts +51 -0
  93. package/dist/harness/independence.js +67 -0
  94. package/dist/harness/index.d.ts +14 -0
  95. package/dist/harness/index.js +20 -0
  96. package/dist/harness/registry.d.ts +17 -0
  97. package/dist/harness/registry.js +31 -0
  98. package/dist/harness/types.d.ts +123 -0
  99. package/dist/harness/types.js +8 -0
  100. package/dist/harness/version-probe.d.ts +14 -0
  101. package/dist/harness/version-probe.js +123 -0
  102. package/dist/index.d.ts +30 -4
  103. package/dist/index.js +35 -2
  104. package/dist/models/classifier.d.ts +76 -0
  105. package/dist/models/classifier.js +221 -0
  106. package/dist/models/index.d.ts +3 -0
  107. package/dist/models/index.js +3 -0
  108. package/dist/models/registry.d.ts +97 -0
  109. package/dist/models/registry.js +173 -0
  110. package/dist/pillar-breakdown.d.ts +63 -0
  111. package/dist/pillar-breakdown.js +153 -0
  112. package/dist/priority.d.ts +5 -0
  113. package/dist/priority.js +18 -5
  114. package/dist/review-meta.d.ts +65 -0
  115. package/dist/review-meta.js +149 -0
  116. package/dist/review.d.ts +4 -0
  117. package/dist/review.js +12 -2
  118. package/dist/runners/claude-code-sdk.d.ts +31 -0
  119. package/dist/runners/claude-code-sdk.js +238 -0
  120. package/dist/runners/claude-code.d.ts +3 -0
  121. package/dist/runners/claude-code.js +30 -66
  122. package/dist/runners/codex.js +4 -1
  123. package/dist/runners/copilot.js +4 -1
  124. package/dist/runners/cursor.js +4 -1
  125. package/dist/runners/git-utils.d.ts +81 -0
  126. package/dist/runners/git-utils.js +201 -0
  127. package/dist/runners/index.d.ts +3 -0
  128. package/dist/runners/index.js +3 -0
  129. package/dist/runners/review-agent.d.ts +20 -0
  130. package/dist/runners/review-agent.js +171 -41
  131. package/dist/runners/runner-registry.js +10 -0
  132. package/dist/runners/sdk-review-runner.d.ts +65 -0
  133. package/dist/runners/sdk-review-runner.js +185 -0
  134. package/dist/runners/security-triage.d.ts +20 -4
  135. package/dist/runners/security-triage.js +39 -15
  136. package/dist/runners/types.d.ts +6 -0
  137. package/dist/runtime/attestations.d.ts +274 -0
  138. package/dist/runtime/attestations.js +460 -0
  139. package/dist/runtime/git-env.d.ts +53 -0
  140. package/dist/runtime/git-env.js +60 -0
  141. package/dist/runtime/index.d.ts +7 -0
  142. package/dist/runtime/index.js +7 -0
  143. package/dist/runtime/parallelism-flag.d.ts +10 -0
  144. package/dist/runtime/parallelism-flag.js +18 -0
  145. package/dist/runtime/port-allocator.d.ts +21 -0
  146. package/dist/runtime/port-allocator.js +66 -0
  147. package/dist/runtime/worktree-pool.d.ts +86 -0
  148. package/dist/runtime/worktree-pool.js +204 -0
  149. package/dist/runtime/worktree.d.ts +25 -0
  150. package/dist/runtime/worktree.js +111 -0
  151. package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
  152. package/dist/sa-scoring/auto-calibrate.js +107 -0
  153. package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
  154. package/dist/sa-scoring/c1-sa2-computable.js +59 -0
  155. package/dist/sa-scoring/composite.d.ts +107 -0
  156. package/dist/sa-scoring/composite.js +139 -0
  157. package/dist/sa-scoring/depparse-client.d.ts +79 -0
  158. package/dist/sa-scoring/depparse-client.js +187 -0
  159. package/dist/sa-scoring/did-compiler.d.ts +122 -0
  160. package/dist/sa-scoring/did-compiler.js +286 -0
  161. package/dist/sa-scoring/drift-monitor.d.ts +84 -0
  162. package/dist/sa-scoring/drift-monitor.js +186 -0
  163. package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
  164. package/dist/sa-scoring/exemplar-bank.js +154 -0
  165. package/dist/sa-scoring/feedback-store.d.ts +100 -0
  166. package/dist/sa-scoring/feedback-store.js +156 -0
  167. package/dist/sa-scoring/index.d.ts +71 -0
  168. package/dist/sa-scoring/index.js +158 -0
  169. package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
  170. package/dist/sa-scoring/layer1-deterministic.js +298 -0
  171. package/dist/sa-scoring/layer2-structural.d.ts +71 -0
  172. package/dist/sa-scoring/layer2-structural.js +151 -0
  173. package/dist/sa-scoring/layer3-llm.d.ts +86 -0
  174. package/dist/sa-scoring/layer3-llm.js +282 -0
  175. package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
  176. package/dist/sa-scoring/rescore-orchestrator.js +47 -0
  177. package/dist/scheduling/burn-down.d.ts +27 -0
  178. package/dist/scheduling/burn-down.js +43 -0
  179. package/dist/scheduling/calibration.d.ts +42 -0
  180. package/dist/scheduling/calibration.js +150 -0
  181. package/dist/scheduling/index.d.ts +8 -0
  182. package/dist/scheduling/index.js +8 -0
  183. package/dist/scheduling/ledger.d.ts +59 -0
  184. package/dist/scheduling/ledger.js +216 -0
  185. package/dist/scheduling/off-peak.d.ts +27 -0
  186. package/dist/scheduling/off-peak.js +112 -0
  187. package/dist/scheduling/schedule-decision.d.ts +39 -0
  188. package/dist/scheduling/schedule-decision.js +89 -0
  189. package/dist/scheduling/tier-analysis.d.ts +47 -0
  190. package/dist/scheduling/tier-analysis.js +81 -0
  191. package/dist/scheduling/types.d.ts +140 -0
  192. package/dist/scheduling/types.js +11 -0
  193. package/dist/shared.d.ts +13 -0
  194. package/dist/shared.js +32 -0
  195. package/dist/state/schema.d.ts +5 -1
  196. package/dist/state/schema.js +223 -1
  197. package/dist/state/store.d.ts +55 -1
  198. package/dist/state/store.js +342 -7
  199. package/dist/state/types.d.ts +139 -0
  200. package/dist/types.d.ts +1 -1
  201. package/dist/validate-agent-output.js +4 -1
  202. package/dist/watch.js +6 -0
  203. package/package.json +2 -2
@@ -0,0 +1,158 @@
1
+ /**
2
+ * SA scoring orchestration (RFC-0008 Addendum B §B.7.3).
3
+ *
4
+ * `scoreSoulAlignment(input, deps)` runs the three-layer SA scorer end
5
+ * to end with phase-aware short-circuits:
6
+ *
7
+ * - Layer 1 hard gate → skips Layer 2/3, SA-1 forced to 0
8
+ * - Phase 2a shadow → all layers computed + persisted, but
9
+ * shadowMode=true signals caller to use
10
+ * label-based soulAlignment in ranking
11
+ * - Phase 2b/2c/3 → sa1 replaces label-based soulAlignment
12
+ *
13
+ * Persists one `did_scoring_events` row per dimension so operators can
14
+ * query per-dimension precision by phase.
15
+ */
16
+ import { compileDid } from './did-compiler.js';
17
+ import { runLayer1 } from './layer1-deterministic.js';
18
+ import { computeDomainRelevance, computePrincipleCoverage, } from './layer2-structural.js';
19
+ import { runLayer3 } from './layer3-llm.js';
20
+ import { computeSoulAlignment, } from './composite.js';
21
+ // ── Orchestration ───────────────────────────────────────────────────
22
+ export async function scoreSoulAlignment(input, deps) {
23
+ const compiled = deps.compiledDid ?? compileDid(input.did);
24
+ // ── Layer 1 (deterministic) ────────────────────────────────────
25
+ const layer1 = await runLayer1({
26
+ issueText: input.issueText,
27
+ compiled,
28
+ depparse: deps.depparse,
29
+ observedMetrics: input.observedMetrics,
30
+ });
31
+ // ── Layer 2 (BM25 structural) ──────────────────────────────────
32
+ // Always compute, even in shadow mode, so precision tracking works.
33
+ const domainRelevance = computeDomainRelevance(input.issueText, compiled.bm25Corpus);
34
+ const principleCoverage = computePrincipleCoverage(input.issueText, compiled.principleCorpora);
35
+ // ── Layer 3 (LLM) ──────────────────────────────────────────────
36
+ // Skip Layer 3 if hard-gated — SA-1 = 0 short-circuits regardless
37
+ // of what the LLM might say. Matches §B.7.1 STOP condition.
38
+ let layer3;
39
+ if (!layer1.hardGated) {
40
+ layer3 = await runLayer3({
41
+ issueText: input.issueText,
42
+ did: input.did,
43
+ dsb: input.dsb,
44
+ preVerifiedSummary: layer1.preVerifiedSummary,
45
+ llm: deps.llm,
46
+ });
47
+ }
48
+ // ── DSB-derived computable inputs for SA-2 ────────────────────
49
+ const tokenCompliance = input.dsb?.status?.tokenCompliance?.currentCoverage ?? 0;
50
+ const catalogHealth = input.dsb?.status?.catalogHealth?.coveragePercent ?? 0;
51
+ // Count design anti-pattern hits for SA-2 conflict penalty.
52
+ const coreDesignAntiPatternCount = layer1.designAntiPatternHits.hits.filter((h) => h.identityClass === 'core').length;
53
+ const evolvingDesignAntiPatternCount = layer1.designAntiPatternHits.hits.filter((h) => h.identityClass === 'evolving').length;
54
+ // ── Composite ─────────────────────────────────────────────────
55
+ const composite = computeSoulAlignment({
56
+ phase: input.phase,
57
+ calibratedWeights: input.calibratedWeights,
58
+ sa1: {
59
+ hardGated: layer1.hardGated,
60
+ coreViolationCount: layer1.coreViolationCount,
61
+ evolvingViolationCount: layer1.evolvingViolationCount,
62
+ domainRelevance: domainRelevance.score,
63
+ domainIntent: layer3?.domainIntent ?? 0,
64
+ subtleConflicts: layer3?.subtleConflicts ?? [],
65
+ },
66
+ sa2: {
67
+ tokenCompliance,
68
+ catalogHealth,
69
+ principleCoverage: principleCoverage.overallCoverage,
70
+ principleAlignment: layer3?.principleAlignment ?? 0,
71
+ coreDesignAntiPatternCount,
72
+ evolvingDesignAntiPatternCount,
73
+ subtleDesignConflicts: layer3?.subtleDesignConflicts ?? [],
74
+ },
75
+ });
76
+ // ── Persist to did_scoring_events (one row per dimension) ─────
77
+ if (deps.stateStore && input.issueNumber !== undefined) {
78
+ persistScoringEvent(deps.stateStore, {
79
+ didName: input.did.metadata.name,
80
+ issueNumber: input.issueNumber,
81
+ dimension: 'SA-1',
82
+ phase: input.phase,
83
+ weights: composite.weights,
84
+ layer1,
85
+ layer2: domainRelevance,
86
+ layer3Sa1: layer3
87
+ ? {
88
+ domainIntent: layer3.domainIntent,
89
+ domainIntentConfidence: layer3.domainIntentConfidence,
90
+ subtleConflicts: layer3.subtleConflicts,
91
+ }
92
+ : undefined,
93
+ compositeScore: composite.sa1.sa1,
94
+ });
95
+ persistScoringEvent(deps.stateStore, {
96
+ didName: input.did.metadata.name,
97
+ issueNumber: input.issueNumber,
98
+ dimension: 'SA-2',
99
+ phase: input.phase,
100
+ weights: composite.weights,
101
+ layer1,
102
+ layer2: principleCoverage,
103
+ layer3Sa2: layer3
104
+ ? {
105
+ principleAlignment: layer3.principleAlignment,
106
+ principleAlignmentConfidence: layer3.principleAlignmentConfidence,
107
+ subtleDesignConflicts: layer3.subtleDesignConflicts,
108
+ }
109
+ : undefined,
110
+ compositeScore: composite.sa2.sa2,
111
+ });
112
+ }
113
+ return {
114
+ sa1: composite.sa1.sa1,
115
+ sa2: composite.sa2.sa2,
116
+ composite,
117
+ layer1,
118
+ layer2: { domainRelevance, principleCoverage },
119
+ layer3,
120
+ shadowMode: composite.shadowMode,
121
+ phase: input.phase,
122
+ weights: composite.weights,
123
+ };
124
+ }
125
+ function persistScoringEvent(store, input) {
126
+ const layer1Summary = {
127
+ hardGated: input.layer1.hardGated,
128
+ coreViolationCount: input.layer1.coreViolationCount,
129
+ evolvingViolationCount: input.layer1.evolvingViolationCount,
130
+ scopeOutOfScopeHits: input.layer1.scopeGate.outOfScopeHits.length,
131
+ constraintViolations: input.layer1.constraintViolations.violations.length,
132
+ antiPatternHits: input.layer1.antiPatternHits.hits.length + input.layer1.designAntiPatternHits.hits.length,
133
+ };
134
+ const layer3Payload = input.layer3Sa1 ?? input.layer3Sa2;
135
+ store.recordDidScoringEvent({
136
+ didName: input.didName,
137
+ issueNumber: input.issueNumber,
138
+ saDimension: input.dimension,
139
+ phase: input.phase,
140
+ layer1ResultJson: JSON.stringify(layer1Summary),
141
+ layer2ResultJson: JSON.stringify(input.layer2),
142
+ layer3ResultJson: layer3Payload ? JSON.stringify(layer3Payload) : undefined,
143
+ compositeScore: input.compositeScore,
144
+ phaseWeightsJson: JSON.stringify(input.weights),
145
+ });
146
+ }
147
+ // ── Admission-composite integration helpers ──────────────────────────
148
+ /**
149
+ * Resolve the soulAlignment value to feed the admission composite
150
+ * based on phase + SA result. In shadow mode (2a), returns undefined
151
+ * so the caller falls back to the label-based heuristic.
152
+ */
153
+ export function resolveSoulAlignmentOverride(result) {
154
+ if (result.shadowMode)
155
+ return undefined;
156
+ return result.sa1;
157
+ }
158
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Layer 1 — Deterministic SA scorer (RFC-0008 Addendum B §B.4).
3
+ *
4
+ * Consumes a `CompiledDid` + issue text + state store metrics and
5
+ * produces a fully-deterministic scoring result. Layer 1 never makes
6
+ * network or LLM calls *except* for the dep-parse sidecar (for
7
+ * requirement-construction detection).
8
+ *
9
+ * A `core` out-of-scope match is a **hard gate** — downstream SA-1
10
+ * scoring must treat `hardGated=true` as SA-1 = 0.0 regardless of
11
+ * Layer 2/3 output. Evolving matches surface as warnings but do not
12
+ * gate admission.
13
+ */
14
+ import type { CompiledDid } from './did-compiler.js';
15
+ import type { DepparseClient } from './depparse-client.js';
16
+ export interface ScopeGateMatch {
17
+ label: string;
18
+ synonym?: string;
19
+ identityClass: 'core' | 'evolving';
20
+ matchedText: string;
21
+ }
22
+ export interface ScopeGateResult {
23
+ inScopeHits: ScopeGateMatch[];
24
+ outOfScopeHits: ScopeGateMatch[];
25
+ /** True when a core out-of-scope term matched (hard gate). */
26
+ hardGated: boolean;
27
+ /** Warnings for evolving out-of-scope hits (soft gate). */
28
+ warnings: string[];
29
+ }
30
+ export interface ConstraintViolation {
31
+ constraintId: string;
32
+ concept: string;
33
+ relationship: string;
34
+ pattern: string;
35
+ matchedText: string;
36
+ construction?: string;
37
+ depPath?: string[];
38
+ identityClass: 'core' | 'evolving';
39
+ }
40
+ export interface ConstraintViolationResult {
41
+ violations: ConstraintViolation[];
42
+ /** True when the depparse sidecar was unavailable (fail-soft skip). */
43
+ depparseSkipped: boolean;
44
+ }
45
+ export interface AntiPatternHit {
46
+ id: string;
47
+ label: string;
48
+ pattern: string;
49
+ matchedText: string;
50
+ identityClass: 'core' | 'evolving';
51
+ scope: 'product' | 'design-principle' | 'voice' | 'visual';
52
+ /** Present only for scope='design-principle'. */
53
+ principleId?: string;
54
+ }
55
+ export interface AntiPatternResult {
56
+ hits: AntiPatternHit[];
57
+ }
58
+ export type MeasurableSignalStatus = 'pass' | 'fail' | 'missing';
59
+ export interface MeasurableSignalCheck {
60
+ id: string;
61
+ metric: string;
62
+ threshold: number;
63
+ operator: string;
64
+ observedValue?: number;
65
+ status: MeasurableSignalStatus;
66
+ identityClass: 'core' | 'evolving';
67
+ }
68
+ export interface MeasurableSignalResult {
69
+ checks: MeasurableSignalCheck[];
70
+ /** Count of signals with status='fail' on a core-classified signal. */
71
+ coreFailureCount: number;
72
+ }
73
+ export interface DeterministicScoringResult {
74
+ scopeGate: ScopeGateResult;
75
+ constraintViolations: ConstraintViolationResult;
76
+ antiPatternHits: AntiPatternResult;
77
+ designAntiPatternHits: AntiPatternResult;
78
+ measurableSignalChecks: MeasurableSignalResult;
79
+ /** Shortcut — true when the scope gate (core) fails. */
80
+ hardGated: boolean;
81
+ /** Total count of `core` violations across all sources. */
82
+ coreViolationCount: number;
83
+ /** Total count of `evolving` violations across all sources. */
84
+ evolvingViolationCount: number;
85
+ /** Human-readable pre-verified summary for Layer 3 prompt injection. */
86
+ preVerifiedSummary: string;
87
+ }
88
+ export declare function checkScopeGate(issueText: string, compiled: CompiledDid): ScopeGateResult;
89
+ export declare function detectConstraintViolations(issueText: string, compiled: CompiledDid, client: DepparseClient): Promise<ConstraintViolationResult>;
90
+ export declare function detectAntiPatterns(issueText: string, compiled: CompiledDid): {
91
+ product: AntiPatternResult;
92
+ design: AntiPatternResult;
93
+ };
94
+ export declare function checkMeasurableSignals(observed: Record<string, number>, compiled: CompiledDid): MeasurableSignalResult;
95
+ export interface Layer1Input {
96
+ issueText: string;
97
+ compiled: CompiledDid;
98
+ depparse: DepparseClient;
99
+ /** Observed metric values keyed by signal metric name. */
100
+ observedMetrics?: Record<string, number>;
101
+ }
102
+ export declare function runLayer1(input: Layer1Input): Promise<DeterministicScoringResult>;
103
+ interface SummaryInput {
104
+ scopeGate: ScopeGateResult;
105
+ constraintViolations: ConstraintViolationResult;
106
+ product: AntiPatternResult;
107
+ design: AntiPatternResult;
108
+ measurable: MeasurableSignalResult;
109
+ hardGated: boolean;
110
+ coreViolationCount: number;
111
+ evolvingViolationCount: number;
112
+ }
113
+ export declare function renderPreVerifiedSummary(input: SummaryInput): string;
114
+ export {};
115
+ //# sourceMappingURL=layer1-deterministic.d.ts.map
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Layer 1 — Deterministic SA scorer (RFC-0008 Addendum B §B.4).
3
+ *
4
+ * Consumes a `CompiledDid` + issue text + state store metrics and
5
+ * produces a fully-deterministic scoring result. Layer 1 never makes
6
+ * network or LLM calls *except* for the dep-parse sidecar (for
7
+ * requirement-construction detection).
8
+ *
9
+ * A `core` out-of-scope match is a **hard gate** — downstream SA-1
10
+ * scoring must treat `hardGated=true` as SA-1 = 0.0 regardless of
11
+ * Layer 2/3 output. Evolving matches surface as warnings but do not
12
+ * gate admission.
13
+ */
14
+ import { DepparseError } from './depparse-client.js';
15
+ // ── Tokenization / matching ──────────────────────────────────────────
16
+ function lower(s) {
17
+ return s.toLowerCase();
18
+ }
19
+ function includesWhole(haystack, needle) {
20
+ if (!needle)
21
+ return false;
22
+ // Whole-word-ish match: bounds on non-alphanumeric.
23
+ const re = new RegExp(`(^|[^a-z0-9])${escapeRegex(lower(needle))}($|[^a-z0-9])`, 'i');
24
+ return re.test(haystack);
25
+ }
26
+ function escapeRegex(s) {
27
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
28
+ }
29
+ // ── Scope gate ───────────────────────────────────────────────────────
30
+ export function checkScopeGate(issueText, compiled) {
31
+ const text = lower(issueText);
32
+ const inHits = [];
33
+ const outHits = [];
34
+ const warnings = [];
35
+ let hardGated = false;
36
+ for (const entry of compiled.scopeLists.inScope) {
37
+ const all = [entry.label, ...entry.synonyms];
38
+ for (const term of all) {
39
+ if (includesWhole(text, term)) {
40
+ inHits.push({
41
+ label: entry.label,
42
+ synonym: term === entry.label ? undefined : term,
43
+ identityClass: entry.identityClass,
44
+ matchedText: term,
45
+ });
46
+ break;
47
+ }
48
+ }
49
+ }
50
+ for (const entry of compiled.scopeLists.outOfScope) {
51
+ const all = [entry.label, ...entry.synonyms];
52
+ for (const term of all) {
53
+ if (includesWhole(text, term)) {
54
+ outHits.push({
55
+ label: entry.label,
56
+ synonym: term === entry.label ? undefined : term,
57
+ identityClass: entry.identityClass,
58
+ matchedText: term,
59
+ });
60
+ if (entry.identityClass === 'core') {
61
+ hardGated = true;
62
+ }
63
+ else {
64
+ warnings.push(`Evolving out-of-scope match: "${entry.label}" via "${term}"`);
65
+ }
66
+ break;
67
+ }
68
+ }
69
+ }
70
+ return { inScopeHits: inHits, outOfScopeHits: outHits, hardGated, warnings };
71
+ }
72
+ // ── Constraint violations (via depparse sidecar) ─────────────────────
73
+ export async function detectConstraintViolations(issueText, compiled, client) {
74
+ const violations = [];
75
+ let depparseSkipped = false;
76
+ for (const rule of compiled.constraintRules) {
77
+ // Only enforce `must-not-require` / `must-not-include` via depparse;
78
+ // `must-require` / `must-include` are positive constraints (enforced
79
+ // downstream as signal requirements, not as violation checks).
80
+ if (rule.relationship !== 'must-not-require' && rule.relationship !== 'must-not-include') {
81
+ continue;
82
+ }
83
+ let response;
84
+ try {
85
+ response = await client.match({
86
+ text: issueText,
87
+ patterns: rule.detectionPatterns,
88
+ });
89
+ }
90
+ catch (err) {
91
+ if (err instanceof DepparseError &&
92
+ (err.kind === 'model-unavailable' || err.kind === 'network' || err.kind === 'timeout')) {
93
+ depparseSkipped = true;
94
+ continue;
95
+ }
96
+ throw err;
97
+ }
98
+ for (const match of response.matches) {
99
+ violations.push(buildViolation(rule, match));
100
+ }
101
+ }
102
+ return { violations, depparseSkipped };
103
+ }
104
+ function buildViolation(rule, match) {
105
+ return {
106
+ constraintId: rule.id,
107
+ concept: rule.concept,
108
+ relationship: rule.relationship,
109
+ pattern: match.pattern,
110
+ matchedText: match.matchedText,
111
+ construction: match.construction,
112
+ depPath: match.depPath,
113
+ identityClass: rule.identityClass,
114
+ };
115
+ }
116
+ // ── Anti-pattern matching ────────────────────────────────────────────
117
+ function matchAntiPatterns(text, list, scope, principleId) {
118
+ const hits = [];
119
+ for (const ap of list) {
120
+ for (const pattern of ap.detectionPatterns) {
121
+ if (includesWhole(text, pattern)) {
122
+ hits.push({
123
+ id: ap.id,
124
+ label: ap.label,
125
+ pattern,
126
+ matchedText: pattern,
127
+ identityClass: ap.identityClass,
128
+ scope,
129
+ ...(principleId ? { principleId } : {}),
130
+ });
131
+ }
132
+ }
133
+ }
134
+ return hits;
135
+ }
136
+ export function detectAntiPatterns(issueText, compiled) {
137
+ const text = lower(issueText);
138
+ const productHits = matchAntiPatterns(text, compiled.antiPatternLists.product, 'product');
139
+ const designHits = [];
140
+ for (const [principleId, list] of Object.entries(compiled.antiPatternLists.perPrinciple)) {
141
+ designHits.push(...matchAntiPatterns(text, list, 'design-principle', principleId));
142
+ }
143
+ designHits.push(...matchAntiPatterns(text, compiled.antiPatternLists.voice, 'voice'));
144
+ designHits.push(...matchAntiPatterns(text, compiled.antiPatternLists.visual, 'visual'));
145
+ return {
146
+ product: { hits: productHits },
147
+ design: { hits: designHits },
148
+ };
149
+ }
150
+ // ── Measurable signal checks ─────────────────────────────────────────
151
+ export function checkMeasurableSignals(observed, compiled) {
152
+ const checks = [];
153
+ let coreFailureCount = 0;
154
+ for (const signal of compiled.measurableSignals) {
155
+ const value = observed[signal.metric];
156
+ let status;
157
+ if (value === undefined || Number.isNaN(value)) {
158
+ status = 'missing';
159
+ }
160
+ else {
161
+ status = evaluateOperator(value, signal.threshold, signal.operator) ? 'pass' : 'fail';
162
+ }
163
+ checks.push({
164
+ id: signal.id,
165
+ metric: signal.metric,
166
+ threshold: signal.threshold,
167
+ operator: signal.operator,
168
+ observedValue: value,
169
+ status,
170
+ identityClass: signal.identityClass,
171
+ });
172
+ if (status === 'fail' && signal.identityClass === 'core')
173
+ coreFailureCount++;
174
+ }
175
+ return { checks, coreFailureCount };
176
+ }
177
+ function evaluateOperator(value, threshold, operator) {
178
+ switch (operator) {
179
+ case 'gte':
180
+ return value >= threshold;
181
+ case 'lte':
182
+ return value <= threshold;
183
+ case 'gt':
184
+ return value > threshold;
185
+ case 'lt':
186
+ return value < threshold;
187
+ case 'eq':
188
+ return value === threshold;
189
+ case 'neq':
190
+ return value !== threshold;
191
+ default:
192
+ return false;
193
+ }
194
+ }
195
+ export async function runLayer1(input) {
196
+ const { issueText, compiled, depparse, observedMetrics = {} } = input;
197
+ const scopeGate = checkScopeGate(issueText, compiled);
198
+ const constraintViolations = await detectConstraintViolations(issueText, compiled, depparse);
199
+ const { product, design } = detectAntiPatterns(issueText, compiled);
200
+ const measurable = checkMeasurableSignals(observedMetrics, compiled);
201
+ // Count core vs evolving violations across all dimensions.
202
+ let coreViolationCount = 0;
203
+ let evolvingViolationCount = 0;
204
+ const bump = (ic) => {
205
+ if (ic === 'core')
206
+ coreViolationCount++;
207
+ else
208
+ evolvingViolationCount++;
209
+ };
210
+ for (const hit of scopeGate.outOfScopeHits)
211
+ bump(hit.identityClass);
212
+ for (const v of constraintViolations.violations)
213
+ bump(v.identityClass);
214
+ for (const h of product.hits)
215
+ bump(h.identityClass);
216
+ for (const h of design.hits)
217
+ bump(h.identityClass);
218
+ coreViolationCount += measurable.coreFailureCount;
219
+ const hardGated = scopeGate.hardGated;
220
+ const preVerifiedSummary = renderPreVerifiedSummary({
221
+ scopeGate,
222
+ constraintViolations,
223
+ product,
224
+ design,
225
+ measurable,
226
+ hardGated,
227
+ coreViolationCount,
228
+ evolvingViolationCount,
229
+ });
230
+ return {
231
+ scopeGate,
232
+ constraintViolations,
233
+ antiPatternHits: product,
234
+ designAntiPatternHits: design,
235
+ measurableSignalChecks: measurable,
236
+ hardGated,
237
+ coreViolationCount,
238
+ evolvingViolationCount,
239
+ preVerifiedSummary,
240
+ };
241
+ }
242
+ export function renderPreVerifiedSummary(input) {
243
+ const lines = [];
244
+ lines.push('## Deterministic verification');
245
+ lines.push('');
246
+ lines.push(`- Hard gated: ${input.hardGated ? 'yes' : 'no'}`);
247
+ lines.push(`- Core violations: ${input.coreViolationCount}`);
248
+ lines.push(`- Evolving violations: ${input.evolvingViolationCount}`);
249
+ lines.push('');
250
+ lines.push('### Scope gate');
251
+ if (input.scopeGate.outOfScopeHits.length === 0) {
252
+ lines.push('- No out-of-scope hits');
253
+ }
254
+ else {
255
+ for (const hit of input.scopeGate.outOfScopeHits) {
256
+ lines.push(`- ${hit.identityClass} OUT — "${hit.label}"` +
257
+ (hit.synonym ? ` via "${hit.synonym}"` : ''));
258
+ }
259
+ }
260
+ lines.push('');
261
+ lines.push('### Constraint violations');
262
+ if (input.constraintViolations.violations.length === 0) {
263
+ lines.push('- None detected');
264
+ if (input.constraintViolations.depparseSkipped) {
265
+ lines.push('- (depparse sidecar unavailable — skipped)');
266
+ }
267
+ }
268
+ else {
269
+ for (const v of input.constraintViolations.violations) {
270
+ lines.push(`- ${v.identityClass} ${v.constraintId} (${v.relationship} ${v.concept}) — "${v.matchedText}"` +
271
+ (v.construction ? ` via ${v.construction}` : ''));
272
+ }
273
+ }
274
+ lines.push('');
275
+ lines.push('### Anti-pattern hits');
276
+ const allAntiHits = [...input.product.hits, ...input.design.hits];
277
+ if (allAntiHits.length === 0) {
278
+ lines.push('- None detected');
279
+ }
280
+ else {
281
+ for (const h of allAntiHits) {
282
+ lines.push(`- ${h.identityClass} [${h.scope}${h.principleId ? `:${h.principleId}` : ''}] ${h.label} — "${h.matchedText}"`);
283
+ }
284
+ }
285
+ lines.push('');
286
+ lines.push('### Measurable signals');
287
+ const failures = input.measurable.checks.filter((c) => c.status === 'fail');
288
+ if (failures.length === 0) {
289
+ lines.push('- No failing signals');
290
+ }
291
+ else {
292
+ for (const c of failures) {
293
+ lines.push(`- ${c.identityClass} ${c.id} (${c.metric} ${c.operator} ${c.threshold}) — observed ${c.observedValue ?? 'n/a'}`);
294
+ }
295
+ }
296
+ return lines.join('\n');
297
+ }
298
+ //# sourceMappingURL=layer1-deterministic.js.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Layer 2 — Structural BM25 scorer (RFC-0008 Addendum B §B.5).
3
+ *
4
+ * computeDomainRelevance(issueText, bm25Corpus) → SA-1 [0, 1]
5
+ * computePrincipleCoverage(issueText, principleCorpora) → SA-2 vector
6
+ *
7
+ * Uses a minimal in-process BM25 implementation — no external index
8
+ * library needed. The corpus is tokenized at compile time
9
+ * (`did-compiler.ts`), so scoring is O(|query| × |corpus|) per call.
10
+ *
11
+ * Determinism: pure functions, no randomness, arithmetic-only. Same
12
+ * inputs → bit-exact outputs.
13
+ */
14
+ import type { Bm25Corpus, PrincipleCorpora } from './did-compiler.js';
15
+ interface Bm25Index {
16
+ /** The weighted-document list — each carries its own TF map + length. */
17
+ docs: Array<{
18
+ id: string;
19
+ weight: number;
20
+ length: number;
21
+ termFreq: Map<string, number>;
22
+ }>;
23
+ /** Number of documents that contain each term (for IDF). */
24
+ docFreq: Map<string, number>;
25
+ /** Average document length (weighted). */
26
+ avgDocLength: number;
27
+ }
28
+ declare function buildIndex(corpus: Bm25Corpus): Bm25Index;
29
+ declare function idf(term: string, index: Bm25Index): number;
30
+ declare function scoreDoc(queryTokens: readonly string[], doc: Bm25Index['docs'][number], index: Bm25Index): {
31
+ score: number;
32
+ termContributions: Map<string, number>;
33
+ };
34
+ declare function normalizeScore(rawScore: number): number;
35
+ declare function topTerms(contributions: Map<string, number>, limit: number): ContributingTerm[];
36
+ export interface ContributingTerm {
37
+ term: string;
38
+ score: number;
39
+ }
40
+ export interface DomainRelevanceResult {
41
+ /** Normalized relevance in [0, 1]. */
42
+ score: number;
43
+ /** Raw BM25 sum before normalization (for debugging / calibration). */
44
+ rawScore: number;
45
+ /** Top contributing terms, sorted by contribution score. */
46
+ contributingTerms: ContributingTerm[];
47
+ /** Number of query tokens after stopword stripping. */
48
+ queryLength: number;
49
+ }
50
+ export interface PrincipleCoverageEntry {
51
+ principleId: string;
52
+ coverage: number;
53
+ identityClass: 'core' | 'evolving';
54
+ contributingTerms: ContributingTerm[];
55
+ }
56
+ export interface PrincipleCoverageVector {
57
+ principles: PrincipleCoverageEntry[];
58
+ /** Weighted mean — core principles count twice, evolving once. */
59
+ overallCoverage: number;
60
+ }
61
+ export declare function computeDomainRelevance(issueText: string, corpus: Bm25Corpus): DomainRelevanceResult;
62
+ export declare function computePrincipleCoverage(issueText: string, principleCorpora: PrincipleCorpora): PrincipleCoverageVector;
63
+ export declare const __internals: {
64
+ buildIndex: typeof buildIndex;
65
+ idf: typeof idf;
66
+ scoreDoc: typeof scoreDoc;
67
+ normalizeScore: typeof normalizeScore;
68
+ topTerms: typeof topTerms;
69
+ };
70
+ export {};
71
+ //# sourceMappingURL=layer2-structural.d.ts.map