@ai-sdlc/orchestrator 0.6.0 → 0.10.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 (209) hide show
  1. package/dist/__test-helpers/git-env.d.ts +40 -0
  2. package/dist/__test-helpers/git-env.js +73 -0
  3. package/dist/admission-composite.d.ts +89 -0
  4. package/dist/admission-composite.js +241 -0
  5. package/dist/admission-enrichment.d.ts +142 -0
  6. package/dist/admission-enrichment.js +341 -0
  7. package/dist/admission-hc.d.ts +81 -0
  8. package/dist/admission-hc.js +94 -0
  9. package/dist/admission-score.d.ts +109 -5
  10. package/dist/admission-score.js +90 -11
  11. package/dist/analysis/analyzer.js +3 -2
  12. package/dist/analysis/convention-detector.d.ts +85 -2
  13. package/dist/analysis/convention-detector.js +375 -70
  14. package/dist/analysis/diff-analyzer.d.ts +33 -0
  15. package/dist/analysis/diff-analyzer.js +122 -0
  16. package/dist/analysis/hotspot-analyzer.js +3 -1
  17. package/dist/analysis/index.d.ts +2 -1
  18. package/dist/analysis/index.js +2 -1
  19. package/dist/artifacts/index.d.ts +65 -0
  20. package/dist/artifacts/index.js +142 -0
  21. package/dist/backlog-adapter.d.ts +121 -0
  22. package/dist/backlog-adapter.js +438 -0
  23. package/dist/calibration.d.ts +43 -0
  24. package/dist/calibration.js +76 -0
  25. package/dist/cli/commands/agents.d.ts +24 -0
  26. package/dist/cli/commands/agents.js +66 -1
  27. package/dist/cli/commands/git-remote.d.ts +74 -0
  28. package/dist/cli/commands/git-remote.js +170 -0
  29. package/dist/cli/commands/health.d.ts +4 -0
  30. package/dist/cli/commands/health.js +13 -1
  31. package/dist/cli/commands/init-features.d.ts +208 -0
  32. package/dist/cli/commands/init-features.js +473 -0
  33. package/dist/cli/commands/init-templates.d.ts +104 -0
  34. package/dist/cli/commands/init-templates.js +399 -0
  35. package/dist/cli/commands/init.d.ts +48 -0
  36. package/dist/cli/commands/init.js +322 -23
  37. package/dist/cli/commands/mcp-setup.d.ts +31 -0
  38. package/dist/cli/commands/mcp-setup.js +78 -8
  39. package/dist/cli/formatters/table.js +15 -2
  40. package/dist/cli/index.d.ts +14 -1
  41. package/dist/cli/index.js +81 -20
  42. package/dist/cli/versions.d.ts +57 -0
  43. package/dist/cli/versions.js +128 -0
  44. package/dist/code-area-classifier.d.ts +21 -0
  45. package/dist/code-area-classifier.js +48 -0
  46. package/dist/config.d.ts +33 -1
  47. package/dist/config.js +78 -8
  48. package/dist/database/adapters/external.d.ts +24 -0
  49. package/dist/database/adapters/external.js +80 -0
  50. package/dist/database/adapters/neon.d.ts +41 -0
  51. package/dist/database/adapters/neon.js +98 -0
  52. package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
  53. package/dist/database/adapters/pg-snapshot-restore.js +68 -0
  54. package/dist/database/adapters/sqlite-copy.d.ts +32 -0
  55. package/dist/database/adapters/sqlite-copy.js +145 -0
  56. package/dist/database/connection-injection.d.ts +35 -0
  57. package/dist/database/connection-injection.js +93 -0
  58. package/dist/database/index.d.ts +12 -0
  59. package/dist/database/index.js +23 -0
  60. package/dist/database/registry.d.ts +13 -0
  61. package/dist/database/registry.js +27 -0
  62. package/dist/database/topology.d.ts +52 -0
  63. package/dist/database/topology.js +44 -0
  64. package/dist/database/types.d.ts +89 -0
  65. package/dist/database/types.js +26 -0
  66. package/dist/design-authority.d.ts +53 -0
  67. package/dist/design-authority.js +84 -0
  68. package/dist/design-lookahead.d.ts +64 -0
  69. package/dist/design-lookahead.js +86 -0
  70. package/dist/design-quality-trend.d.ts +87 -0
  71. package/dist/design-quality-trend.js +190 -0
  72. package/dist/design-system-context.d.ts +46 -0
  73. package/dist/design-system-context.js +80 -0
  74. package/dist/design-system-correction-loop.d.ts +64 -0
  75. package/dist/design-system-correction-loop.js +128 -0
  76. package/dist/design-system-metrics.d.ts +61 -0
  77. package/dist/design-system-metrics.js +104 -0
  78. package/dist/design-system-stewardship.d.ts +22 -0
  79. package/dist/design-system-stewardship.js +85 -0
  80. package/dist/design-system-validation.d.ts +37 -0
  81. package/dist/design-system-validation.js +88 -0
  82. package/dist/dispatch/index.d.ts +4 -0
  83. package/dist/dispatch/index.js +4 -0
  84. package/dist/dispatch/merge-gate.d.ts +46 -0
  85. package/dist/dispatch/merge-gate.js +90 -0
  86. package/dist/dispatch/requeue.d.ts +57 -0
  87. package/dist/dispatch/requeue.js +131 -0
  88. package/dist/dispatch/worker-pool.d.ts +62 -0
  89. package/dist/dispatch/worker-pool.js +60 -0
  90. package/dist/execute.d.ts +40 -0
  91. package/dist/execute.js +188 -15
  92. package/dist/fix-ci.js +8 -1
  93. package/dist/fix-review.js +8 -1
  94. package/dist/harness/adapters/claude-code.d.ts +29 -0
  95. package/dist/harness/adapters/claude-code.js +191 -0
  96. package/dist/harness/adapters/codex.d.ts +25 -0
  97. package/dist/harness/adapters/codex.js +61 -0
  98. package/dist/harness/independence.d.ts +51 -0
  99. package/dist/harness/independence.js +67 -0
  100. package/dist/harness/index.d.ts +14 -0
  101. package/dist/harness/index.js +20 -0
  102. package/dist/harness/registry.d.ts +17 -0
  103. package/dist/harness/registry.js +31 -0
  104. package/dist/harness/types.d.ts +123 -0
  105. package/dist/harness/types.js +8 -0
  106. package/dist/harness/version-probe.d.ts +14 -0
  107. package/dist/harness/version-probe.js +123 -0
  108. package/dist/index.d.ts +30 -4
  109. package/dist/index.js +35 -2
  110. package/dist/models/classifier.d.ts +78 -0
  111. package/dist/models/classifier.js +277 -0
  112. package/dist/models/index.d.ts +3 -0
  113. package/dist/models/index.js +3 -0
  114. package/dist/models/registry.d.ts +97 -0
  115. package/dist/models/registry.js +173 -0
  116. package/dist/pillar-breakdown.d.ts +85 -0
  117. package/dist/pillar-breakdown.js +162 -0
  118. package/dist/priority.d.ts +5 -0
  119. package/dist/priority.js +18 -5
  120. package/dist/review-meta.d.ts +65 -0
  121. package/dist/review-meta.js +149 -0
  122. package/dist/review.d.ts +4 -0
  123. package/dist/review.js +12 -2
  124. package/dist/runners/claude-code-sdk.d.ts +31 -0
  125. package/dist/runners/claude-code-sdk.js +238 -0
  126. package/dist/runners/claude-code.d.ts +3 -0
  127. package/dist/runners/claude-code.js +30 -66
  128. package/dist/runners/codex.js +4 -1
  129. package/dist/runners/copilot.js +4 -1
  130. package/dist/runners/cursor.js +4 -1
  131. package/dist/runners/git-utils.d.ts +81 -0
  132. package/dist/runners/git-utils.js +201 -0
  133. package/dist/runners/index.d.ts +3 -0
  134. package/dist/runners/index.js +3 -0
  135. package/dist/runners/review-agent.d.ts +20 -0
  136. package/dist/runners/review-agent.js +171 -41
  137. package/dist/runners/runner-registry.js +10 -0
  138. package/dist/runners/sdk-review-runner.d.ts +65 -0
  139. package/dist/runners/sdk-review-runner.js +185 -0
  140. package/dist/runners/security-triage.d.ts +20 -4
  141. package/dist/runners/security-triage.js +39 -15
  142. package/dist/runners/types.d.ts +6 -0
  143. package/dist/runtime/attestations.d.ts +766 -0
  144. package/dist/runtime/attestations.js +1195 -0
  145. package/dist/runtime/git-env.d.ts +53 -0
  146. package/dist/runtime/git-env.js +60 -0
  147. package/dist/runtime/index.d.ts +7 -0
  148. package/dist/runtime/index.js +7 -0
  149. package/dist/runtime/parallelism-flag.d.ts +28 -0
  150. package/dist/runtime/parallelism-flag.js +39 -0
  151. package/dist/runtime/port-allocator.d.ts +32 -0
  152. package/dist/runtime/port-allocator.js +96 -0
  153. package/dist/runtime/worktree-pool.d.ts +86 -0
  154. package/dist/runtime/worktree-pool.js +204 -0
  155. package/dist/runtime/worktree.d.ts +25 -0
  156. package/dist/runtime/worktree.js +111 -0
  157. package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
  158. package/dist/sa-scoring/auto-calibrate.js +107 -0
  159. package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
  160. package/dist/sa-scoring/c1-sa2-computable.js +59 -0
  161. package/dist/sa-scoring/composite.d.ts +107 -0
  162. package/dist/sa-scoring/composite.js +139 -0
  163. package/dist/sa-scoring/depparse-client.d.ts +79 -0
  164. package/dist/sa-scoring/depparse-client.js +187 -0
  165. package/dist/sa-scoring/did-compiler.d.ts +122 -0
  166. package/dist/sa-scoring/did-compiler.js +286 -0
  167. package/dist/sa-scoring/drift-monitor.d.ts +84 -0
  168. package/dist/sa-scoring/drift-monitor.js +186 -0
  169. package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
  170. package/dist/sa-scoring/exemplar-bank.js +154 -0
  171. package/dist/sa-scoring/feedback-store.d.ts +100 -0
  172. package/dist/sa-scoring/feedback-store.js +156 -0
  173. package/dist/sa-scoring/index.d.ts +71 -0
  174. package/dist/sa-scoring/index.js +158 -0
  175. package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
  176. package/dist/sa-scoring/layer1-deterministic.js +298 -0
  177. package/dist/sa-scoring/layer2-structural.d.ts +71 -0
  178. package/dist/sa-scoring/layer2-structural.js +151 -0
  179. package/dist/sa-scoring/layer3-llm.d.ts +86 -0
  180. package/dist/sa-scoring/layer3-llm.js +282 -0
  181. package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
  182. package/dist/sa-scoring/rescore-orchestrator.js +47 -0
  183. package/dist/scheduling/burn-down.d.ts +27 -0
  184. package/dist/scheduling/burn-down.js +43 -0
  185. package/dist/scheduling/calibration.d.ts +42 -0
  186. package/dist/scheduling/calibration.js +150 -0
  187. package/dist/scheduling/index.d.ts +8 -0
  188. package/dist/scheduling/index.js +8 -0
  189. package/dist/scheduling/ledger.d.ts +59 -0
  190. package/dist/scheduling/ledger.js +216 -0
  191. package/dist/scheduling/off-peak.d.ts +27 -0
  192. package/dist/scheduling/off-peak.js +112 -0
  193. package/dist/scheduling/schedule-decision.d.ts +39 -0
  194. package/dist/scheduling/schedule-decision.js +89 -0
  195. package/dist/scheduling/tier-analysis.d.ts +47 -0
  196. package/dist/scheduling/tier-analysis.js +81 -0
  197. package/dist/scheduling/types.d.ts +140 -0
  198. package/dist/scheduling/types.js +11 -0
  199. package/dist/shared.d.ts +13 -0
  200. package/dist/shared.js +32 -0
  201. package/dist/state/schema.d.ts +5 -1
  202. package/dist/state/schema.js +223 -1
  203. package/dist/state/store.d.ts +55 -1
  204. package/dist/state/store.js +342 -7
  205. package/dist/state/types.d.ts +139 -0
  206. package/dist/types.d.ts +1 -1
  207. package/dist/validate-agent-output.js +4 -1
  208. package/dist/watch.js +6 -0
  209. package/package.json +3 -2
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Bridge between stateless admission scoring and the stateful orchestrator
3
+ * (RFC-0008 Addendum A §A.2 – §A.5).
4
+ *
5
+ * `enrichAdmissionInput()` reads from the orchestrator's state store and
6
+ * resolved resources to populate the RFC-0008 context fields on
7
+ * `AdmissionInput`, then `computeDesignSystemReadiness()` produces the
8
+ * Eρ₄ scalar that feeds the admission composite in §A.6.
9
+ *
10
+ * Scope for AISDLC-43: implement C2 (Eρ₄) only. C3/C4/C5 are populated
11
+ * by later tasks (AISDLC-44/45/46).
12
+ */
13
+ import { checkHasFrontendComponents } from './code-area-classifier.js';
14
+ import { checkDesignAuthority } from './design-authority.js';
15
+ /**
16
+ * Minimum data points required before `code_area_metrics` is trusted
17
+ * enough to drive defect-risk penalties (RFC-0008 §7.4 Open Question 4).
18
+ */
19
+ export const CODE_AREA_METRICS_MIN_DATA_POINTS = 10;
20
+ /** Default window (ms) for `getCodeAreaMetrics` lookups — 90 days. */
21
+ const DEFAULT_METRICS_WINDOW_MS = 90 * 24 * 60 * 60 * 1000;
22
+ /**
23
+ * Populate `designSystemContext` on the admission input using the
24
+ * resolved DSB and state store. Returns the input unchanged when no DSB
25
+ * is available (preDesignSystem phase — caller falls through to the
26
+ * stateless path).
27
+ */
28
+ export function enrichAdmissionInput(input, ctx) {
29
+ const binding = ctx.designSystemBinding;
30
+ const codeAreaQuality = ctx.codeArea
31
+ ? buildCodeAreaQuality(ctx.codeArea, ctx.stateStore, ctx.now)
32
+ : undefined;
33
+ const autonomyContext = buildAutonomyContext(ctx);
34
+ const designAuthoritySignal = buildDesignAuthoritySignal(input, ctx);
35
+ if (!binding) {
36
+ const next = { ...input };
37
+ // When ctx.codeArea is set but buildCodeAreaQuality returns undefined
38
+ // (insufficient data), explicitly clear any stale value that may have
39
+ // been carried over from input — otherwise the spread above preserves
40
+ // it and drives a bogus defect-risk penalty.
41
+ if (ctx.codeArea)
42
+ next.codeAreaQuality = codeAreaQuality;
43
+ if (autonomyContext)
44
+ next.autonomyContext = autonomyContext;
45
+ if (designAuthoritySignal)
46
+ next.designAuthoritySignal = designAuthoritySignal;
47
+ return next;
48
+ }
49
+ const catalogCoverageRaw = binding.status?.catalogHealth?.coveragePercent;
50
+ const tokenComplianceRaw = binding.status?.tokenCompliance?.currentCoverage;
51
+ const catalogCoverage = normalizeCoverage(catalogCoverageRaw);
52
+ const tokenCompliance = normalizeCoverage(tokenComplianceRaw);
53
+ const baselineCoverage = ctx.stateStore
54
+ ? computeBaselineCoverage(ctx.stateStore, binding.metadata.name)
55
+ : 0;
56
+ const ageDays = computeDsbAgeDays(ctx.dsbAdoptedAt, ctx.now);
57
+ const phase = detectLifecyclePhase(binding, catalogCoverage, ageDays);
58
+ const context = {
59
+ catalogCoverage,
60
+ tokenCompliance,
61
+ inBootstrapPhase: phase === 'catalogBootstrap',
62
+ baselineCoverage,
63
+ catalogGaps: ctx.catalogGaps ?? [],
64
+ };
65
+ return {
66
+ ...input,
67
+ designSystemContext: context,
68
+ // When ctx.codeArea is set we always write codeAreaQuality — either
69
+ // the computed value or `undefined` — so stale input.codeAreaQuality
70
+ // can't silently drive a penalty under fresh enrichment context.
71
+ ...(ctx.codeArea ? { codeAreaQuality } : {}),
72
+ ...(autonomyContext ? { autonomyContext } : {}),
73
+ ...(designAuthoritySignal ? { designAuthoritySignal } : {}),
74
+ };
75
+ }
76
+ /**
77
+ * Read code-area metrics within the 90-day window and project them into
78
+ * the `CodeAreaQuality` shape. Returns undefined when the metric row is
79
+ * missing or has fewer than `CODE_AREA_METRICS_MIN_DATA_POINTS` samples —
80
+ * downstream defect-risk consumers treat "absent" as 0 penalty.
81
+ */
82
+ function buildCodeAreaQuality(codeArea, store, now) {
83
+ if (!store) {
84
+ // No state → fall back to heuristic classification only.
85
+ return { hasFrontendComponents: checkHasFrontendComponents(codeArea) };
86
+ }
87
+ const windowStart = new Date((now ?? (() => Date.now()))() - DEFAULT_METRICS_WINDOW_MS).toISOString();
88
+ const metrics = store.getCodeAreaMetrics(codeArea, { since: windowStart });
89
+ if (!metrics || (metrics.dataPointCount ?? 0) < CODE_AREA_METRICS_MIN_DATA_POINTS) {
90
+ return undefined;
91
+ }
92
+ const designQuality = parseDesignQuality(metrics.designMetricsJson);
93
+ return {
94
+ defectDensity: metrics.defectDensity,
95
+ churnRate: metrics.churnRate,
96
+ prRejectionRate: metrics.prRejectionRate,
97
+ hasFrontendComponents: metrics.hasFrontendComponents ?? false,
98
+ ...(designQuality ? { designQuality } : {}),
99
+ };
100
+ }
101
+ function parseDesignQuality(json) {
102
+ if (!json)
103
+ return undefined;
104
+ try {
105
+ const parsed = JSON.parse(json);
106
+ if (parsed.designCIPassRate === undefined &&
107
+ parsed.designReviewRejectionRate === undefined &&
108
+ parsed.usabilitySimPassRate === undefined) {
109
+ return undefined;
110
+ }
111
+ return parsed;
112
+ }
113
+ catch {
114
+ return undefined;
115
+ }
116
+ }
117
+ /**
118
+ * Compute the C3 defect-risk factor per §A.5. Returns 0 when
119
+ * `codeAreaQuality` is absent (insufficient data → no penalty).
120
+ *
121
+ * !hasFrontendComponents → 0.5×dd + 0.3×churn + 0.2×prRej
122
+ * hasFrontendComponents
123
+ * no designQuality → same as pure code (no blend target)
124
+ * with designQuality → 0.7 × code + 0.3 × design
125
+ * where design = 0.4×(1-ciPass)
126
+ * + 0.4×reviewRej
127
+ * + 0.2×(1-usabPass)
128
+ *
129
+ * Final value is clamped to [0, 0.5].
130
+ */
131
+ export function computeDefectRiskFactor(quality) {
132
+ if (!quality)
133
+ return 0;
134
+ const code = 0.5 * (quality.defectDensity ?? 0) +
135
+ 0.3 * (quality.churnRate ?? 0) +
136
+ 0.2 * (quality.prRejectionRate ?? 0);
137
+ if (!quality.hasFrontendComponents || !quality.designQuality) {
138
+ return clamp(code, 0, 0.5);
139
+ }
140
+ const dq = quality.designQuality;
141
+ const ciPass = dq.designCIPassRate ?? 1;
142
+ const reviewRej = dq.designReviewRejectionRate ?? 0;
143
+ const usabPass = dq.usabilitySimPassRate ?? 1;
144
+ const design = 0.4 * (1 - ciPass) + 0.4 * reviewRej + 0.2 * (1 - usabPass);
145
+ const blended = 0.7 * code + 0.3 * design;
146
+ return clamp(blended, 0, 0.5);
147
+ }
148
+ function clamp(value, min, max) {
149
+ return Math.min(max, Math.max(min, value));
150
+ }
151
+ // ── C4 Autonomy Factor ─────────────────────────────────────────────────
152
+ /**
153
+ * Map task complexity to the required autonomy level per §A.4:
154
+ * complexity ≤ 3 → level 1
155
+ * complexity ≤ 6 → level 2
156
+ * else → level 3
157
+ */
158
+ export function complexityToAutonomyLevel(complexity) {
159
+ if (complexity <= 3)
160
+ return 1;
161
+ if (complexity <= 6)
162
+ return 2;
163
+ return 3;
164
+ }
165
+ /**
166
+ * Compute the C4 autonomy factor per §A.5:
167
+ * gap = requiredLevel - currentEarnedLevel
168
+ * gap > 0 → max(0.1, 1.0 - gap × 0.4)
169
+ * gap ≤ 0 → 1.0
170
+ */
171
+ export function computeAutonomyFactor(ctx) {
172
+ if (!ctx)
173
+ return 1.0;
174
+ const gap = ctx.requiredLevel - ctx.currentEarnedLevel;
175
+ if (gap <= 0)
176
+ return 1.0;
177
+ return Math.max(0.1, 1.0 - gap * 0.4);
178
+ }
179
+ function buildAutonomyContext(ctx) {
180
+ if (!ctx.autonomyPolicy)
181
+ return undefined;
182
+ const agents = ctx.autonomyPolicy.status?.agents ?? [];
183
+ if (agents.length === 0)
184
+ return undefined;
185
+ const selected = ctx.agentName
186
+ ? agents.find((a) => a.name === ctx.agentName)
187
+ : pickMostPermissiveAgent(agents);
188
+ if (!selected)
189
+ return undefined;
190
+ const currentEarnedLevel = selected.currentLevel;
191
+ const requiredLevel = ctx.complexity !== undefined ? complexityToAutonomyLevel(ctx.complexity) : currentEarnedLevel;
192
+ return { currentEarnedLevel, requiredLevel };
193
+ }
194
+ function pickMostPermissiveAgent(agents) {
195
+ return agents.reduce((best, a) => (a.currentLevel > best.currentLevel ? a : best), agents[0]);
196
+ }
197
+ // ── C5 Design Authority Signal + HC_design ─────────────────────────────
198
+ /** Base weights per signal type (§A.5) before compliance modulation. */
199
+ const DESIGN_AUTHORITY_BASE_WEIGHT = Object.freeze({
200
+ 'advances-design-coherence': 0.6,
201
+ 'fills-catalog-gap': 0.6,
202
+ 'fragments-component-catalog': -0.4,
203
+ 'misaligned-with-brand': -0.4,
204
+ unspecified: 0.3,
205
+ });
206
+ /**
207
+ * Compute the C5 design-authority weight per §A.5.
208
+ *
209
+ * non-authority → 0.0
210
+ * authority + positive → +0.6 × modulation
211
+ * authority + negative → -0.4 × modulation
212
+ * authority + no type → +0.3 × modulation
213
+ *
214
+ * where `modulation = 1.2 - areaComplianceScore` when the score is
215
+ * supplied, else `1.0` (unmodulated base weight).
216
+ */
217
+ export function computeDesignAuthorityWeight(signal) {
218
+ if (!signal || !signal.isDesignAuthority)
219
+ return 0;
220
+ const signalType = signal.signalType ?? 'unspecified';
221
+ const base = DESIGN_AUTHORITY_BASE_WEIGHT[signalType];
222
+ const modulation = signal.areaComplianceScore !== undefined ? 1.2 - signal.areaComplianceScore : 1;
223
+ return base * modulation;
224
+ }
225
+ function buildDesignAuthoritySignal(input, ctx) {
226
+ if (!ctx.designSystemBinding)
227
+ return undefined;
228
+ // AISDLC-171: surface whether the DSB declares any design authority
229
+ // principals at all. This is a diagnostic flag — it does NOT participate
230
+ // in the HC_design weight calculation (per RFC-0008 §14.2, only
231
+ // principals who participate as author/commenter can emit HC_design).
232
+ // Surfacing it lets pillarBreakdown distinguish "DSB has no design
233
+ // authority structure" from "DSB has design authority but no principal
234
+ // participated in this issue".
235
+ const principalsDeclared = (ctx.designSystemBinding.spec.stewardship.designAuthority.principals?.length ?? 0) > 0;
236
+ const { isDesignAuthority, signalType } = checkDesignAuthority({
237
+ authorLogin: input.authorLogin,
238
+ commenterLogins: input.commenterLogins,
239
+ labels: input.labels,
240
+ }, ctx.designSystemBinding);
241
+ if (!isDesignAuthority) {
242
+ return { isDesignAuthority: false, principalsDeclared };
243
+ }
244
+ return {
245
+ isDesignAuthority: true,
246
+ signalType,
247
+ principalsDeclared,
248
+ ...(ctx.areaComplianceScore !== undefined
249
+ ? { areaComplianceScore: ctx.areaComplianceScore }
250
+ : {}),
251
+ };
252
+ }
253
+ /**
254
+ * Compute the C2 Eρ₄ design-system readiness scalar in [0, 1] per §A.5.
255
+ *
256
+ * preDesignSystem: 1.0 (no DSB → no penalty)
257
+ * catalogBootstrap: max(0.3, 0.4×cat + 0.3×tok + 0.3×baseline)
258
+ * postDesignSystem: 0.4×cat + 0.3×tok + 0.3×baseline
259
+ */
260
+ export function computeDesignSystemReadiness(ctx) {
261
+ const binding = ctx.designSystemBinding;
262
+ if (!binding)
263
+ return 1.0;
264
+ const catalogCoverage = normalizeCoverage(binding.status?.catalogHealth?.coveragePercent);
265
+ const tokenCompliance = normalizeCoverage(binding.status?.tokenCompliance?.currentCoverage);
266
+ const baselineCoverage = ctx.stateStore
267
+ ? computeBaselineCoverage(ctx.stateStore, binding.metadata.name)
268
+ : 0;
269
+ const ageDays = computeDsbAgeDays(ctx.dsbAdoptedAt, ctx.now);
270
+ const phase = detectLifecyclePhase(binding, catalogCoverage, ageDays);
271
+ const computed = 0.4 * catalogCoverage + 0.3 * tokenCompliance + 0.3 * baselineCoverage;
272
+ if (phase === 'catalogBootstrap')
273
+ return Math.max(0.3, computed);
274
+ return computed;
275
+ }
276
+ /**
277
+ * Compute the C2 Eρ₄ scalar directly from the DesignSystemContext
278
+ * already populated on an `AdmissionInput` (no DSB/state lookups).
279
+ *
280
+ * undefined (preDesignSystem) → 1.0
281
+ * inBootstrapPhase → max(0.3, computed)
282
+ * else → computed
283
+ *
284
+ * Used by the admission composite (§A.6) to avoid re-reading the state
285
+ * store on every score call.
286
+ */
287
+ export function computeReadinessFromDesignSystemContext(context) {
288
+ if (!context)
289
+ return 1.0;
290
+ const catalogCoverage = normalizeCoverage(context.catalogCoverage);
291
+ const tokenCompliance = normalizeCoverage(context.tokenCompliance);
292
+ const baselineCoverage = normalizeCoverage(context.baselineCoverage);
293
+ const computed = 0.4 * catalogCoverage + 0.3 * tokenCompliance + 0.3 * baselineCoverage;
294
+ if (context.inBootstrapPhase)
295
+ return Math.max(0.3, computed);
296
+ return computed;
297
+ }
298
+ export function detectLifecyclePhase(binding, normalizedCatalogCoverage, ageDays) {
299
+ if (!binding)
300
+ return 'preDesignSystem';
301
+ if (normalizedCatalogCoverage < 0.2 && ageDays < 90)
302
+ return 'catalogBootstrap';
303
+ return 'postDesignSystem';
304
+ }
305
+ /**
306
+ * Days since the DSB was adopted. Returns 0 when no adoption timestamp
307
+ * is supplied — the conservative default (treats DSB as brand-new and
308
+ * favours the bootstrap floor).
309
+ */
310
+ export function computeDsbAgeDays(adoptedAt, now) {
311
+ if (!adoptedAt)
312
+ return 0;
313
+ const adoptedMs = Date.parse(adoptedAt);
314
+ if (Number.isNaN(adoptedMs))
315
+ return 0;
316
+ const nowMs = (now ?? (() => Date.now()))();
317
+ const diffMs = Math.max(0, nowMs - adoptedMs);
318
+ return diffMs / (1000 * 60 * 60 * 24);
319
+ }
320
+ /**
321
+ * Fraction of the UI under visual-regression monitoring for this binding,
322
+ * derived from approved baselines in `visual_regression_results`.
323
+ *
324
+ * Definition (§A.5 proxy): `approvedBaselines / totalBaselines`. Returns
325
+ * 0 when no history exists (bootstrap protection: avoids over-crediting
326
+ * readiness when the monitor hasn't run yet).
327
+ */
328
+ export function computeBaselineCoverage(store, bindingName) {
329
+ const history = store.getVisualRegressionResults(bindingName, 1000);
330
+ if (history.length === 0)
331
+ return 0;
332
+ const approved = history.filter((r) => Boolean(r.approved)).length;
333
+ return approved / history.length;
334
+ }
335
+ function normalizeCoverage(value) {
336
+ if (value === undefined || Number.isNaN(value))
337
+ return 0;
338
+ const clamped = value > 1 ? value / 100 : value;
339
+ return Math.min(1, Math.max(0, clamped));
340
+ }
341
+ //# sourceMappingURL=admission-enrichment.js.map
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Admission-specific Human Curve composite (RFC-0008 §A.6, Amendment 4).
3
+ *
4
+ * The admission HC differs from the legacy PPA HC in two ways:
5
+ * 1. Four terms instead of three — HC_design enters at 0.10 weight.
6
+ * 2. Weights are (0.2, 0.45, 0.25, 0.10) rather than (0.5, 0.3, 0.2).
7
+ *
8
+ * HC_design flows through tanh alongside the other three components;
9
+ * it is NOT a direct soul-alignment modifier (Amendment 5 correction
10
+ * to the v3 draft).
11
+ *
12
+ * The `override` bypass on `PriorityInput` is still position-1: this
13
+ * module never runs when an override is active — the admission
14
+ * composite (AISDLC-48) short-circuits on override before calling
15
+ * `computeAdmissionHumanCurve`.
16
+ */
17
+ import type { AdmissionInput, DesignAuthoritySignal } from './admission-score.js';
18
+ /**
19
+ * Fixed §A.6 weights. Exposed for validation and for downstream callers
20
+ * that need to introspect the HC decomposition.
21
+ */
22
+ export declare const HC_WEIGHTS: Readonly<{
23
+ explicit: 0.2;
24
+ consensus: 0.45;
25
+ decision: 0.25;
26
+ design: 0.1;
27
+ }>;
28
+ /** Sum of HC_WEIGHTS — must equal 1.0 exactly (AC #2). */
29
+ export declare const HC_WEIGHT_SUM: number;
30
+ export interface AdmissionHumanCurveResult {
31
+ /** Signed explicit-priority signal in [-1, 1]. */
32
+ hcExplicit: number;
33
+ /** Signed consensus signal in [-1, 1]. */
34
+ hcConsensus: number;
35
+ /** Signed meeting-decision signal in [-1, 1] (0 = neutral when absent). */
36
+ hcDecision: number;
37
+ /**
38
+ * Signed design-authority signal in [-1, 1].
39
+ *
40
+ * AISDLC-171: this channel ONLY fires when one of the issue's
41
+ * participants (author or commenters) is a principal listed in
42
+ * `DesignSystemBinding.spec.stewardship.designAuthority.principals`.
43
+ * Per RFC-0008 §14.2, non-principal participants' design opinions
44
+ * route through `hcConsensus` instead — `hcDesign` carries
45
+ * specifically the design-authority leadership signal. To distinguish
46
+ * "no DSB at all" from "DSB exists but no design principal
47
+ * participated", consult `designAuthorityConfigured` on this result
48
+ * (and on `pillarBreakdown.shared.hcComposite`).
49
+ */
50
+ hcDesign: number;
51
+ /**
52
+ * Diagnostic flag (AISDLC-171) — true when the resolved DSB declared
53
+ * `stewardship.designAuthority.principals` entries. Always undefined
54
+ * when no DSB was supplied (preDesignSystem). Surfaces the
55
+ * "configured but inactive" state without altering hcDesign weight.
56
+ */
57
+ designAuthorityConfigured?: boolean;
58
+ /** Weighted sum before tanh. */
59
+ hcRaw: number;
60
+ /** `tanh(hcRaw)` — the HC value consumed by the admission composite. */
61
+ hcComposite: number;
62
+ }
63
+ export declare function deriveHcExplicit(input: Pick<AdmissionInput, 'labels'>): number;
64
+ export declare function deriveHcConsensus(input: Pick<AdmissionInput, 'reactionCount' | 'authorAssociation'>): number;
65
+ /**
66
+ * HC_decision — meeting-decision signal in [-1, 1].
67
+ *
68
+ * AdmissionInput has no dedicated meeting-decision field. We return
69
+ * neutral (0) by default. Callers that later add a GitHub-comment
70
+ * parser for `/decide approve` / `/decide reject` can plumb it through
71
+ * via an optional AdmissionInput field without breaking this shape.
72
+ */
73
+ export declare function deriveHcDecision(_input: AdmissionInput): number;
74
+ export declare function deriveHcDesign(signal: DesignAuthoritySignal | undefined): number;
75
+ /**
76
+ * Compute the admission HC composite from an `AdmissionInput`.
77
+ * Returns both the weighted pre-tanh sum and the tanh-compressed value
78
+ * for auditability.
79
+ */
80
+ export declare function computeAdmissionHumanCurve(input: AdmissionInput): AdmissionHumanCurveResult;
81
+ //# sourceMappingURL=admission-hc.d.ts.map
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Admission-specific Human Curve composite (RFC-0008 §A.6, Amendment 4).
3
+ *
4
+ * The admission HC differs from the legacy PPA HC in two ways:
5
+ * 1. Four terms instead of three — HC_design enters at 0.10 weight.
6
+ * 2. Weights are (0.2, 0.45, 0.25, 0.10) rather than (0.5, 0.3, 0.2).
7
+ *
8
+ * HC_design flows through tanh alongside the other three components;
9
+ * it is NOT a direct soul-alignment modifier (Amendment 5 correction
10
+ * to the v3 draft).
11
+ *
12
+ * The `override` bypass on `PriorityInput` is still position-1: this
13
+ * module never runs when an override is active — the admission
14
+ * composite (AISDLC-48) short-circuits on override before calling
15
+ * `computeAdmissionHumanCurve`.
16
+ */
17
+ import { computeDesignAuthorityWeight } from './admission-enrichment.js';
18
+ /**
19
+ * Fixed §A.6 weights. Exposed for validation and for downstream callers
20
+ * that need to introspect the HC decomposition.
21
+ */
22
+ export const HC_WEIGHTS = Object.freeze({
23
+ explicit: 0.2,
24
+ consensus: 0.45,
25
+ decision: 0.25,
26
+ design: 0.1,
27
+ });
28
+ /** Sum of HC_WEIGHTS — must equal 1.0 exactly (AC #2). */
29
+ export const HC_WEIGHT_SUM = HC_WEIGHTS.explicit + HC_WEIGHTS.consensus + HC_WEIGHTS.decision + HC_WEIGHTS.design;
30
+ const TRUSTED_ASSOCIATIONS = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
31
+ export function deriveHcExplicit(input) {
32
+ const labels = input.labels;
33
+ if (labels.includes('high') || labels.includes('P0') || labels.includes('critical')) {
34
+ return 1.0;
35
+ }
36
+ if (labels.includes('low') || labels.includes('backlog'))
37
+ return -1.0;
38
+ return 0;
39
+ }
40
+ export function deriveHcConsensus(input) {
41
+ const isTrusted = TRUSTED_ASSOCIATIONS.has(input.authorAssociation ?? 'NONE');
42
+ const reactionConsensus = Math.min(1, input.reactionCount / 5);
43
+ // Trusted authors carry implicit team consensus — floor at 0.5 before centering.
44
+ const base = isTrusted ? Math.max(0.5, reactionConsensus) : reactionConsensus;
45
+ // [0, 1] → [-1, 1]
46
+ return base * 2 - 1;
47
+ }
48
+ /**
49
+ * HC_decision — meeting-decision signal in [-1, 1].
50
+ *
51
+ * AdmissionInput has no dedicated meeting-decision field. We return
52
+ * neutral (0) by default. Callers that later add a GitHub-comment
53
+ * parser for `/decide approve` / `/decide reject` can plumb it through
54
+ * via an optional AdmissionInput field without breaking this shape.
55
+ */
56
+ export function deriveHcDecision(_input) {
57
+ return 0;
58
+ }
59
+ export function deriveHcDesign(signal) {
60
+ const raw = computeDesignAuthorityWeight(signal);
61
+ return clamp(raw, -1, 1);
62
+ }
63
+ /**
64
+ * Compute the admission HC composite from an `AdmissionInput`.
65
+ * Returns both the weighted pre-tanh sum and the tanh-compressed value
66
+ * for auditability.
67
+ */
68
+ export function computeAdmissionHumanCurve(input) {
69
+ const hcExplicit = deriveHcExplicit(input);
70
+ const hcConsensus = deriveHcConsensus(input);
71
+ const hcDecision = deriveHcDecision(input);
72
+ const hcDesign = deriveHcDesign(input.designAuthoritySignal);
73
+ // AISDLC-171: surface the diagnostic flag from the enriched signal so
74
+ // pillarBreakdown can render the "configured but inactive" state.
75
+ const designAuthorityConfigured = input.designAuthoritySignal?.principalsDeclared;
76
+ const hcRaw = HC_WEIGHTS.explicit * hcExplicit +
77
+ HC_WEIGHTS.consensus * hcConsensus +
78
+ HC_WEIGHTS.decision * hcDecision +
79
+ HC_WEIGHTS.design * hcDesign;
80
+ const hcComposite = Math.tanh(hcRaw);
81
+ return {
82
+ hcExplicit,
83
+ hcConsensus,
84
+ hcDecision,
85
+ hcDesign,
86
+ hcRaw,
87
+ hcComposite,
88
+ ...(designAuthorityConfigured !== undefined ? { designAuthorityConfigured } : {}),
89
+ };
90
+ }
91
+ function clamp(value, min, max) {
92
+ return Math.min(max, Math.max(min, value));
93
+ }
94
+ //# sourceMappingURL=admission-hc.js.map
@@ -5,7 +5,8 @@
5
5
  * Extracted from dogfood/scripts/ppa-score.ts for reuse across CLI
