@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.
- package/dist/__test-helpers/git-env.d.ts +40 -0
- package/dist/__test-helpers/git-env.js +73 -0
- package/dist/admission-composite.d.ts +89 -0
- package/dist/admission-composite.js +241 -0
- package/dist/admission-enrichment.d.ts +142 -0
- package/dist/admission-enrichment.js +341 -0
- package/dist/admission-hc.d.ts +81 -0
- package/dist/admission-hc.js +94 -0
- package/dist/admission-score.d.ts +109 -5
- package/dist/admission-score.js +90 -11
- package/dist/analysis/analyzer.js +3 -2
- package/dist/analysis/convention-detector.d.ts +85 -2
- package/dist/analysis/convention-detector.js +375 -70
- package/dist/analysis/diff-analyzer.d.ts +33 -0
- package/dist/analysis/diff-analyzer.js +122 -0
- package/dist/analysis/hotspot-analyzer.js +3 -1
- package/dist/analysis/index.d.ts +2 -1
- package/dist/analysis/index.js +2 -1
- package/dist/artifacts/index.d.ts +65 -0
- package/dist/artifacts/index.js +142 -0
- package/dist/backlog-adapter.d.ts +121 -0
- package/dist/backlog-adapter.js +438 -0
- package/dist/calibration.d.ts +43 -0
- package/dist/calibration.js +76 -0
- package/dist/cli/commands/agents.d.ts +24 -0
- package/dist/cli/commands/agents.js +66 -1
- package/dist/cli/commands/git-remote.d.ts +74 -0
- package/dist/cli/commands/git-remote.js +170 -0
- package/dist/cli/commands/health.d.ts +4 -0
- package/dist/cli/commands/health.js +13 -1
- package/dist/cli/commands/init-features.d.ts +208 -0
- package/dist/cli/commands/init-features.js +473 -0
- package/dist/cli/commands/init-templates.d.ts +104 -0
- package/dist/cli/commands/init-templates.js +399 -0
- package/dist/cli/commands/init.d.ts +48 -0
- package/dist/cli/commands/init.js +322 -23
- package/dist/cli/commands/mcp-setup.d.ts +31 -0
- package/dist/cli/commands/mcp-setup.js +78 -8
- package/dist/cli/formatters/table.js +15 -2
- package/dist/cli/index.d.ts +14 -1
- package/dist/cli/index.js +81 -20
- package/dist/cli/versions.d.ts +57 -0
- package/dist/cli/versions.js +128 -0
- package/dist/code-area-classifier.d.ts +21 -0
- package/dist/code-area-classifier.js +48 -0
- package/dist/config.d.ts +33 -1
- package/dist/config.js +78 -8
- package/dist/database/adapters/external.d.ts +24 -0
- package/dist/database/adapters/external.js +80 -0
- package/dist/database/adapters/neon.d.ts +41 -0
- package/dist/database/adapters/neon.js +98 -0
- package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
- package/dist/database/adapters/pg-snapshot-restore.js +68 -0
- package/dist/database/adapters/sqlite-copy.d.ts +32 -0
- package/dist/database/adapters/sqlite-copy.js +145 -0
- package/dist/database/connection-injection.d.ts +35 -0
- package/dist/database/connection-injection.js +93 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.js +23 -0
- package/dist/database/registry.d.ts +13 -0
- package/dist/database/registry.js +27 -0
- package/dist/database/topology.d.ts +52 -0
- package/dist/database/topology.js +44 -0
- package/dist/database/types.d.ts +89 -0
- package/dist/database/types.js +26 -0
- package/dist/design-authority.d.ts +53 -0
- package/dist/design-authority.js +84 -0
- package/dist/design-lookahead.d.ts +64 -0
- package/dist/design-lookahead.js +86 -0
- package/dist/design-quality-trend.d.ts +87 -0
- package/dist/design-quality-trend.js +190 -0
- package/dist/design-system-context.d.ts +46 -0
- package/dist/design-system-context.js +80 -0
- package/dist/design-system-correction-loop.d.ts +64 -0
- package/dist/design-system-correction-loop.js +128 -0
- package/dist/design-system-metrics.d.ts +61 -0
- package/dist/design-system-metrics.js +104 -0
- package/dist/design-system-stewardship.d.ts +22 -0
- package/dist/design-system-stewardship.js +85 -0
- package/dist/design-system-validation.d.ts +37 -0
- package/dist/design-system-validation.js +88 -0
- package/dist/dispatch/index.d.ts +4 -0
- package/dist/dispatch/index.js +4 -0
- package/dist/dispatch/merge-gate.d.ts +46 -0
- package/dist/dispatch/merge-gate.js +90 -0
- package/dist/dispatch/requeue.d.ts +57 -0
- package/dist/dispatch/requeue.js +131 -0
- package/dist/dispatch/worker-pool.d.ts +62 -0
- package/dist/dispatch/worker-pool.js +60 -0
- package/dist/execute.d.ts +40 -0
- package/dist/execute.js +188 -15
- package/dist/fix-ci.js +8 -1
- package/dist/fix-review.js +8 -1
- package/dist/harness/adapters/claude-code.d.ts +29 -0
- package/dist/harness/adapters/claude-code.js +191 -0
- package/dist/harness/adapters/codex.d.ts +25 -0
- package/dist/harness/adapters/codex.js +61 -0
- package/dist/harness/independence.d.ts +51 -0
- package/dist/harness/independence.js +67 -0
- package/dist/harness/index.d.ts +14 -0
- package/dist/harness/index.js +20 -0
- package/dist/harness/registry.d.ts +17 -0
- package/dist/harness/registry.js +31 -0
- package/dist/harness/types.d.ts +123 -0
- package/dist/harness/types.js +8 -0
- package/dist/harness/version-probe.d.ts +14 -0
- package/dist/harness/version-probe.js +123 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.js +35 -2
- package/dist/models/classifier.d.ts +78 -0
- package/dist/models/classifier.js +277 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/registry.d.ts +97 -0
- package/dist/models/registry.js +173 -0
- package/dist/pillar-breakdown.d.ts +85 -0
- package/dist/pillar-breakdown.js +162 -0
- package/dist/priority.d.ts +5 -0
- package/dist/priority.js +18 -5
- package/dist/review-meta.d.ts +65 -0
- package/dist/review-meta.js +149 -0
- package/dist/review.d.ts +4 -0
- package/dist/review.js +12 -2
- package/dist/runners/claude-code-sdk.d.ts +31 -0
- package/dist/runners/claude-code-sdk.js +238 -0
- package/dist/runners/claude-code.d.ts +3 -0
- package/dist/runners/claude-code.js +30 -66
- package/dist/runners/codex.js +4 -1
- package/dist/runners/copilot.js +4 -1
- package/dist/runners/cursor.js +4 -1
- package/dist/runners/git-utils.d.ts +81 -0
- package/dist/runners/git-utils.js +201 -0
- package/dist/runners/index.d.ts +3 -0
- package/dist/runners/index.js +3 -0
- package/dist/runners/review-agent.d.ts +20 -0
- package/dist/runners/review-agent.js +171 -41
- package/dist/runners/runner-registry.js +10 -0
- package/dist/runners/sdk-review-runner.d.ts +65 -0
- package/dist/runners/sdk-review-runner.js +185 -0
- package/dist/runners/security-triage.d.ts +20 -4
- package/dist/runners/security-triage.js +39 -15
- package/dist/runners/types.d.ts +6 -0
- package/dist/runtime/attestations.d.ts +766 -0
- package/dist/runtime/attestations.js +1195 -0
- package/dist/runtime/git-env.d.ts +53 -0
- package/dist/runtime/git-env.js +60 -0
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/parallelism-flag.d.ts +28 -0
- package/dist/runtime/parallelism-flag.js +39 -0
- package/dist/runtime/port-allocator.d.ts +32 -0
- package/dist/runtime/port-allocator.js +96 -0
- package/dist/runtime/worktree-pool.d.ts +86 -0
- package/dist/runtime/worktree-pool.js +204 -0
- package/dist/runtime/worktree.d.ts +25 -0
- package/dist/runtime/worktree.js +111 -0
- package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
- package/dist/sa-scoring/auto-calibrate.js +107 -0
- package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
- package/dist/sa-scoring/c1-sa2-computable.js +59 -0
- package/dist/sa-scoring/composite.d.ts +107 -0
- package/dist/sa-scoring/composite.js +139 -0
- package/dist/sa-scoring/depparse-client.d.ts +79 -0
- package/dist/sa-scoring/depparse-client.js +187 -0
- package/dist/sa-scoring/did-compiler.d.ts +122 -0
- package/dist/sa-scoring/did-compiler.js +286 -0
- package/dist/sa-scoring/drift-monitor.d.ts +84 -0
- package/dist/sa-scoring/drift-monitor.js +186 -0
- package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
- package/dist/sa-scoring/exemplar-bank.js +154 -0
- package/dist/sa-scoring/feedback-store.d.ts +100 -0
- package/dist/sa-scoring/feedback-store.js +156 -0
- package/dist/sa-scoring/index.d.ts +71 -0
- package/dist/sa-scoring/index.js +158 -0
- package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
- package/dist/sa-scoring/layer1-deterministic.js +298 -0
- package/dist/sa-scoring/layer2-structural.d.ts +71 -0
- package/dist/sa-scoring/layer2-structural.js +151 -0
- package/dist/sa-scoring/layer3-llm.d.ts +86 -0
- package/dist/sa-scoring/layer3-llm.js +282 -0
- package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
- package/dist/sa-scoring/rescore-orchestrator.js +47 -0
- package/dist/scheduling/burn-down.d.ts +27 -0
- package/dist/scheduling/burn-down.js +43 -0
- package/dist/scheduling/calibration.d.ts +42 -0
- package/dist/scheduling/calibration.js +150 -0
- package/dist/scheduling/index.d.ts +8 -0
- package/dist/scheduling/index.js +8 -0
- package/dist/scheduling/ledger.d.ts +59 -0
- package/dist/scheduling/ledger.js +216 -0
- package/dist/scheduling/off-peak.d.ts +27 -0
- package/dist/scheduling/off-peak.js +112 -0
- package/dist/scheduling/schedule-decision.d.ts +39 -0
- package/dist/scheduling/schedule-decision.js +89 -0
- package/dist/scheduling/tier-analysis.d.ts +47 -0
- package/dist/scheduling/tier-analysis.js +81 -0
- package/dist/scheduling/types.d.ts +140 -0
- package/dist/scheduling/types.js +11 -0
- package/dist/shared.d.ts +13 -0
- package/dist/shared.js +32 -0
- package/dist/state/schema.d.ts +5 -1
- package/dist/state/schema.js +223 -1
- package/dist/state/store.d.ts +55 -1
- package/dist/state/store.js +342 -7
- package/dist/state/types.d.ts +139 -0
- package/dist/types.d.ts +1 -1
- package/dist/validate-agent-output.js +4 -1
- package/dist/watch.js +6 -0
- package/package.json +3 -2
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DesignQualityTrendDegrading detector (RFC-0008 Addendum A §A.8).
|
|
3
|
+
*
|
|
4
|
+
* Periodic monitor that analyses rolling windows over
|
|
5
|
+
* `code_area_metrics` (designMetricsJson) and `token_compliance_history`
|
|
6
|
+
* to catch degradation *before* it shows up in the admission hot path
|
|
7
|
+
* via the C3 defect-risk factor. Emits one event per code area on
|
|
8
|
+
* first detection and is hysteretic — does not re-fire until recovery.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_TREND_CONFIG = {
|
|
11
|
+
windowPrs: 10,
|
|
12
|
+
windowDays: 30,
|
|
13
|
+
ciDropThreshold: 0.15,
|
|
14
|
+
reviewIncreaseThreshold: 0.2,
|
|
15
|
+
consecutiveNegativeCompliance: 5,
|
|
16
|
+
};
|
|
17
|
+
function parseDesignMetrics(json) {
|
|
18
|
+
if (!json)
|
|
19
|
+
return undefined;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(json);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// ── Window selection ───────────────────────────────────────────────────
|
|
28
|
+
/**
|
|
29
|
+
* Partition the history into `recent` (newest `windowPrs` records or
|
|
30
|
+
* anything inside `windowDays`) and `baseline` (everything older). The
|
|
31
|
+
* recent window fills by whichever bound hits first — that gives us a
|
|
32
|
+
* consistent signal whether activity is sparse or bursty.
|
|
33
|
+
*
|
|
34
|
+
* History is assumed to be in descending `computed_at` order (as returned
|
|
35
|
+
* by `getCodeAreaMetricsHistory`).
|
|
36
|
+
*/
|
|
37
|
+
export function splitHistoryByWindow(history, config, nowMs) {
|
|
38
|
+
const cutoffMs = nowMs - config.windowDays * 24 * 60 * 60 * 1000;
|
|
39
|
+
const recent = [];
|
|
40
|
+
for (const row of history) {
|
|
41
|
+
if (recent.length >= config.windowPrs)
|
|
42
|
+
break;
|
|
43
|
+
const ts = row.computedAt ? Date.parse(row.computedAt) : NaN;
|
|
44
|
+
if (Number.isNaN(ts))
|
|
45
|
+
continue;
|
|
46
|
+
if (ts < cutoffMs)
|
|
47
|
+
break;
|
|
48
|
+
recent.push(row);
|
|
49
|
+
}
|
|
50
|
+
const baseline = history.slice(recent.length);
|
|
51
|
+
return { recent, baseline };
|
|
52
|
+
}
|
|
53
|
+
export function evaluateCiPassRate(recent, baseline, threshold) {
|
|
54
|
+
const recentMean = meanDesignMetric(recent, 'designCIPassRate');
|
|
55
|
+
const baselineMean = meanDesignMetric(baseline, 'designCIPassRate');
|
|
56
|
+
if (recentMean === undefined || baselineMean === undefined) {
|
|
57
|
+
return { triggered: false };
|
|
58
|
+
}
|
|
59
|
+
const delta = baselineMean - recentMean; // positive ⇒ dropped
|
|
60
|
+
return {
|
|
61
|
+
triggered: delta >= threshold,
|
|
62
|
+
recentValue: recentMean,
|
|
63
|
+
baselineValue: baselineMean,
|
|
64
|
+
delta,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function evaluateReviewRejectionRate(recent, baseline, threshold) {
|
|
68
|
+
const recentMean = meanDesignMetric(recent, 'designReviewRejectionRate');
|
|
69
|
+
const baselineMean = meanDesignMetric(baseline, 'designReviewRejectionRate');
|
|
70
|
+
if (recentMean === undefined || baselineMean === undefined) {
|
|
71
|
+
return { triggered: false };
|
|
72
|
+
}
|
|
73
|
+
const delta = recentMean - baselineMean; // positive ⇒ rejections rising
|
|
74
|
+
return {
|
|
75
|
+
triggered: delta >= threshold,
|
|
76
|
+
recentValue: recentMean,
|
|
77
|
+
baselineValue: baselineMean,
|
|
78
|
+
delta,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function evaluateTokenComplianceTrend(history, minConsecutive) {
|
|
82
|
+
// history is descending (newest first). Walk newest→oldest, counting
|
|
83
|
+
// a run of declining coverages.
|
|
84
|
+
let streak = 0;
|
|
85
|
+
for (let i = 0; i < history.length - 1; i++) {
|
|
86
|
+
if (history[i].coveragePercent < history[i + 1].coveragePercent)
|
|
87
|
+
streak++;
|
|
88
|
+
else
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
triggered: streak >= minConsecutive,
|
|
93
|
+
recentValue: streak,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function meanDesignMetric(rows, key) {
|
|
97
|
+
const values = [];
|
|
98
|
+
for (const row of rows) {
|
|
99
|
+
const blob = parseDesignMetrics(row.designMetricsJson);
|
|
100
|
+
const value = blob?.[key];
|
|
101
|
+
if (typeof value === 'number' && !Number.isNaN(value))
|
|
102
|
+
values.push(value);
|
|
103
|
+
}
|
|
104
|
+
if (values.length === 0)
|
|
105
|
+
return undefined;
|
|
106
|
+
return values.reduce((a, b) => a + b, 0) / values.length;
|
|
107
|
+
}
|
|
108
|
+
export function analyzeTrend(codeArea, codeAreaHistory, tokenComplianceHistory, nowMs, overrides = {}) {
|
|
109
|
+
const config = { ...DEFAULT_TREND_CONFIG, ...overrides };
|
|
110
|
+
const { recent, baseline } = splitHistoryByWindow(codeAreaHistory, config, nowMs);
|
|
111
|
+
const ci = evaluateCiPassRate(recent, baseline, config.ciDropThreshold);
|
|
112
|
+
const review = evaluateReviewRejectionRate(recent, baseline, config.reviewIncreaseThreshold);
|
|
113
|
+
const compliance = evaluateTokenComplianceTrend(tokenComplianceHistory, config.consecutiveNegativeCompliance);
|
|
114
|
+
const conditions = {};
|
|
115
|
+
if (ci.triggered)
|
|
116
|
+
conditions.designCIPassRate = ci;
|
|
117
|
+
if (review.triggered)
|
|
118
|
+
conditions.designReviewRejectionRate = review;
|
|
119
|
+
if (compliance.triggered)
|
|
120
|
+
conditions.tokenComplianceTrend = compliance;
|
|
121
|
+
return {
|
|
122
|
+
codeArea,
|
|
123
|
+
triggered: Object.keys(conditions).length > 0,
|
|
124
|
+
conditions,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Run the trend analysis for one code area. Returns an event when the
|
|
129
|
+
* trend is currently degrading AND the hysteresis quiet window has
|
|
130
|
+
* elapsed since the last trigger (or no prior trigger). Returns
|
|
131
|
+
* undefined otherwise.
|
|
132
|
+
*/
|
|
133
|
+
export function detectDesignQualityTrendDegrading(codeArea, deps) {
|
|
134
|
+
const nowMs = (deps.now ?? (() => Date.now()))();
|
|
135
|
+
// Hysteresis: skip if we've emitted recently within the recovery window.
|
|
136
|
+
const lastTriggerAt = deps.getLastTriggerAt?.(codeArea);
|
|
137
|
+
if (lastTriggerAt) {
|
|
138
|
+
const lastMs = Date.parse(lastTriggerAt);
|
|
139
|
+
const recoveryMs = deps.hysteresisRecoveryMs ?? 7 * 24 * 60 * 60 * 1000; // 7d default
|
|
140
|
+
if (!Number.isNaN(lastMs) && nowMs - lastMs < recoveryMs)
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const history = deps.stateStore.getCodeAreaMetricsHistory(codeArea, { limit: 100 });
|
|
144
|
+
const binding = deps.getBindingForCodeArea?.(codeArea);
|
|
145
|
+
const tokenHistory = binding
|
|
146
|
+
? deps.stateStore.getTokenComplianceHistory(binding.metadata.name)
|
|
147
|
+
: [];
|
|
148
|
+
const result = analyzeTrend(codeArea, history, tokenHistory, nowMs, deps.config);
|
|
149
|
+
if (!result.triggered)
|
|
150
|
+
return undefined;
|
|
151
|
+
const principals = binding ? gatherPrincipals(binding) : [];
|
|
152
|
+
const triggeredConditions = Object.keys(result.conditions);
|
|
153
|
+
return {
|
|
154
|
+
type: 'DesignQualityTrendDegrading',
|
|
155
|
+
codeArea,
|
|
156
|
+
bindingName: binding?.metadata.name,
|
|
157
|
+
triggeredAt: new Date(nowMs).toISOString(),
|
|
158
|
+
triggeredConditions,
|
|
159
|
+
conditions: result.conditions,
|
|
160
|
+
notifiedPrincipals: principals,
|
|
161
|
+
issueBodyMarkdown: renderIssueBody(result, binding),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function gatherPrincipals(binding) {
|
|
165
|
+
const design = binding.spec.stewardship.designAuthority.principals;
|
|
166
|
+
const engineering = binding.spec.stewardship.engineeringAuthority.principals;
|
|
167
|
+
const unique = new Set([...design, ...engineering]);
|
|
168
|
+
return Array.from(unique);
|
|
169
|
+
}
|
|
170
|
+
function renderIssueBody(result, binding) {
|
|
171
|
+
const lines = [
|
|
172
|
+
`## DesignQualityTrendDegrading — ${result.codeArea}`,
|
|
173
|
+
'',
|
|
174
|
+
binding
|
|
175
|
+
? `Linked DesignSystemBinding: **${binding.metadata.name}**`
|
|
176
|
+
: 'No linked DesignSystemBinding',
|
|
177
|
+
'',
|
|
178
|
+
'### Triggered conditions',
|
|
179
|
+
'',
|
|
180
|
+
];
|
|
181
|
+
for (const [name, evaluation] of Object.entries(result.conditions)) {
|
|
182
|
+
const baseline = evaluation.baselineValue !== undefined ? evaluation.baselineValue.toFixed(3) : 'n/a';
|
|
183
|
+
const current = evaluation.recentValue !== undefined ? evaluation.recentValue.toFixed(3) : 'n/a';
|
|
184
|
+
const delta = evaluation.delta !== undefined ? evaluation.delta.toFixed(3) : 'n/a';
|
|
185
|
+
lines.push(`- **${name}** — baseline ${baseline}, recent ${current}, delta ${delta}`);
|
|
186
|
+
}
|
|
187
|
+
lines.push('', '---', 'Investigate the code area and file follow-up tasks as needed.');
|
|
188
|
+
return lines.join('\n');
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=design-quality-trend.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context strategy selection for design-system-aware agents (RFC-0006 §7.2).
|
|
3
|
+
*
|
|
4
|
+
* Implements the 5-step decision tree that determines how much design
|
|
5
|
+
* system context an agent receives.
|
|
6
|
+
*/
|
|
7
|
+
import type { ContextStrategy, DesignSystemBinding } from '@ai-sdlc/reference';
|
|
8
|
+
export interface TaskContext {
|
|
9
|
+
/** The trigger event type (e.g., 'design-token.changed', 'issue.assigned'). */
|
|
10
|
+
triggerEvent?: string;
|
|
11
|
+
/** Whether the task involves modifying existing components. */
|
|
12
|
+
modifiesComponents?: boolean;
|
|
13
|
+
/** Whether the task creates a new component. */
|
|
14
|
+
createsNewComponent?: boolean;
|
|
15
|
+
/** Whether the task involves both tokens AND component composition. */
|
|
16
|
+
touchesTokensAndComponents?: boolean;
|
|
17
|
+
/** Reusability score from the design-context stage (0.0-1.0). */
|
|
18
|
+
reusabilityScore?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface ContextStrategyResult {
|
|
21
|
+
strategy: ContextStrategy;
|
|
22
|
+
reason: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Select the context strategy using the 5-step decision tree from RFC-0006 §7.2.
|
|
26
|
+
*
|
|
27
|
+
* 1. Token-change trigger with no component mods → tokens-only
|
|
28
|
+
* 2. Modifying/composing existing components → manifest-first
|
|
29
|
+
* 3. Creating new component → full
|
|
30
|
+
* 4. Both tokens AND composition → full
|
|
31
|
+
* 5. Reusability score < 0.5 → full
|
|
32
|
+
*
|
|
33
|
+
* Falls back to manifest-first as the default.
|
|
34
|
+
*/
|
|
35
|
+
export declare function selectContextStrategy(task: TaskContext, binding: DesignSystemBinding): ContextStrategyResult;
|
|
36
|
+
/**
|
|
37
|
+
* Re-evaluate context strategy after scope change (RFC-0006 §7.2 bottom).
|
|
38
|
+
* Called after design impact review if the approved scope differs from
|
|
39
|
+
* the initial scope.
|
|
40
|
+
*/
|
|
41
|
+
export declare function reEvaluateStrategy(originalTask: TaskContext, updatedTask: TaskContext, binding: DesignSystemBinding): {
|
|
42
|
+
changed: boolean;
|
|
43
|
+
result: ContextStrategyResult;
|
|
44
|
+
reason?: string;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=design-system-context.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context strategy selection for design-system-aware agents (RFC-0006 §7.2).
|
|
3
|
+
*
|
|
4
|
+
* Implements the 5-step decision tree that determines how much design
|
|
5
|
+
* system context an agent receives.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Select the context strategy using the 5-step decision tree from RFC-0006 §7.2.
|
|
9
|
+
*
|
|
10
|
+
* 1. Token-change trigger with no component mods → tokens-only
|
|
11
|
+
* 2. Modifying/composing existing components → manifest-first
|
|
12
|
+
* 3. Creating new component → full
|
|
13
|
+
* 4. Both tokens AND composition → full
|
|
14
|
+
* 5. Reusability score < 0.5 → full
|
|
15
|
+
*
|
|
16
|
+
* Falls back to manifest-first as the default.
|
|
17
|
+
*/
|
|
18
|
+
export function selectContextStrategy(task, binding) {
|
|
19
|
+
const agentConfig = binding.spec;
|
|
20
|
+
// If contextStrategyOverride is 'fixed', use the declared strategy
|
|
21
|
+
if (agentConfig.designSystem?.contextStrategyOverride === 'fixed') {
|
|
22
|
+
const fixed = (agentConfig.designSystem?.contextStrategy ??
|
|
23
|
+
'manifest-first');
|
|
24
|
+
return { strategy: fixed, reason: 'Fixed strategy override — using declared contextStrategy' };
|
|
25
|
+
}
|
|
26
|
+
// Step 1: Token-change trigger with no component modifications
|
|
27
|
+
if (task.triggerEvent === 'design-token.changed' &&
|
|
28
|
+
!task.modifiesComponents &&
|
|
29
|
+
!task.createsNewComponent) {
|
|
30
|
+
return {
|
|
31
|
+
strategy: 'tokens-only',
|
|
32
|
+
reason: 'Token-change trigger with no component modifications',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// Step 2: Modifying/composing existing components only
|
|
36
|
+
if (task.modifiesComponents && !task.createsNewComponent && !task.touchesTokensAndComponents) {
|
|
37
|
+
return {
|
|
38
|
+
strategy: 'manifest-first',
|
|
39
|
+
reason: 'Modifying existing components — manifest sufficient',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Step 3: Creating a new component
|
|
43
|
+
if (task.createsNewComponent) {
|
|
44
|
+
return { strategy: 'full', reason: 'New component creation requires full context' };
|
|
45
|
+
}
|
|
46
|
+
// Step 4: Both tokens AND component composition
|
|
47
|
+
if (task.touchesTokensAndComponents) {
|
|
48
|
+
return {
|
|
49
|
+
strategy: 'full',
|
|
50
|
+
reason: 'Task touches both tokens and components — escalating to full',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Step 5: Low reusability score
|
|
54
|
+
if (task.reusabilityScore !== undefined && task.reusabilityScore < 0.5) {
|
|
55
|
+
return {
|
|
56
|
+
strategy: 'full',
|
|
57
|
+
reason: `Reusability score ${task.reusabilityScore} < 0.5 — catalog insufficient`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// Default
|
|
61
|
+
return { strategy: 'manifest-first', reason: 'Default strategy' };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Re-evaluate context strategy after scope change (RFC-0006 §7.2 bottom).
|
|
65
|
+
* Called after design impact review if the approved scope differs from
|
|
66
|
+
* the initial scope.
|
|
67
|
+
*/
|
|
68
|
+
export function reEvaluateStrategy(originalTask, updatedTask, binding) {
|
|
69
|
+
const original = selectContextStrategy(originalTask, binding);
|
|
70
|
+
const updated = selectContextStrategy(updatedTask, binding);
|
|
71
|
+
if (original.strategy !== updated.strategy) {
|
|
72
|
+
return {
|
|
73
|
+
changed: true,
|
|
74
|
+
result: updated,
|
|
75
|
+
reason: 'scope-changed-at-impact-review',
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return { changed: false, result: original };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=design-system-context.js.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autonomous correction loop for design system gates (RFC-0006 §8.4)
|
|
3
|
+
* and Design Review feedback pipeline (RFC-0006 §8.5).
|
|
4
|
+
*/
|
|
5
|
+
import type { VisualRegressionFailure } from '@ai-sdlc/reference';
|
|
6
|
+
export interface CorrectionIteration {
|
|
7
|
+
attempt: number;
|
|
8
|
+
failures: VisualRegressionFailure[];
|
|
9
|
+
codeDiff?: string;
|
|
10
|
+
visualDiff?: string;
|
|
11
|
+
costUsd: number;
|
|
12
|
+
tokenReferencesChanged: boolean;
|
|
13
|
+
timestamp: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CorrectionLoopConfig {
|
|
16
|
+
maxRetries: number;
|
|
17
|
+
costSoftLimitUsd: number;
|
|
18
|
+
}
|
|
19
|
+
export type CorrectionExitReason = 'max-retries' | 'token-reference-changed' | 'cost-limit-exceeded' | 'design-review-triggered' | 'success';
|
|
20
|
+
export interface CorrectionLoopResult {
|
|
21
|
+
converged: boolean;
|
|
22
|
+
exitReason: CorrectionExitReason;
|
|
23
|
+
iterations: CorrectionIteration[];
|
|
24
|
+
totalCostUsd: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check whether the correction loop should exit.
|
|
28
|
+
*/
|
|
29
|
+
export declare function checkExitConditions(iterations: CorrectionIteration[], config: CorrectionLoopConfig, designReviewTriggered: boolean): CorrectionExitReason | null;
|
|
30
|
+
/**
|
|
31
|
+
* Run the autonomous correction loop.
|
|
32
|
+
*
|
|
33
|
+
* @param runAttempt - Function that executes the agent and returns failures + cost
|
|
34
|
+
* @param config - Loop configuration (maxRetries, cost limit)
|
|
35
|
+
* @param checkDesignReviewTrigger - Function that checks if design review conditions are met
|
|
36
|
+
*/
|
|
37
|
+
export declare function runCorrectionLoop(runAttempt: (failures: VisualRegressionFailure[], attempt: number) => Promise<{
|
|
38
|
+
failures: VisualRegressionFailure[];
|
|
39
|
+
costUsd: number;
|
|
40
|
+
tokenReferencesChanged: boolean;
|
|
41
|
+
codeDiff?: string;
|
|
42
|
+
}>, config: CorrectionLoopConfig, checkDesignReviewTrigger?: () => boolean): Promise<CorrectionLoopResult>;
|
|
43
|
+
export type FeedbackSignal = 'accepted' | 'dismissed' | 'overridden' | 'escalated';
|
|
44
|
+
export interface FeedbackEntry {
|
|
45
|
+
prNumber: number;
|
|
46
|
+
category: string;
|
|
47
|
+
signal: FeedbackSignal;
|
|
48
|
+
reviewer: string;
|
|
49
|
+
comment?: string;
|
|
50
|
+
timestamp: string;
|
|
51
|
+
}
|
|
52
|
+
export interface CategoryAnalysis {
|
|
53
|
+
category: string;
|
|
54
|
+
dismissRate: number;
|
|
55
|
+
}
|
|
56
|
+
export interface DesignReviewFeedbackStore {
|
|
57
|
+
record(entry: FeedbackEntry): void;
|
|
58
|
+
precision(): number;
|
|
59
|
+
highFalsePositiveCategories(): CategoryAnalysis[];
|
|
60
|
+
falseNegativeCategories(): CategoryAnalysis[];
|
|
61
|
+
getEntries(): FeedbackEntry[];
|
|
62
|
+
}
|
|
63
|
+
export declare function createDesignReviewFeedbackStore(): DesignReviewFeedbackStore;
|
|
64
|
+
//# sourceMappingURL=design-system-correction-loop.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autonomous correction loop for design system gates (RFC-0006 §8.4)
|
|
3
|
+
* and Design Review feedback pipeline (RFC-0006 §8.5).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check whether the correction loop should exit.
|
|
7
|
+
*/
|
|
8
|
+
export function checkExitConditions(iterations, config, designReviewTriggered) {
|
|
9
|
+
// Condition 1: maxRetries reached
|
|
10
|
+
if (iterations.length >= config.maxRetries) {
|
|
11
|
+
return 'max-retries';
|
|
12
|
+
}
|
|
13
|
+
// Condition 2: agent changed a token reference
|
|
14
|
+
const last = iterations[iterations.length - 1];
|
|
15
|
+
if (last?.tokenReferencesChanged) {
|
|
16
|
+
return 'token-reference-changed';
|
|
17
|
+
}
|
|
18
|
+
// Condition 3: cumulative cost exceeds soft limit
|
|
19
|
+
const totalCost = iterations.reduce((sum, it) => sum + it.costUsd, 0);
|
|
20
|
+
if (totalCost >= config.costSoftLimitUsd) {
|
|
21
|
+
return 'cost-limit-exceeded';
|
|
22
|
+
}
|
|
23
|
+
// Condition 4: design review trigger conditions met
|
|
24
|
+
if (designReviewTriggered) {
|
|
25
|
+
return 'design-review-triggered';
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Run the autonomous correction loop.
|
|
31
|
+
*
|
|
32
|
+
* @param runAttempt - Function that executes the agent and returns failures + cost
|
|
33
|
+
* @param config - Loop configuration (maxRetries, cost limit)
|
|
34
|
+
* @param checkDesignReviewTrigger - Function that checks if design review conditions are met
|
|
35
|
+
*/
|
|
36
|
+
export async function runCorrectionLoop(runAttempt, config, checkDesignReviewTrigger = () => false) {
|
|
37
|
+
const iterations = [];
|
|
38
|
+
let currentFailures = [];
|
|
39
|
+
for (let attempt = 0; attempt < config.maxRetries; attempt++) {
|
|
40
|
+
const result = await runAttempt(currentFailures, attempt);
|
|
41
|
+
iterations.push({
|
|
42
|
+
attempt,
|
|
43
|
+
failures: result.failures,
|
|
44
|
+
codeDiff: result.codeDiff,
|
|
45
|
+
costUsd: result.costUsd,
|
|
46
|
+
tokenReferencesChanged: result.tokenReferencesChanged,
|
|
47
|
+
timestamp: new Date().toISOString(),
|
|
48
|
+
});
|
|
49
|
+
// Check if converged (no more failures)
|
|
50
|
+
if (result.failures.length === 0) {
|
|
51
|
+
return {
|
|
52
|
+
converged: true,
|
|
53
|
+
exitReason: 'success',
|
|
54
|
+
iterations,
|
|
55
|
+
totalCostUsd: iterations.reduce((s, it) => s + it.costUsd, 0),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
currentFailures = result.failures;
|
|
59
|
+
// Check exit conditions
|
|
60
|
+
const exitReason = checkExitConditions(iterations, config, checkDesignReviewTrigger());
|
|
61
|
+
if (exitReason) {
|
|
62
|
+
return {
|
|
63
|
+
converged: false,
|
|
64
|
+
exitReason,
|
|
65
|
+
iterations,
|
|
66
|
+
totalCostUsd: iterations.reduce((s, it) => s + it.costUsd, 0),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
converged: false,
|
|
72
|
+
exitReason: 'max-retries',
|
|
73
|
+
iterations,
|
|
74
|
+
totalCostUsd: iterations.reduce((s, it) => s + it.costUsd, 0),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function createDesignReviewFeedbackStore() {
|
|
78
|
+
const entries = [];
|
|
79
|
+
return {
|
|
80
|
+
record(entry) {
|
|
81
|
+
entries.push(entry);
|
|
82
|
+
},
|
|
83
|
+
precision() {
|
|
84
|
+
const accepted = entries.filter((e) => e.signal === 'accepted').length;
|
|
85
|
+
const dismissed = entries.filter((e) => e.signal === 'dismissed').length;
|
|
86
|
+
const total = accepted + dismissed;
|
|
87
|
+
return total > 0 ? accepted / total : 1;
|
|
88
|
+
},
|
|
89
|
+
highFalsePositiveCategories() {
|
|
90
|
+
const categoryStats = new Map();
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const stats = categoryStats.get(entry.category) ?? { dismissed: 0, total: 0 };
|
|
93
|
+
stats.total++;
|
|
94
|
+
if (entry.signal === 'dismissed')
|
|
95
|
+
stats.dismissed++;
|
|
96
|
+
categoryStats.set(entry.category, stats);
|
|
97
|
+
}
|
|
98
|
+
return [...categoryStats.entries()]
|
|
99
|
+
.map(([category, stats]) => ({
|
|
100
|
+
category,
|
|
101
|
+
dismissRate: stats.total > 0 ? stats.dismissed / stats.total : 0,
|
|
102
|
+
}))
|
|
103
|
+
.filter((c) => c.dismissRate > 0)
|
|
104
|
+
.sort((a, b) => b.dismissRate - a.dismissRate);
|
|
105
|
+
},
|
|
106
|
+
falseNegativeCategories() {
|
|
107
|
+
const categoryStats = new Map();
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
const stats = categoryStats.get(entry.category) ?? { escalated: 0, total: 0 };
|
|
110
|
+
stats.total++;
|
|
111
|
+
if (entry.signal === 'escalated')
|
|
112
|
+
stats.escalated++;
|
|
113
|
+
categoryStats.set(entry.category, stats);
|
|
114
|
+
}
|
|
115
|
+
return [...categoryStats.entries()]
|
|
116
|
+
.map(([category, stats]) => ({
|
|
117
|
+
category,
|
|
118
|
+
dismissRate: stats.total > 0 ? stats.escalated / stats.total : 0,
|
|
119
|
+
}))
|
|
120
|
+
.filter((c) => c.dismissRate > 0)
|
|
121
|
+
.sort((a, b) => b.dismissRate - a.dismissRate);
|
|
122
|
+
},
|
|
123
|
+
getEntries() {
|
|
124
|
+
return [...entries];
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=design-system-correction-loop.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design system metrics for autonomy promotion/demotion (RFC-0006 §13.2, §A.10).
|
|
3
|
+
*
|
|
4
|
+
* Computes six design review metrics from state store data and integrates
|
|
5
|
+
* them into the autonomy evaluation system.
|
|
6
|
+
*/
|
|
7
|
+
import type { DesignReviewEventRecord, TokenComplianceRecord, VisualRegressionResultRecord, UsabilitySimulationResultRecord } from './state/types.js';
|
|
8
|
+
export interface DesignMetrics {
|
|
9
|
+
/** Percentage of Design CI runs that pass on first attempt. */
|
|
10
|
+
designCiPassRate: number;
|
|
11
|
+
/** Percentage of usability simulations that complete successfully. */
|
|
12
|
+
usabilitySimulationPassRate: number;
|
|
13
|
+
/** Percentage of design reviews approved (any decision except rejected). */
|
|
14
|
+
designReviewApprovalRate: number;
|
|
15
|
+
/** Percentage of design reviews approved without any rejection cycle. */
|
|
16
|
+
designReviewFirstPassRate: number;
|
|
17
|
+
/** Percentage of Design CI failures auto-fixed by correction loop. */
|
|
18
|
+
designCiAutoFixRate: number;
|
|
19
|
+
/** Precision of usability findings (accepted / (accepted + dismissed)). */
|
|
20
|
+
usabilityFindingAccuracy: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Compute design review approval rate from review events.
|
|
24
|
+
*/
|
|
25
|
+
export declare function computeDesignReviewApprovalRate(events: DesignReviewEventRecord[]): number;
|
|
26
|
+
/**
|
|
27
|
+
* Compute design review first-pass rate (approved without rejection cycles).
|
|
28
|
+
* Groups events by PR and checks if the first review for each PR was an approval.
|
|
29
|
+
*/
|
|
30
|
+
export declare function computeDesignReviewFirstPassRate(events: DesignReviewEventRecord[]): number;
|
|
31
|
+
/**
|
|
32
|
+
* Compute usability simulation pass rate from simulation results.
|
|
33
|
+
*/
|
|
34
|
+
export declare function computeUsabilitySimulationPassRate(results: UsabilitySimulationResultRecord[]): number;
|
|
35
|
+
/**
|
|
36
|
+
* Compute token compliance trend from compliance history.
|
|
37
|
+
*/
|
|
38
|
+
export declare function computeTokenComplianceTrend(history: TokenComplianceRecord[]): {
|
|
39
|
+
current: number;
|
|
40
|
+
trend: 'improving' | 'stable' | 'declining';
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Compute visual regression pass rate from results.
|
|
44
|
+
*/
|
|
45
|
+
export declare function computeVisualRegressionPassRate(results: VisualRegressionResultRecord[]): number;
|
|
46
|
+
/**
|
|
47
|
+
* Compute all six design metrics from state store data.
|
|
48
|
+
*/
|
|
49
|
+
export declare function computeDesignMetrics(data: {
|
|
50
|
+
reviewEvents: DesignReviewEventRecord[];
|
|
51
|
+
complianceHistory: TokenComplianceRecord[];
|
|
52
|
+
visualRegressionResults: VisualRegressionResultRecord[];
|
|
53
|
+
usabilitySimulationResults: UsabilitySimulationResultRecord[];
|
|
54
|
+
designCiPassCount?: number;
|
|
55
|
+
designCiTotalCount?: number;
|
|
56
|
+
designCiAutoFixCount?: number;
|
|
57
|
+
designCiFailCount?: number;
|
|
58
|
+
findingsAccepted?: number;
|
|
59
|
+
findingsDismissed?: number;
|
|
60
|
+
}): DesignMetrics;
|
|
61
|
+
//# sourceMappingURL=design-system-metrics.d.ts.map
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design system metrics for autonomy promotion/demotion (RFC-0006 §13.2, §A.10).
|
|
3
|
+
*
|
|
4
|
+
* Computes six design review metrics from state store data and integrates
|
|
5
|
+
* them into the autonomy evaluation system.
|
|
6
|
+
*/
|
|
7
|
+
// ── Metric Computation ───────────────────────────────────────────────
|
|
8
|
+
/**
|
|
9
|
+
* Compute design review approval rate from review events.
|
|
10
|
+
*/
|
|
11
|
+
export function computeDesignReviewApprovalRate(events) {
|
|
12
|
+
if (events.length === 0)
|
|
13
|
+
return 1;
|
|
14
|
+
const approved = events.filter((e) => e.decision === 'approved' || e.decision === 'approved-with-comments').length;
|
|
15
|
+
return approved / events.length;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Compute design review first-pass rate (approved without rejection cycles).
|
|
19
|
+
* Groups events by PR and checks if the first review for each PR was an approval.
|
|
20
|
+
*/
|
|
21
|
+
export function computeDesignReviewFirstPassRate(events) {
|
|
22
|
+
if (events.length === 0)
|
|
23
|
+
return 1;
|
|
24
|
+
const prGroups = new Map();
|
|
25
|
+
for (const e of events) {
|
|
26
|
+
if (e.prNumber === undefined)
|
|
27
|
+
continue;
|
|
28
|
+
const group = prGroups.get(e.prNumber) ?? [];
|
|
29
|
+
group.push(e);
|
|
30
|
+
prGroups.set(e.prNumber, group);
|
|
31
|
+
}
|
|
32
|
+
if (prGroups.size === 0)
|
|
33
|
+
return 1;
|
|
34
|
+
let firstPassCount = 0;
|
|
35
|
+
for (const [, group] of prGroups) {
|
|
36
|
+
// Sort by created_at, check if first is approved
|
|
37
|
+
const sorted = group.sort((a, b) => (a.createdAt ?? '').localeCompare(b.createdAt ?? ''));
|
|
38
|
+
if (sorted[0].decision === 'approved' || sorted[0].decision === 'approved-with-comments') {
|
|
39
|
+
firstPassCount++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return firstPassCount / prGroups.size;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Compute usability simulation pass rate from simulation results.
|
|
46
|
+
*/
|
|
47
|
+
export function computeUsabilitySimulationPassRate(results) {
|
|
48
|
+
if (results.length === 0)
|
|
49
|
+
return 1;
|
|
50
|
+
const passed = results.filter((r) => r.completed).length;
|
|
51
|
+
return passed / results.length;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Compute token compliance trend from compliance history.
|
|
55
|
+
*/
|
|
56
|
+
export function computeTokenComplianceTrend(history) {
|
|
57
|
+
if (history.length === 0)
|
|
58
|
+
return { current: 0, trend: 'stable' };
|
|
59
|
+
if (history.length === 1)
|
|
60
|
+
return { current: history[0].coveragePercent, trend: 'stable' };
|
|
61
|
+
const sorted = [...history].sort((a, b) => (a.scannedAt ?? '').localeCompare(b.scannedAt ?? ''));
|
|
62
|
+
const current = sorted[sorted.length - 1].coveragePercent;
|
|
63
|
+
const previous = sorted[sorted.length - 2].coveragePercent;
|
|
64
|
+
const delta = current - previous;
|
|
65
|
+
let trend;
|
|
66
|
+
if (delta > 1)
|
|
67
|
+
trend = 'improving';
|
|
68
|
+
else if (delta < -1)
|
|
69
|
+
trend = 'declining';
|
|
70
|
+
else
|
|
71
|
+
trend = 'stable';
|
|
72
|
+
return { current, trend };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Compute visual regression pass rate from results.
|
|
76
|
+
*/
|
|
77
|
+
export function computeVisualRegressionPassRate(results) {
|
|
78
|
+
if (results.length === 0)
|
|
79
|
+
return 1;
|
|
80
|
+
const threshold = 0.01; // default diff threshold
|
|
81
|
+
const passed = results.filter((r) => r.diffPercentage <= threshold).length;
|
|
82
|
+
return passed / results.length;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Compute all six design metrics from state store data.
|
|
86
|
+
*/
|
|
87
|
+
export function computeDesignMetrics(data) {
|
|
88
|
+
const ciTotal = data.designCiTotalCount ?? 0;
|
|
89
|
+
const ciPass = data.designCiPassCount ?? ciTotal;
|
|
90
|
+
const ciAutoFix = data.designCiAutoFixCount ?? 0;
|
|
91
|
+
const ciFail = data.designCiFailCount ?? 0;
|
|
92
|
+
const findingsAccepted = data.findingsAccepted ?? 0;
|
|
93
|
+
const findingsDismissed = data.findingsDismissed ?? 0;
|
|
94
|
+
const findingsTotal = findingsAccepted + findingsDismissed;
|
|
95
|
+
return {
|
|
96
|
+
designCiPassRate: ciTotal > 0 ? ciPass / ciTotal : 1,
|
|
97
|
+
usabilitySimulationPassRate: computeUsabilitySimulationPassRate(data.usabilitySimulationResults),
|
|
98
|
+
designReviewApprovalRate: computeDesignReviewApprovalRate(data.reviewEvents),
|
|
99
|
+
designReviewFirstPassRate: computeDesignReviewFirstPassRate(data.reviewEvents),
|
|
100
|
+
designCiAutoFixRate: ciFail > 0 ? ciAutoFix / ciFail : 1,
|
|
101
|
+
usabilityFindingAccuracy: findingsTotal > 0 ? findingsAccepted / findingsTotal : 1,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=design-system-metrics.js.map
|