6
6
  * scripts and workflows.
7
7
  */
8
- import { type PriorityInput, type PriorityScore, type PriorityConfig } from './priority.js';
8
+ import type { PriorityInput, PriorityScore, PriorityConfig } from './priority.js';
9
+ import { type PillarBreakdown } from './pillar-breakdown.js';
9
10
  /**
10
11
  * GitHub author_association values indicating trust level.
11
12
  * OWNER/MEMBER/COLLABORATOR = trusted (project team)
@@ -26,6 +27,95 @@ export interface AdmissionInput {
26
27
  createdAt: string;
27
28
  /** GitHub author_association — determines trust-based signal boosting. */
28
29
  authorAssociation?: AuthorAssociation;
30
+ /** GitHub login of the issue author (used by C5 principal match). */
31
+ authorLogin?: string;
32
+ /** GitHub logins of anyone who commented on the issue (C5 principal match). */
33
+ commenterLogins?: string[];
34
+ /** C2 Eρ₄ inputs — populated by enrichAdmissionInput() (AISDLC-43). */
35
+ designSystemContext?: DesignSystemContext;
36
+ /** C4 inputs — current earned autonomy vs. required level (AISDLC-45). */
37
+ autonomyContext?: AutonomyContext;
38
+ /** C3 inputs — defect/churn/rejection signals per code area (AISDLC-44). */
39
+ codeAreaQuality?: CodeAreaQuality;
40
+ /** C5 inputs — HC_design signal from design-authority principals (AISDLC-46). */
41
+ designAuthoritySignal?: DesignAuthoritySignal;
42
+ /**
43
+ * Backlog-task signals (RFC-0010 dual-workflow). Populated when the issue comes
44
+ * from a Backlog.md task instead of GitHub. Used to discriminate between tasks
45
+ * that share identical GitHub-style signals (no reactions / no comments / OWNER
46
+ * author) — typical for the internal backlog workflow.
47
+ */
48
+ backlogContext?: BacklogContext;
49
+ }
50
+ export interface BacklogContext {
51
+ /** Frontmatter `priority` field — operator's stated importance. */
52
+ priority?: 'critical' | 'high' | 'medium' | 'low';
53
+ /** Number of tasks this one is blocked by (frontmatter `dependencies`). */
54
+ dependencyCount?: number;
55
+ /** Number of file/RFC/URL references in the task body. */
56
+ referenceCount?: number;
57
+ /** Number of acceptance criteria — proxy for scope. */
58
+ acceptanceCriteriaCount?: number;
59
+ /** Frontmatter `status` value (e.g. "To Do", "Draft", "In Progress", "Done"). */
60
+ status?: string;
61
+ }
62
+ export interface DesignSystemContext {
63
+ /** Catalog coverage percent (0–100) from DSB.status.catalogHealth. */
64
+ catalogCoverage?: number;
65
+ /** Token compliance percent (0–100) from DSB.status.tokenCompliance. */
66
+ tokenCompliance?: number;
67
+ /** True when DSB is young or catalog coverage is below the bootstrap floor. */
68
+ inBootstrapPhase?: boolean;
69
+ /** Baseline coverage from visual_regression_results before DSB adoption. */
70
+ baselineCoverage?: number;
71
+ /** Component/token gaps preventing the issue from being built catalog-first. */
72
+ catalogGaps?: string[];
73
+ }
74
+ export interface AutonomyContext {
75
+ /** The AutonomyPolicy-issued earned level for the current agent (0–3). */
76
+ currentEarnedLevel: number;
77
+ /** Level required by the issue's complexity band (≤3→1, ≤6→2, else→3). */
78
+ requiredLevel: number;
79
+ }
80
+ export interface DesignQualityMetrics {
81
+ /** Fraction of design CI checks passing in the window (0–1). */
82
+ designCIPassRate?: number;
83
+ /** Fraction of PRs in the area rejected on design grounds (0–1). */
84
+ designReviewRejectionRate?: number;
85
+ /** Fraction of usability-sim tasks completed successfully (0–1). */
86
+ usabilitySimPassRate?: number;
87
+ }
88
+ export interface CodeAreaQuality {
89
+ defectDensity?: number;
90
+ churnRate?: number;
91
+ prRejectionRate?: number;
92
+ /** True when the code area produces frontend artifacts gated by the DSB. */
93
+ hasFrontendComponents: boolean;
94
+ /** Present only when `hasFrontendComponents === true`. */
95
+ designQuality?: DesignQualityMetrics;
96
+ }
97
+ export type DesignAuthoritySignalType = 'advances-design-coherence' | 'fills-catalog-gap' | 'fragments-component-catalog' | 'misaligned-with-brand' | 'unspecified';
98
+ export interface DesignAuthoritySignal {
99
+ /** True when the issue author/commenter is a DSB designAuthority principal. */
100
+ isDesignAuthority: boolean;
101
+ /** The signal type parsed from labels or structured comments. */
102
+ signalType?: DesignAuthoritySignalType;
103
+ /** The issue's code area compliance score in [0, 1] (used to modulate weight). */
104
+ areaComplianceScore?: number;
105
+ /**
106
+ * Diagnostic flag (AISDLC-171) — true when the resolved DSB declared
107
+ * one or more `stewardship.designAuthority.principals` entries,
108
+ * regardless of whether any of them participated in this issue.
109
+ *
110
+ * This is intentionally NOT consumed by `computeDesignAuthorityWeight`
111
+ * — RFC-0008 §14.2 requires principal participation for HC_design to
112
+ * fire at any weight. The flag exists so `pillarBreakdown.shared.
113
+ * hcComposite.designAuthorityConfigured` can surface "design authority
114
+ * is configured but absent from this issue" — distinct from "no
115
+ * design authority structure exists at all" — without violating the
116
+ * RFC's §14.2 weighting constraint.
117
+ */
118
+ principalsDeclared?: boolean;
29
119
  }
30
120
  export interface AdmissionThresholds {
31
121
  minimumScore: number;
@@ -36,6 +126,11 @@ export interface IssueAdmissionResult {
36
126
  score: PriorityScore;
37
127
  reason: string;
38
128
  suggestions?: string[];
129
+ /**
130
+ * RFC-0008 §A.6 — pillar attribution + tension flags. Required on
131
+ * every admission result so reviewers can act on pillar mismatches.
132
+ */
133
+ pillarBreakdown: PillarBreakdown;
39
134
  }
40
135
  /**
41
136
  * Map GitHub issue fields to PPA PriorityInput dimensions.
@@ -49,10 +144,19 @@ export interface IssueAdmissionResult {
49
144
  */
50
145
  export declare function mapIssueToPriorityInput(input: AdmissionInput): PriorityInput;
51
146
  /**
52
- * Score a GitHub issue for pipeline admission using the Product Priority Algorithm.
147
+ * Score a GitHub issue for pipeline admission using the RFC-0008 §A.6
148
+ * admission-subset composite.
149
+ *
150
+ * P_admission = SA × D-pi_adjusted × ER × (1 + HC)
151
+ *
152
+ * M-phi, E-tau, C-kappa are deferred to runtime scoring — they apply
153
+ * when an admitted issue is picked up for execution, not at the gate.
53
154
  *
54
- * Returns whether the issue is admitted (score and confidence above thresholds)
55
- * along with the full score and, if rejected, suggestions for improvement.
155
+ * Returns whether the issue is admitted (score and confidence above
156
+ * thresholds) along with the full score and, if rejected, suggestions
157
+ * for improvement.
56
158
  */
57
- export declare function scoreIssueForAdmission(input: AdmissionInput, thresholds: AdmissionThresholds, priorityConfig?: PriorityConfig): IssueAdmissionResult;
159
+ export declare function scoreIssueForAdmission(input: AdmissionInput, thresholds: AdmissionThresholds, priorityConfig?: PriorityConfig, options?: import('./admission-composite.js').AdmissionCompositeOptions): IssueAdmissionResult;
160
+ /** Map backlog frontmatter priority string to the typed BacklogContext shape. */
161
+ export declare function normalizeBacklogPriority(p: string | null | undefined): BacklogContext['priority'];
58
162
  //# sourceMappingURL=admission-score.d.ts.map