kiro-spec-engine 1.47.32 → 1.47.33
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.
|
@@ -765,16 +765,18 @@ Dual-track handoff integration:
|
|
|
765
765
|
- `kse auto handoff plan --manifest <path> [--out <path>] [--strict] [--strict-warnings] [--json]`: parse handoff manifest (source project, specs, templates, known gaps) and generate an executable KSE integration phase plan.
|
|
766
766
|
- `kse auto handoff queue --manifest <path> [--out <path>] [--append] [--no-include-known-gaps] [--dry-run] [--json]`: generate close-loop batch goal queue from handoff manifest and optionally persist line-based queue file (default `.kiro/auto/handoff-goals.lines`).
|
|
767
767
|
- `kse auto handoff template-diff --manifest <path> [--json]`: compare manifest templates against local template exports/registry and report `missing_in_local` and `extra_in_local`.
|
|
768
|
-
- `kse auto handoff run --manifest <path> [--out <path>] [--queue-out <path>] [--append] [--no-include-known-gaps] [--continue-from <session|latest|file>] [--continue-strategy <auto|pending|failed-only>] [--dry-run] [--strict] [--strict-warnings] [--no-dependency-batching] [--min-spec-success-rate <n>] [--max-risk-level <level>] [--no-require-ontology-validation] [--release-evidence-window <n>] [--json]`: execute handoff end-to-end (`plan -> queue -> close-loop-batch -> observability`) with automatic report archive to `.kiro/reports/handoff-runs/<session>.json`.
|
|
768
|
+
- `kse auto handoff run --manifest <path> [--out <path>] [--queue-out <path>] [--append] [--no-include-known-gaps] [--continue-from <session|latest|file>] [--continue-strategy <auto|pending|failed-only>] [--dry-run] [--strict] [--strict-warnings] [--no-dependency-batching] [--min-spec-success-rate <n>] [--max-risk-level <level>] [--no-require-ontology-validation] [--no-require-moqui-baseline] [--min-capability-coverage <n>] [--no-require-capability-coverage] [--release-evidence-window <n>] [--json]`: execute handoff end-to-end (`plan -> queue -> close-loop-batch -> observability`) with automatic report archive to `.kiro/reports/handoff-runs/<session>.json`.
|
|
769
769
|
- Default mode is dependency-aware: spec integration goals are grouped into dependency batches and executed in topological order.
|
|
770
770
|
- `--continue-from` resumes pending goals from an existing handoff run report (`latest`, session id, or JSON file path). For safety, KSE enforces manifest-path consistency between the previous report and current run.
|
|
771
771
|
- `--continue-strategy auto|pending|failed-only` controls resumed scope. `auto` (default) derives the best strategy from prior run state (`pending` when unprocessed/planned goals exist, otherwise `failed-only` for pure failure replay).
|
|
772
|
-
- Non-dry runs auto-merge release evidence into `.kiro/reports/release-evidence/handoff-runs.json` with session-level gate/ontology/regression/moqui-baseline snapshots. Merge failures are recorded as warnings without aborting the run.
|
|
772
|
+
- Non-dry runs auto-merge release evidence into `.kiro/reports/release-evidence/handoff-runs.json` with session-level gate/ontology/regression/moqui-baseline/capability-coverage snapshots. Merge failures are recorded as warnings without aborting the run.
|
|
773
773
|
- `--release-evidence-window` controls trend snapshot window size (2-50, default `5`) used in merged release evidence (`latest_trend_window` and per-session `trend_window`).
|
|
774
774
|
- Run output includes `moqui_baseline` snapshot by default, with artifacts at `.kiro/reports/release-evidence/moqui-template-baseline.json` and `.kiro/reports/release-evidence/moqui-template-baseline.md`.
|
|
775
|
+
- Run output includes `moqui_capability_coverage` snapshot by default (when manifest `capabilities` is declared), with artifacts at `.kiro/reports/release-evidence/moqui-capability-coverage.json` and `.kiro/reports/release-evidence/moqui-capability-coverage.md`.
|
|
776
|
+
- When Moqui baseline/capability gates fail, KSE auto-generates remediation queue lines at `.kiro/auto/moqui-remediation.lines`.
|
|
775
777
|
- Run result includes `recommendations` with executable follow-up commands (for example, auto-generated `--continue-from <session>` on failed/incomplete batches).
|
|
776
|
-
- Gate defaults: `--min-spec-success-rate` defaults to `100`, `--max-risk-level` defaults to `high`,
|
|
777
|
-
- Use `--no-require-ontology-validation` only for emergency bypass
|
|
778
|
+
- Gate defaults: `--min-spec-success-rate` defaults to `100`, `--max-risk-level` defaults to `high`, ontology validation requirement is enabled by default, Moqui baseline requirement is enabled by default, and capability coverage minimum defaults to `100` when manifest `capabilities` is declared.
|
|
779
|
+
- Use `--no-require-ontology-validation`, `--no-require-moqui-baseline`, or `--no-require-capability-coverage` only for emergency bypass.
|
|
778
780
|
- `kse auto handoff regression [--session-id <id|latest>] [--window <n>] [--format <json|markdown>] [--out <path>] [--json]`: compare one handoff run report with its previous run and output trend deltas (success-rate/risk/failed-goals/elapsed time).
|
|
779
781
|
- `--window` (2-50, default `2`) returns multi-run `series`, `window_trend`, and `aggregates` for broader regression visibility.
|
|
780
782
|
- Regression JSON now includes `risk_layers` (low/medium/high/unknown buckets with per-layer session list and quality aggregates).
|
|
@@ -782,11 +784,11 @@ Dual-track handoff integration:
|
|
|
782
784
|
- Markdown report includes `Trend Series` (ASCII success/ontology bars per session) and `Risk Layer View`.
|
|
783
785
|
- `--out` writes the generated regression report using the selected format.
|
|
784
786
|
- Output includes `recommendations` to guide next action when trend degrades or risk escalates.
|
|
785
|
-
- `kse auto handoff evidence [--file <path>] [--session-id <id|latest>] [--window <n>] [--format <json|markdown>] [--out <path>] [--json]`: quick-review merged release evidence and render current-batch gate/ontology/regression/moqui-baseline/risk-layer overview.
|
|
787
|
+
- `kse auto handoff evidence [--file <path>] [--session-id <id|latest>] [--window <n>] [--format <json|markdown>] [--out <path>] [--json]`: quick-review merged release evidence and render current-batch gate/ontology/regression/moqui-baseline/capability-coverage/risk-layer overview.
|
|
786
788
|
- Default evidence file is `.kiro/reports/release-evidence/handoff-runs.json`.
|
|
787
789
|
- `--window` (1-50, default `5`) controls how many recent sessions are aggregated in review.
|
|
788
790
|
- JSON output includes `current_overview`, `aggregates.status_counts`, `aggregates.gate_pass_rate_percent`, and `risk_layers`.
|
|
789
|
-
- Markdown output includes `Current Gate`, `Current Ontology`, `Current Regression`, `Current Moqui Baseline`, `Trend Series`, and `Risk Layer View`.
|
|
791
|
+
- Markdown output includes `Current Gate`, `Current Ontology`, `Current Regression`, `Current Moqui Baseline`, `Current Capability Coverage`, `Trend Series`, and `Risk Layer View`.
|
|
790
792
|
- Add `--release-draft <path>` to auto-generate a release notes draft and evidence review markdown in one run.
|
|
791
793
|
- `--release-version` sets draft version tag (defaults to `v<package.json version>`), and `--release-date` accepts `YYYY-MM-DD` (default: current UTC date).
|
|
792
794
|
- Use `--review-out <path>` to override the generated evidence review markdown path (default `.kiro/reports/release-evidence/handoff-evidence-review.md`).
|
|
@@ -14,6 +14,8 @@ KSE defaults already enforce the baseline below:
|
|
|
14
14
|
|
|
15
15
|
- `kse auto handoff run`: ontology validation is required by default.
|
|
16
16
|
- `kse auto handoff run`: generates Moqui baseline snapshot by default and appends it to release-evidence sessions.
|
|
17
|
+
- `kse auto handoff run`: requires Moqui baseline portfolio pass by default.
|
|
18
|
+
- `kse auto handoff run`: evaluates capability coverage matrix by default when manifest `capabilities` is declared (default minimum `100%`).
|
|
17
19
|
- `kse scene package-publish-batch`:
|
|
18
20
|
- ontology validation required by default
|
|
19
21
|
- batch ontology gate defaults:
|
|
@@ -23,6 +25,8 @@ KSE defaults already enforce the baseline below:
|
|
|
23
25
|
Emergency bypass exists but is not recommended:
|
|
24
26
|
|
|
25
27
|
- `--no-require-ontology-validation`
|
|
28
|
+
- `--no-require-moqui-baseline`
|
|
29
|
+
- `--no-require-capability-coverage`
|
|
26
30
|
|
|
27
31
|
## One-Shot Intake Flow
|
|
28
32
|
|
|
@@ -65,8 +69,11 @@ Required artifacts for each intake batch:
|
|
|
65
69
|
- `.kiro/reports/moqui-template-baseline.md`
|
|
66
70
|
- `.kiro/reports/release-evidence/moqui-template-baseline.json`
|
|
67
71
|
- `.kiro/reports/release-evidence/moqui-template-baseline.md`
|
|
72
|
+
- `.kiro/reports/release-evidence/moqui-capability-coverage.json`
|
|
73
|
+
- `.kiro/reports/release-evidence/moqui-capability-coverage.md`
|
|
68
74
|
- `.kiro/reports/handoff-runs/<session>.json`
|
|
69
75
|
- `.kiro/reports/scene-package-ontology-batch.json`
|
|
76
|
+
- `.kiro/auto/moqui-remediation.lines` (when baseline/coverage gaps exist)
|
|
70
77
|
- `.kiro/templates/scene-packages/registry.json`
|
|
71
78
|
- gate output/evidence linked from release notes or handoff summary
|
|
72
79
|
|
package/lib/commands/auto.js
CHANGED
|
@@ -21,6 +21,9 @@ const AUTO_HANDOFF_RELEASE_EVIDENCE_DIR = '.kiro/reports/release-evidence';
|
|
|
21
21
|
const AUTO_HANDOFF_RELEASE_GATE_HISTORY_FILE = '.kiro/reports/release-evidence/release-gate-history.json';
|
|
22
22
|
const AUTO_HANDOFF_MOQUI_BASELINE_JSON_FILE = '.kiro/reports/release-evidence/moqui-template-baseline.json';
|
|
23
23
|
const AUTO_HANDOFF_MOQUI_BASELINE_MARKDOWN_FILE = '.kiro/reports/release-evidence/moqui-template-baseline.md';
|
|
24
|
+
const AUTO_HANDOFF_MOQUI_CAPABILITY_COVERAGE_JSON_FILE = '.kiro/reports/release-evidence/moqui-capability-coverage.json';
|
|
25
|
+
const AUTO_HANDOFF_MOQUI_CAPABILITY_COVERAGE_MARKDOWN_FILE = '.kiro/reports/release-evidence/moqui-capability-coverage.md';
|
|
26
|
+
const AUTO_HANDOFF_MOQUI_REMEDIATION_QUEUE_FILE = '.kiro/auto/moqui-remediation.lines';
|
|
24
27
|
|
|
25
28
|
/**
|
|
26
29
|
* Register auto commands
|
|
@@ -1664,6 +1667,22 @@ function registerAutoCommands(program) {
|
|
|
1664
1667
|
console.log(chalk.gray(` Portfolio: ${moquiSummary.portfolio_passed === true ? 'pass' : 'fail'} | avg=${scoreText} | valid-rate=${validRateText}`));
|
|
1665
1668
|
}
|
|
1666
1669
|
}
|
|
1670
|
+
if (result.current_overview && result.current_overview.capability_coverage) {
|
|
1671
|
+
const capabilityCoverage = result.current_overview.capability_coverage;
|
|
1672
|
+
const capabilitySummary = capabilityCoverage && capabilityCoverage.summary ? capabilityCoverage.summary : null;
|
|
1673
|
+
console.log(chalk.gray(` Capability coverage: ${capabilityCoverage.status || 'n/a'}`));
|
|
1674
|
+
if (capabilitySummary) {
|
|
1675
|
+
const coverageText = Number.isFinite(Number(capabilitySummary.coverage_percent))
|
|
1676
|
+
? `${capabilitySummary.coverage_percent}%`
|
|
1677
|
+
: 'n/a';
|
|
1678
|
+
console.log(
|
|
1679
|
+
chalk.gray(
|
|
1680
|
+
` Passed: ${capabilitySummary.passed === true ? 'yes' : 'no'} | ` +
|
|
1681
|
+
`coverage=${coverageText} | min=${capabilitySummary.min_required_percent}%`
|
|
1682
|
+
)
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1667
1686
|
if (result.output_file) {
|
|
1668
1687
|
console.log(chalk.gray(` Output: ${result.output_file}`));
|
|
1669
1688
|
}
|
|
@@ -1765,6 +1784,11 @@ function registerAutoCommands(program) {
|
|
|
1765
1784
|
.option('--max-undecided-decisions <n>', 'Gate: maximum allowed undecided decisions (optional)', parseInt)
|
|
1766
1785
|
.option('--require-ontology-validation', 'Gate: require manifest ontology_validation to be present and passed (default: enabled)')
|
|
1767
1786
|
.option('--no-require-ontology-validation', 'Gate: disable manifest ontology_validation requirement (not recommended)')
|
|
1787
|
+
.option('--require-moqui-baseline', 'Gate: require Moqui baseline portfolio to pass (default: enabled)')
|
|
1788
|
+
.option('--no-require-moqui-baseline', 'Gate: disable Moqui baseline portfolio requirement (not recommended)')
|
|
1789
|
+
.option('--min-capability-coverage <n>', 'Gate: minimum Moqui capability coverage percent (default: 100)', parseFloat)
|
|
1790
|
+
.option('--require-capability-coverage', 'Gate: require capability coverage threshold when capabilities are declared (default: enabled)')
|
|
1791
|
+
.option('--no-require-capability-coverage', 'Gate: disable capability coverage requirement (not recommended)')
|
|
1768
1792
|
.option('--release-evidence-window <n>', 'Release evidence trend window size (2-50, default: 5)', parseInt)
|
|
1769
1793
|
.option('--json', 'Output machine-readable JSON')
|
|
1770
1794
|
.action(async (options) => {
|
|
@@ -1804,6 +1828,24 @@ function registerAutoCommands(program) {
|
|
|
1804
1828
|
console.log(chalk.gray(` Baseline report: ${result.moqui_baseline.output.json}`));
|
|
1805
1829
|
}
|
|
1806
1830
|
}
|
|
1831
|
+
if (result.moqui_capability_coverage) {
|
|
1832
|
+
console.log(chalk.gray(` Capability coverage: ${result.moqui_capability_coverage.status || 'unknown'}`));
|
|
1833
|
+
if (result.moqui_capability_coverage.summary) {
|
|
1834
|
+
const coverageSummary = result.moqui_capability_coverage.summary;
|
|
1835
|
+
const coverageText = Number.isFinite(Number(coverageSummary.coverage_percent))
|
|
1836
|
+
? `${coverageSummary.coverage_percent}%`
|
|
1837
|
+
: 'n/a';
|
|
1838
|
+
console.log(
|
|
1839
|
+
chalk.gray(
|
|
1840
|
+
` Passed: ${coverageSummary.passed === true ? 'yes' : 'no'} | ` +
|
|
1841
|
+
`coverage=${coverageText} | min=${coverageSummary.min_required_percent}%`
|
|
1842
|
+
)
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
if (result.remediation_queue && result.remediation_queue.file) {
|
|
1847
|
+
console.log(chalk.gray(` Remediation queue: ${toAutoHandoffCliPath(process.cwd(), result.remediation_queue.file)} (${result.remediation_queue.goal_count})`));
|
|
1848
|
+
}
|
|
1807
1849
|
if (result.output_file) {
|
|
1808
1850
|
console.log(chalk.gray(` Report: ${result.output_file}`));
|
|
1809
1851
|
}
|
|
@@ -6911,6 +6953,16 @@ function normalizeAutoHandoffManifest(payload = {}) {
|
|
|
6911
6953
|
validationWarnings.push('templates is empty');
|
|
6912
6954
|
}
|
|
6913
6955
|
|
|
6956
|
+
const capabilitiesCollected = collectUniqueIdentifiers(
|
|
6957
|
+
payload.capabilities,
|
|
6958
|
+
['name', 'capability', 'capability_name', 'id', 'capability.id', 'capability.name'],
|
|
6959
|
+
'capabilities'
|
|
6960
|
+
);
|
|
6961
|
+
validationWarnings.push(...capabilitiesCollected.warnings);
|
|
6962
|
+
if (capabilitiesCollected.values.length === 0) {
|
|
6963
|
+
validationWarnings.push('capabilities is empty; capability coverage gate will be skipped unless capabilities are declared');
|
|
6964
|
+
}
|
|
6965
|
+
|
|
6914
6966
|
const knownGapCollected = collectKnownGaps(payload.known_gaps);
|
|
6915
6967
|
validationWarnings.push(...knownGapCollected.warnings);
|
|
6916
6968
|
|
|
@@ -6932,6 +6984,7 @@ function normalizeAutoHandoffManifest(payload = {}) {
|
|
|
6932
6984
|
spec_descriptors: specsCollected.descriptors,
|
|
6933
6985
|
dependency_batches: dependencyBatches,
|
|
6934
6986
|
templates: templatesCollected.values,
|
|
6987
|
+
capabilities: capabilitiesCollected.values,
|
|
6935
6988
|
known_gaps: knownGapCollected.gaps,
|
|
6936
6989
|
ontology_validation: ontologyValidation,
|
|
6937
6990
|
next_batch: nextBatch,
|
|
@@ -7039,11 +7092,13 @@ async function buildAutoHandoffPlan(projectPath, options = {}) {
|
|
|
7039
7092
|
timestamp: handoff.timestamp,
|
|
7040
7093
|
spec_count: handoff.specs.length,
|
|
7041
7094
|
template_count: handoff.templates.length,
|
|
7095
|
+
capability_count: Array.isArray(handoff.capabilities) ? handoff.capabilities.length : 0,
|
|
7042
7096
|
known_gap_count: handoff.known_gaps.length,
|
|
7043
7097
|
specs: handoff.specs,
|
|
7044
7098
|
spec_descriptors: handoff.spec_descriptors,
|
|
7045
7099
|
dependency_batches: handoff.dependency_batches,
|
|
7046
7100
|
templates: handoff.templates,
|
|
7101
|
+
capabilities: handoff.capabilities,
|
|
7047
7102
|
known_gaps: handoff.known_gaps,
|
|
7048
7103
|
ontology_validation: handoff.ontology_validation,
|
|
7049
7104
|
next_batch: handoff.next_batch
|
|
@@ -8923,6 +8978,19 @@ function buildAutoHandoffEvidenceSnapshot(entry = {}) {
|
|
|
8923
8978
|
),
|
|
8924
8979
|
ontology_business_rule_pass_rate_percent: toNumber(ontologyMetrics.business_rule_pass_rate_percent),
|
|
8925
8980
|
ontology_decision_resolved_rate_percent: toNumber(ontologyMetrics.decision_resolved_rate_percent),
|
|
8981
|
+
capability_coverage_percent: toNumber(
|
|
8982
|
+
entry &&
|
|
8983
|
+
entry.capability_coverage &&
|
|
8984
|
+
entry.capability_coverage.summary
|
|
8985
|
+
? entry.capability_coverage.summary.coverage_percent
|
|
8986
|
+
: null
|
|
8987
|
+
),
|
|
8988
|
+
capability_coverage_passed: Boolean(
|
|
8989
|
+
entry &&
|
|
8990
|
+
entry.capability_coverage &&
|
|
8991
|
+
entry.capability_coverage.summary &&
|
|
8992
|
+
entry.capability_coverage.summary.passed === true
|
|
8993
|
+
),
|
|
8926
8994
|
generated_at: normalizeHandoffText(entry.merged_at)
|
|
8927
8995
|
};
|
|
8928
8996
|
}
|
|
@@ -8985,6 +9053,18 @@ function renderAutoHandoffEvidenceReviewMarkdown(payload = {}) {
|
|
|
8985
9053
|
const moquiFailedTemplates = moquiCompare && moquiCompare.failed_templates && typeof moquiCompare.failed_templates === 'object'
|
|
8986
9054
|
? moquiCompare.failed_templates
|
|
8987
9055
|
: {};
|
|
9056
|
+
const capabilityCoverage = currentOverview.capability_coverage && typeof currentOverview.capability_coverage === 'object'
|
|
9057
|
+
? currentOverview.capability_coverage
|
|
9058
|
+
: {};
|
|
9059
|
+
const capabilitySummary = capabilityCoverage && capabilityCoverage.summary && typeof capabilityCoverage.summary === 'object'
|
|
9060
|
+
? capabilityCoverage.summary
|
|
9061
|
+
: {};
|
|
9062
|
+
const capabilityCompare = capabilityCoverage && capabilityCoverage.compare && typeof capabilityCoverage.compare === 'object'
|
|
9063
|
+
? capabilityCoverage.compare
|
|
9064
|
+
: {};
|
|
9065
|
+
const capabilityGaps = Array.isArray(capabilityCoverage && capabilityCoverage.gaps)
|
|
9066
|
+
? capabilityCoverage.gaps
|
|
9067
|
+
: [];
|
|
8988
9068
|
const window = payload.window || { requested: 5, actual: 0 };
|
|
8989
9069
|
const series = Array.isArray(payload.series) ? payload.series : [];
|
|
8990
9070
|
const riskLayers = payload.risk_layers && typeof payload.risk_layers === 'object'
|
|
@@ -8999,7 +9079,11 @@ function renderAutoHandoffEvidenceReviewMarkdown(payload = {}) {
|
|
|
8999
9079
|
const failedGoals = formatAutoHandoffRegressionValue(item.failed_goals);
|
|
9000
9080
|
const successBar = renderAutoHandoffRegressionAsciiBar(item.spec_success_rate_percent, 100, 20);
|
|
9001
9081
|
const ontologyBar = renderAutoHandoffRegressionAsciiBar(item.ontology_quality_score, 100, 20);
|
|
9002
|
-
|
|
9082
|
+
const capabilityBar = renderAutoHandoffRegressionAsciiBar(item.capability_coverage_percent, 100, 20);
|
|
9083
|
+
return (
|
|
9084
|
+
`- ${sessionId} | ${mergedAt} | risk=${riskLevel} | failed=${failedGoals} | ` +
|
|
9085
|
+
`success=${successBar} | ontology=${ontologyBar} | capability=${capabilityBar}`
|
|
9086
|
+
);
|
|
9003
9087
|
})
|
|
9004
9088
|
: ['- None'];
|
|
9005
9089
|
const riskLayerLines = ['low', 'medium', 'high', 'unknown'].map(level => {
|
|
@@ -9062,6 +9146,21 @@ function renderAutoHandoffEvidenceReviewMarkdown(payload = {}) {
|
|
|
9062
9146
|
`- Recovered templates: ${Array.isArray(moquiFailedTemplates.recovered) && moquiFailedTemplates.recovered.length > 0 ? moquiFailedTemplates.recovered.join(', ') : 'none'}`,
|
|
9063
9147
|
`- Baseline JSON: ${formatAutoHandoffRegressionValue(moquiBaseline.output && moquiBaseline.output.json)}`,
|
|
9064
9148
|
'',
|
|
9149
|
+
'## Current Capability Coverage',
|
|
9150
|
+
'',
|
|
9151
|
+
`- Status: ${formatAutoHandoffRegressionValue(capabilityCoverage.status)}`,
|
|
9152
|
+
`- Passed: ${capabilitySummary.passed === true ? 'yes' : (capabilitySummary.passed === false ? 'no' : 'n/a')}`,
|
|
9153
|
+
`- Coverage: ${formatAutoHandoffRegressionValue(capabilitySummary.coverage_percent)}%`,
|
|
9154
|
+
`- Min required: ${formatAutoHandoffRegressionValue(capabilitySummary.min_required_percent)}%`,
|
|
9155
|
+
`- Covered capabilities: ${formatAutoHandoffRegressionValue(capabilitySummary.covered_capabilities)}`,
|
|
9156
|
+
`- Uncovered capabilities: ${formatAutoHandoffRegressionValue(capabilitySummary.uncovered_capabilities)}`,
|
|
9157
|
+
`- Delta coverage: ${formatAutoHandoffRegressionValue(capabilityCompare.delta_coverage_percent)}%`,
|
|
9158
|
+
`- Delta covered capabilities: ${formatAutoHandoffRegressionValue(capabilityCompare.delta_covered_capabilities)}`,
|
|
9159
|
+
`- Newly covered: ${Array.isArray(capabilityCompare.newly_covered) && capabilityCompare.newly_covered.length > 0 ? capabilityCompare.newly_covered.join(', ') : 'none'}`,
|
|
9160
|
+
`- Newly uncovered: ${Array.isArray(capabilityCompare.newly_uncovered) && capabilityCompare.newly_uncovered.length > 0 ? capabilityCompare.newly_uncovered.join(', ') : 'none'}`,
|
|
9161
|
+
`- Capability gaps: ${capabilityGaps.length > 0 ? capabilityGaps.join(', ') : 'none'}`,
|
|
9162
|
+
`- Coverage JSON: ${formatAutoHandoffRegressionValue(capabilityCoverage.output && capabilityCoverage.output.json)}`,
|
|
9163
|
+
'',
|
|
9065
9164
|
'## Trend Series',
|
|
9066
9165
|
'',
|
|
9067
9166
|
...trendSeriesLines,
|
|
@@ -9168,6 +9267,18 @@ function renderAutoHandoffReleaseNotesDraft(payload = {}, context = {}) {
|
|
|
9168
9267
|
const moquiFailedTemplates = moquiCompare && moquiCompare.failed_templates && typeof moquiCompare.failed_templates === 'object'
|
|
9169
9268
|
? moquiCompare.failed_templates
|
|
9170
9269
|
: {};
|
|
9270
|
+
const capabilityCoverage = currentOverview.capability_coverage && typeof currentOverview.capability_coverage === 'object'
|
|
9271
|
+
? currentOverview.capability_coverage
|
|
9272
|
+
: {};
|
|
9273
|
+
const capabilitySummary = capabilityCoverage && capabilityCoverage.summary && typeof capabilityCoverage.summary === 'object'
|
|
9274
|
+
? capabilityCoverage.summary
|
|
9275
|
+
: {};
|
|
9276
|
+
const capabilityCompare = capabilityCoverage && capabilityCoverage.compare && typeof capabilityCoverage.compare === 'object'
|
|
9277
|
+
? capabilityCoverage.compare
|
|
9278
|
+
: {};
|
|
9279
|
+
const capabilityGaps = Array.isArray(capabilityCoverage && capabilityCoverage.gaps)
|
|
9280
|
+
? capabilityCoverage.gaps
|
|
9281
|
+
: [];
|
|
9171
9282
|
const riskLayers = payload.risk_layers && typeof payload.risk_layers === 'object'
|
|
9172
9283
|
? payload.risk_layers
|
|
9173
9284
|
: {};
|
|
@@ -9219,6 +9330,13 @@ function renderAutoHandoffReleaseNotesDraft(payload = {}, context = {}) {
|
|
|
9219
9330
|
`- Moqui baseline avg score delta: ${formatAutoHandoffRegressionValue(moquiDeltas.avg_score)}`,
|
|
9220
9331
|
`- Moqui baseline valid-rate delta: ${formatAutoHandoffRegressionValue(moquiDeltas.valid_rate_percent)}%`,
|
|
9221
9332
|
`- Moqui newly failed templates: ${Array.isArray(moquiFailedTemplates.newly_failed) && moquiFailedTemplates.newly_failed.length > 0 ? moquiFailedTemplates.newly_failed.join(', ') : 'none'}`,
|
|
9333
|
+
`- Capability coverage status: ${formatAutoHandoffRegressionValue(capabilityCoverage.status)}`,
|
|
9334
|
+
`- Capability coverage passed: ${capabilitySummary.passed === true ? 'yes' : (capabilitySummary.passed === false ? 'no' : 'n/a')}`,
|
|
9335
|
+
`- Capability coverage: ${formatAutoHandoffRegressionValue(capabilitySummary.coverage_percent)}%`,
|
|
9336
|
+
`- Capability min required: ${formatAutoHandoffRegressionValue(capabilitySummary.min_required_percent)}%`,
|
|
9337
|
+
`- Capability coverage delta: ${formatAutoHandoffRegressionValue(capabilityCompare.delta_coverage_percent)}%`,
|
|
9338
|
+
`- Capability newly uncovered: ${Array.isArray(capabilityCompare.newly_uncovered) && capabilityCompare.newly_uncovered.length > 0 ? capabilityCompare.newly_uncovered.join(', ') : 'none'}`,
|
|
9339
|
+
`- Capability gaps: ${capabilityGaps.length > 0 ? capabilityGaps.join(', ') : 'none'}`,
|
|
9222
9340
|
'',
|
|
9223
9341
|
'## Status Breakdown',
|
|
9224
9342
|
'',
|
|
@@ -9239,6 +9357,8 @@ function renderAutoHandoffReleaseNotesDraft(payload = {}, context = {}) {
|
|
|
9239
9357
|
`- Release evidence JSON: ${formatAutoHandoffRegressionValue(payload.evidence_file)}`,
|
|
9240
9358
|
`- Moqui baseline JSON: ${formatAutoHandoffRegressionValue(moquiBaseline.output && moquiBaseline.output.json)}`,
|
|
9241
9359
|
`- Moqui baseline markdown: ${formatAutoHandoffRegressionValue(moquiBaseline.output && moquiBaseline.output.markdown)}`,
|
|
9360
|
+
`- Capability coverage JSON: ${formatAutoHandoffRegressionValue(capabilityCoverage.output && capabilityCoverage.output.json)}`,
|
|
9361
|
+
`- Capability coverage markdown: ${formatAutoHandoffRegressionValue(capabilityCoverage.output && capabilityCoverage.output.markdown)}`,
|
|
9242
9362
|
'',
|
|
9243
9363
|
'## Recommendations'
|
|
9244
9364
|
];
|
|
@@ -9454,6 +9574,17 @@ function normalizeHandoffMinOntologyScore(scoreCandidate) {
|
|
|
9454
9574
|
return Number(parsed.toFixed(2));
|
|
9455
9575
|
}
|
|
9456
9576
|
|
|
9577
|
+
function normalizeHandoffMinCapabilityCoverage(coverageCandidate) {
|
|
9578
|
+
if (coverageCandidate === undefined || coverageCandidate === null) {
|
|
9579
|
+
return 100;
|
|
9580
|
+
}
|
|
9581
|
+
const parsed = Number(coverageCandidate);
|
|
9582
|
+
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 100) {
|
|
9583
|
+
throw new Error('--min-capability-coverage must be a number between 0 and 100.');
|
|
9584
|
+
}
|
|
9585
|
+
return Number(parsed.toFixed(2));
|
|
9586
|
+
}
|
|
9587
|
+
|
|
9457
9588
|
function normalizeHandoffOptionalNonNegativeInteger(valueCandidate, optionName) {
|
|
9458
9589
|
if (valueCandidate === undefined || valueCandidate === null || valueCandidate === '') {
|
|
9459
9590
|
return null;
|
|
@@ -9481,6 +9612,7 @@ function buildAutoHandoffRunPolicy(options = {}) {
|
|
|
9481
9612
|
min_spec_success_rate: normalizeHandoffMinSpecSuccessRate(options.minSpecSuccessRate),
|
|
9482
9613
|
max_risk_level: normalizeHandoffRiskLevel(options.maxRiskLevel),
|
|
9483
9614
|
min_ontology_score: normalizeHandoffMinOntologyScore(options.minOntologyScore),
|
|
9615
|
+
min_capability_coverage_percent: normalizeHandoffMinCapabilityCoverage(options.minCapabilityCoverage),
|
|
9484
9616
|
max_unmapped_rules: normalizeHandoffOptionalNonNegativeInteger(
|
|
9485
9617
|
options.maxUnmappedRules,
|
|
9486
9618
|
'--max-unmapped-rules'
|
|
@@ -9490,6 +9622,8 @@ function buildAutoHandoffRunPolicy(options = {}) {
|
|
|
9490
9622
|
'--max-undecided-decisions'
|
|
9491
9623
|
),
|
|
9492
9624
|
require_ontology_validation: options.requireOntologyValidation !== false,
|
|
9625
|
+
require_moqui_baseline: options.requireMoquiBaseline !== false,
|
|
9626
|
+
require_capability_coverage: options.requireCapabilityCoverage !== false,
|
|
9493
9627
|
dependency_batching: options.dependencyBatching !== false,
|
|
9494
9628
|
release_evidence_window: normalizeHandoffReleaseEvidenceWindow(options.releaseEvidenceWindow)
|
|
9495
9629
|
};
|
|
@@ -9793,6 +9927,84 @@ function evaluateAutoHandoffOntologyGateReasons(policy = {}, ontology = {}) {
|
|
|
9793
9927
|
return reasons;
|
|
9794
9928
|
}
|
|
9795
9929
|
|
|
9930
|
+
function evaluateAutoHandoffMoquiBaselineGateReasons(policy = {}, moquiBaseline = null) {
|
|
9931
|
+
const reasons = [];
|
|
9932
|
+
if (policy.require_moqui_baseline !== true) {
|
|
9933
|
+
return reasons;
|
|
9934
|
+
}
|
|
9935
|
+
|
|
9936
|
+
const baseline = moquiBaseline && typeof moquiBaseline === 'object'
|
|
9937
|
+
? moquiBaseline
|
|
9938
|
+
: null;
|
|
9939
|
+
const summary = baseline && baseline.summary && typeof baseline.summary === 'object'
|
|
9940
|
+
? baseline.summary
|
|
9941
|
+
: {};
|
|
9942
|
+
const status = `${baseline && baseline.status ? baseline.status : 'missing'}`.trim().toLowerCase();
|
|
9943
|
+
if (!baseline || baseline.generated !== true) {
|
|
9944
|
+
const reason = baseline && baseline.reason ? baseline.reason : 'moqui baseline snapshot missing';
|
|
9945
|
+
reasons.push(`moqui baseline unavailable: ${reason}`);
|
|
9946
|
+
return reasons;
|
|
9947
|
+
}
|
|
9948
|
+
if (status === 'error') {
|
|
9949
|
+
reasons.push(`moqui baseline errored: ${baseline.error || 'unknown error'}`);
|
|
9950
|
+
return reasons;
|
|
9951
|
+
}
|
|
9952
|
+
if (summary.portfolio_passed !== true) {
|
|
9953
|
+
const avgScore = Number(summary.avg_score);
|
|
9954
|
+
const validRate = Number(summary.valid_rate_percent);
|
|
9955
|
+
reasons.push(
|
|
9956
|
+
`moqui baseline portfolio not passed (avg_score=${Number.isFinite(avgScore) ? avgScore : 'n/a'}, ` +
|
|
9957
|
+
`valid_rate=${Number.isFinite(validRate) ? `${validRate}%` : 'n/a'})`
|
|
9958
|
+
);
|
|
9959
|
+
}
|
|
9960
|
+
return reasons;
|
|
9961
|
+
}
|
|
9962
|
+
|
|
9963
|
+
function evaluateAutoHandoffCapabilityCoverageGateReasons(policy = {}, capabilityCoverage = null) {
|
|
9964
|
+
const reasons = [];
|
|
9965
|
+
if (policy.require_capability_coverage !== true) {
|
|
9966
|
+
return reasons;
|
|
9967
|
+
}
|
|
9968
|
+
|
|
9969
|
+
const coverage = capabilityCoverage && typeof capabilityCoverage === 'object'
|
|
9970
|
+
? capabilityCoverage
|
|
9971
|
+
: null;
|
|
9972
|
+
if (!coverage) {
|
|
9973
|
+
reasons.push('capability coverage snapshot missing');
|
|
9974
|
+
return reasons;
|
|
9975
|
+
}
|
|
9976
|
+
if (coverage.status === 'error') {
|
|
9977
|
+
reasons.push(`capability coverage errored: ${coverage.error || 'unknown error'}`);
|
|
9978
|
+
return reasons;
|
|
9979
|
+
}
|
|
9980
|
+
if (coverage.status === 'skipped') {
|
|
9981
|
+
const totalCapabilities = Number(
|
|
9982
|
+
coverage &&
|
|
9983
|
+
coverage.summary &&
|
|
9984
|
+
coverage.summary.total_capabilities !== undefined
|
|
9985
|
+
? coverage.summary.total_capabilities
|
|
9986
|
+
: 0
|
|
9987
|
+
);
|
|
9988
|
+
if (Number.isFinite(totalCapabilities) && totalCapabilities <= 0) {
|
|
9989
|
+
return reasons;
|
|
9990
|
+
}
|
|
9991
|
+
reasons.push(`capability coverage skipped: ${coverage.reason || 'unknown reason'}`);
|
|
9992
|
+
return reasons;
|
|
9993
|
+
}
|
|
9994
|
+
|
|
9995
|
+
const summary = coverage.summary && typeof coverage.summary === 'object'
|
|
9996
|
+
? coverage.summary
|
|
9997
|
+
: {};
|
|
9998
|
+
const coveragePercent = Number(summary.coverage_percent);
|
|
9999
|
+
const minCoverage = Number(policy.min_capability_coverage_percent);
|
|
10000
|
+
if (!Number.isFinite(coveragePercent)) {
|
|
10001
|
+
reasons.push('capability_coverage_percent unavailable');
|
|
10002
|
+
} else if (Number.isFinite(minCoverage) && coveragePercent < minCoverage) {
|
|
10003
|
+
reasons.push(`capability_coverage_percent ${coveragePercent} < required ${minCoverage}`);
|
|
10004
|
+
}
|
|
10005
|
+
return reasons;
|
|
10006
|
+
}
|
|
10007
|
+
|
|
9796
10008
|
function collectHandoffBlockers(resultItem) {
|
|
9797
10009
|
const blockers = [];
|
|
9798
10010
|
if (!resultItem) {
|
|
@@ -9877,6 +10089,12 @@ function evaluateAutoHandoffRunGates(context = {}) {
|
|
|
9877
10089
|
present: false,
|
|
9878
10090
|
passed: false
|
|
9879
10091
|
};
|
|
10092
|
+
const moquiBaseline = context.moquiBaseline && typeof context.moquiBaseline === 'object'
|
|
10093
|
+
? context.moquiBaseline
|
|
10094
|
+
: null;
|
|
10095
|
+
const capabilityCoverage = context.capabilityCoverage && typeof context.capabilityCoverage === 'object'
|
|
10096
|
+
? context.capabilityCoverage
|
|
10097
|
+
: null;
|
|
9880
10098
|
const kpi = context.programKpi || {
|
|
9881
10099
|
risk_level: 'high'
|
|
9882
10100
|
};
|
|
@@ -9902,6 +10120,8 @@ function evaluateAutoHandoffRunGates(context = {}) {
|
|
|
9902
10120
|
}
|
|
9903
10121
|
|
|
9904
10122
|
reasons.push(...evaluateAutoHandoffOntologyGateReasons(policy, ontology));
|
|
10123
|
+
reasons.push(...evaluateAutoHandoffMoquiBaselineGateReasons(policy, moquiBaseline));
|
|
10124
|
+
reasons.push(...evaluateAutoHandoffCapabilityCoverageGateReasons(policy, capabilityCoverage));
|
|
9905
10125
|
|
|
9906
10126
|
return {
|
|
9907
10127
|
passed: reasons.length === 0,
|
|
@@ -9935,6 +10155,18 @@ function evaluateAutoHandoffRunGates(context = {}) {
|
|
|
9935
10155
|
Number(ontology && ontology.metrics ? ontology.metrics.decision_resolved_rate_percent : null)
|
|
9936
10156
|
)
|
|
9937
10157
|
? Number(ontology.metrics.decision_resolved_rate_percent)
|
|
10158
|
+
: null,
|
|
10159
|
+
moqui_baseline_status: normalizeHandoffText(moquiBaseline && moquiBaseline.status),
|
|
10160
|
+
moqui_baseline_portfolio_passed: Boolean(
|
|
10161
|
+
moquiBaseline &&
|
|
10162
|
+
moquiBaseline.summary &&
|
|
10163
|
+
moquiBaseline.summary.portfolio_passed === true
|
|
10164
|
+
),
|
|
10165
|
+
capability_coverage_status: normalizeHandoffText(capabilityCoverage && capabilityCoverage.status),
|
|
10166
|
+
capability_coverage_percent: Number.isFinite(
|
|
10167
|
+
Number(capabilityCoverage && capabilityCoverage.summary ? capabilityCoverage.summary.coverage_percent : null)
|
|
10168
|
+
)
|
|
10169
|
+
? Number(capabilityCoverage.summary.coverage_percent)
|
|
9938
10170
|
: null
|
|
9939
10171
|
},
|
|
9940
10172
|
reasons
|
|
@@ -10024,6 +10256,14 @@ function buildAutoHandoffRunRecommendations(projectPath, result) {
|
|
|
10024
10256
|
push('kse auto governance stats --days 14 --json');
|
|
10025
10257
|
}
|
|
10026
10258
|
|
|
10259
|
+
if (result && result.remediation_queue && result.remediation_queue.file) {
|
|
10260
|
+
push(
|
|
10261
|
+
`kse auto close-loop-batch ${quoteCliArg(
|
|
10262
|
+
toAutoHandoffCliPath(projectPath, result.remediation_queue.file)
|
|
10263
|
+
)} --format lines --json`
|
|
10264
|
+
);
|
|
10265
|
+
}
|
|
10266
|
+
|
|
10027
10267
|
const moquiBaseline = result && result.moqui_baseline && typeof result.moqui_baseline === 'object'
|
|
10028
10268
|
? result.moqui_baseline
|
|
10029
10269
|
: null;
|
|
@@ -10043,6 +10283,20 @@ function buildAutoHandoffRunRecommendations(projectPath, result) {
|
|
|
10043
10283
|
);
|
|
10044
10284
|
}
|
|
10045
10285
|
|
|
10286
|
+
const capabilityCoverage = result && result.moqui_capability_coverage && typeof result.moqui_capability_coverage === 'object'
|
|
10287
|
+
? result.moqui_capability_coverage
|
|
10288
|
+
: null;
|
|
10289
|
+
const capabilitySummary = capabilityCoverage && capabilityCoverage.summary && typeof capabilityCoverage.summary === 'object'
|
|
10290
|
+
? capabilityCoverage.summary
|
|
10291
|
+
: null;
|
|
10292
|
+
if (capabilityCoverage && capabilityCoverage.status === 'error') {
|
|
10293
|
+
push('declare manifest capabilities and rerun `kse auto handoff run` to rebuild capability coverage evidence');
|
|
10294
|
+
} else if (capabilitySummary && capabilitySummary.passed === false) {
|
|
10295
|
+
push('complete uncovered moqui capabilities and rerun `kse auto handoff run --json`');
|
|
10296
|
+
} else if (capabilityCoverage && capabilityCoverage.status === 'skipped') {
|
|
10297
|
+
push('declare `capabilities` in handoff manifest to enable machine-checkable moqui capability coverage');
|
|
10298
|
+
}
|
|
10299
|
+
|
|
10046
10300
|
return recommendations;
|
|
10047
10301
|
}
|
|
10048
10302
|
|
|
@@ -10145,6 +10399,18 @@ function buildAutoHandoffReleaseEvidenceEntry(projectPath, result, reportFile =
|
|
|
10145
10399
|
const moquiFailedTemplates = moquiCompare && moquiCompare.failed_templates && typeof moquiCompare.failed_templates === 'object'
|
|
10146
10400
|
? moquiCompare.failed_templates
|
|
10147
10401
|
: {};
|
|
10402
|
+
const capabilityCoverage = result && result.moqui_capability_coverage && typeof result.moqui_capability_coverage === 'object'
|
|
10403
|
+
? result.moqui_capability_coverage
|
|
10404
|
+
: {};
|
|
10405
|
+
const capabilitySummary = capabilityCoverage && capabilityCoverage.summary && typeof capabilityCoverage.summary === 'object'
|
|
10406
|
+
? capabilityCoverage.summary
|
|
10407
|
+
: {};
|
|
10408
|
+
const capabilityCompare = capabilityCoverage && capabilityCoverage.compare && typeof capabilityCoverage.compare === 'object'
|
|
10409
|
+
? capabilityCoverage.compare
|
|
10410
|
+
: {};
|
|
10411
|
+
const capabilityGaps = Array.isArray(capabilityCoverage && capabilityCoverage.gaps)
|
|
10412
|
+
? capabilityCoverage.gaps
|
|
10413
|
+
: [];
|
|
10148
10414
|
const batchSummary = result && result.batch_summary && typeof result.batch_summary === 'object'
|
|
10149
10415
|
? result.batch_summary
|
|
10150
10416
|
: {};
|
|
@@ -10239,6 +10505,34 @@ function buildAutoHandoffReleaseEvidenceEntry(projectPath, result, reportFile =
|
|
|
10239
10505
|
markdown: normalizeHandoffText(moquiBaseline && moquiBaseline.output ? moquiBaseline.output.markdown : null)
|
|
10240
10506
|
}
|
|
10241
10507
|
},
|
|
10508
|
+
capability_coverage: {
|
|
10509
|
+
status: normalizeHandoffText(capabilityCoverage.status),
|
|
10510
|
+
generated: capabilityCoverage.generated === true,
|
|
10511
|
+
reason: normalizeHandoffText(capabilityCoverage.reason),
|
|
10512
|
+
error: normalizeHandoffText(capabilityCoverage.error),
|
|
10513
|
+
summary: {
|
|
10514
|
+
total_capabilities: toNumber(capabilitySummary.total_capabilities),
|
|
10515
|
+
covered_capabilities: toNumber(capabilitySummary.covered_capabilities),
|
|
10516
|
+
uncovered_capabilities: toNumber(capabilitySummary.uncovered_capabilities),
|
|
10517
|
+
coverage_percent: toNumber(capabilitySummary.coverage_percent),
|
|
10518
|
+
min_required_percent: toNumber(capabilitySummary.min_required_percent),
|
|
10519
|
+
passed: capabilitySummary.passed === true
|
|
10520
|
+
},
|
|
10521
|
+
compare: Object.keys(capabilityCompare).length === 0
|
|
10522
|
+
? null
|
|
10523
|
+
: {
|
|
10524
|
+
previous_generated_at: normalizeHandoffText(capabilityCompare.previous_generated_at),
|
|
10525
|
+
delta_coverage_percent: toNumber(capabilityCompare.delta_coverage_percent),
|
|
10526
|
+
delta_covered_capabilities: toNumber(capabilityCompare.delta_covered_capabilities),
|
|
10527
|
+
newly_covered: Array.isArray(capabilityCompare.newly_covered) ? capabilityCompare.newly_covered : [],
|
|
10528
|
+
newly_uncovered: Array.isArray(capabilityCompare.newly_uncovered) ? capabilityCompare.newly_uncovered : []
|
|
10529
|
+
},
|
|
10530
|
+
gaps: capabilityGaps,
|
|
10531
|
+
output: {
|
|
10532
|
+
json: normalizeHandoffText(capabilityCoverage && capabilityCoverage.output ? capabilityCoverage.output.json : null),
|
|
10533
|
+
markdown: normalizeHandoffText(capabilityCoverage && capabilityCoverage.output ? capabilityCoverage.output.markdown : null)
|
|
10534
|
+
}
|
|
10535
|
+
},
|
|
10242
10536
|
batch_summary: {
|
|
10243
10537
|
status: normalizeHandoffText(batchSummary.status),
|
|
10244
10538
|
total_goals: toNumber(batchSummary.total_goals),
|
|
@@ -10478,6 +10772,8 @@ async function buildAutoHandoffMoquiBaselineSnapshot(projectPath) {
|
|
|
10478
10772
|
previous_template_root: compare.previous_template_root || null,
|
|
10479
10773
|
deltas: compare.deltas || null,
|
|
10480
10774
|
failed_templates: {
|
|
10775
|
+
previous: Array.isArray(failedTemplates.previous) ? failedTemplates.previous : [],
|
|
10776
|
+
current: Array.isArray(failedTemplates.current) ? failedTemplates.current : [],
|
|
10481
10777
|
newly_failed: Array.isArray(failedTemplates.newly_failed) ? failedTemplates.newly_failed : [],
|
|
10482
10778
|
recovered: Array.isArray(failedTemplates.recovered) ? failedTemplates.recovered : []
|
|
10483
10779
|
}
|
|
@@ -10491,6 +10787,377 @@ async function buildAutoHandoffMoquiBaselineSnapshot(projectPath) {
|
|
|
10491
10787
|
};
|
|
10492
10788
|
}
|
|
10493
10789
|
|
|
10790
|
+
function normalizeMoquiCapabilityToken(value) {
|
|
10791
|
+
if (value === undefined || value === null) {
|
|
10792
|
+
return null;
|
|
10793
|
+
}
|
|
10794
|
+
const normalized = `${value}`
|
|
10795
|
+
.trim()
|
|
10796
|
+
.toLowerCase()
|
|
10797
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
10798
|
+
.replace(/^-+|-+$/g, '');
|
|
10799
|
+
return normalized.length > 0 ? normalized : null;
|
|
10800
|
+
}
|
|
10801
|
+
|
|
10802
|
+
function tokenizeMoquiCapability(value) {
|
|
10803
|
+
const normalized = normalizeMoquiCapabilityToken(value);
|
|
10804
|
+
if (!normalized) {
|
|
10805
|
+
return [];
|
|
10806
|
+
}
|
|
10807
|
+
return normalized.split('-').map(item => item.trim()).filter(Boolean);
|
|
10808
|
+
}
|
|
10809
|
+
|
|
10810
|
+
function moquiCapabilityMatch(expected, provided) {
|
|
10811
|
+
const left = normalizeMoquiCapabilityToken(expected);
|
|
10812
|
+
const right = normalizeMoquiCapabilityToken(provided);
|
|
10813
|
+
if (!left || !right) {
|
|
10814
|
+
return false;
|
|
10815
|
+
}
|
|
10816
|
+
if (left === right) {
|
|
10817
|
+
return true;
|
|
10818
|
+
}
|
|
10819
|
+
if ((left.length >= 8 && left.includes(right)) || (right.length >= 8 && right.includes(left))) {
|
|
10820
|
+
return true;
|
|
10821
|
+
}
|
|
10822
|
+
const leftTokens = tokenizeMoquiCapability(left);
|
|
10823
|
+
const rightTokens = tokenizeMoquiCapability(right);
|
|
10824
|
+
if (leftTokens.length === 0 || rightTokens.length === 0) {
|
|
10825
|
+
return false;
|
|
10826
|
+
}
|
|
10827
|
+
const rightSet = new Set(rightTokens);
|
|
10828
|
+
const overlap = leftTokens.filter(item => rightSet.has(item)).length;
|
|
10829
|
+
return overlap >= 2;
|
|
10830
|
+
}
|
|
10831
|
+
|
|
10832
|
+
function renderMoquiCapabilityCoverageMarkdown(report = {}) {
|
|
10833
|
+
const summary = report.summary && typeof report.summary === 'object'
|
|
10834
|
+
? report.summary
|
|
10835
|
+
: {};
|
|
10836
|
+
const coverage = Array.isArray(report.coverage) ? report.coverage : [];
|
|
10837
|
+
const compare = report.compare && typeof report.compare === 'object' ? report.compare : null;
|
|
10838
|
+
const lines = [
|
|
10839
|
+
'# Moqui Capability Coverage Report',
|
|
10840
|
+
'',
|
|
10841
|
+
`- Generated at: ${report.generated_at || 'n/a'}`,
|
|
10842
|
+
`- Expected capabilities: ${summary.total_capabilities !== undefined ? summary.total_capabilities : 'n/a'}`,
|
|
10843
|
+
`- Covered capabilities: ${summary.covered_capabilities !== undefined ? summary.covered_capabilities : 'n/a'}`,
|
|
10844
|
+
`- Uncovered capabilities: ${summary.uncovered_capabilities !== undefined ? summary.uncovered_capabilities : 'n/a'}`,
|
|
10845
|
+
`- Coverage: ${summary.coverage_percent !== undefined && summary.coverage_percent !== null ? `${summary.coverage_percent}%` : 'n/a'}`,
|
|
10846
|
+
`- Min required: ${summary.min_required_percent !== undefined && summary.min_required_percent !== null ? `${summary.min_required_percent}%` : 'n/a'}`,
|
|
10847
|
+
`- Passed: ${summary.passed === true ? 'yes' : 'no'}`,
|
|
10848
|
+
'',
|
|
10849
|
+
'## Capability Matrix',
|
|
10850
|
+
'',
|
|
10851
|
+
'| Capability | Covered | Matched Templates |',
|
|
10852
|
+
'| --- | --- | --- |'
|
|
10853
|
+
];
|
|
10854
|
+
|
|
10855
|
+
for (const item of coverage) {
|
|
10856
|
+
const matchedTemplates = Array.isArray(item.matched_templates) && item.matched_templates.length > 0
|
|
10857
|
+
? item.matched_templates.join(', ')
|
|
10858
|
+
: 'none';
|
|
10859
|
+
lines.push(`| ${item.capability} | ${item.covered ? 'yes' : 'no'} | ${matchedTemplates} |`);
|
|
10860
|
+
}
|
|
10861
|
+
|
|
10862
|
+
if (compare) {
|
|
10863
|
+
lines.push('');
|
|
10864
|
+
lines.push('## Trend vs Previous');
|
|
10865
|
+
lines.push('');
|
|
10866
|
+
lines.push(`- Previous generated at: ${compare.previous_generated_at || 'n/a'}`);
|
|
10867
|
+
lines.push(`- Delta coverage: ${compare.delta_coverage_percent !== null && compare.delta_coverage_percent !== undefined ? `${compare.delta_coverage_percent}%` : 'n/a'}`);
|
|
10868
|
+
lines.push(`- Delta covered capabilities: ${compare.delta_covered_capabilities !== null && compare.delta_covered_capabilities !== undefined ? compare.delta_covered_capabilities : 'n/a'}`);
|
|
10869
|
+
lines.push(`- Newly covered: ${Array.isArray(compare.newly_covered) && compare.newly_covered.length > 0 ? compare.newly_covered.join(', ') : 'none'}`);
|
|
10870
|
+
lines.push(`- Newly uncovered: ${Array.isArray(compare.newly_uncovered) && compare.newly_uncovered.length > 0 ? compare.newly_uncovered.join(', ') : 'none'}`);
|
|
10871
|
+
}
|
|
10872
|
+
|
|
10873
|
+
return `${lines.join('\n')}\n`;
|
|
10874
|
+
}
|
|
10875
|
+
|
|
10876
|
+
function buildCapabilityCoverageComparison(currentPayload, previousPayload) {
|
|
10877
|
+
const currentSummary = currentPayload && currentPayload.summary ? currentPayload.summary : {};
|
|
10878
|
+
const previousSummary = previousPayload && previousPayload.summary ? previousPayload.summary : {};
|
|
10879
|
+
const currentCoverage = Array.isArray(currentPayload && currentPayload.coverage) ? currentPayload.coverage : [];
|
|
10880
|
+
const previousCoverage = Array.isArray(previousPayload && previousPayload.coverage) ? previousPayload.coverage : [];
|
|
10881
|
+
const currentCovered = new Set(
|
|
10882
|
+
currentCoverage.filter(item => item && item.covered === true).map(item => item.capability)
|
|
10883
|
+
);
|
|
10884
|
+
const previousCovered = new Set(
|
|
10885
|
+
previousCoverage.filter(item => item && item.covered === true).map(item => item.capability)
|
|
10886
|
+
);
|
|
10887
|
+
const newlyCovered = Array.from(currentCovered).filter(item => !previousCovered.has(item)).sort();
|
|
10888
|
+
const newlyUncovered = Array.from(previousCovered).filter(item => !currentCovered.has(item)).sort();
|
|
10889
|
+
const toDelta = (current, previous) => {
|
|
10890
|
+
if (!Number.isFinite(Number(current)) || !Number.isFinite(Number(previous))) {
|
|
10891
|
+
return null;
|
|
10892
|
+
}
|
|
10893
|
+
return Number((Number(current) - Number(previous)).toFixed(2));
|
|
10894
|
+
};
|
|
10895
|
+
return {
|
|
10896
|
+
previous_generated_at: previousPayload && previousPayload.generated_at ? previousPayload.generated_at : null,
|
|
10897
|
+
delta_coverage_percent: toDelta(currentSummary.coverage_percent, previousSummary.coverage_percent),
|
|
10898
|
+
delta_covered_capabilities: toDelta(currentSummary.covered_capabilities, previousSummary.covered_capabilities),
|
|
10899
|
+
newly_covered: newlyCovered,
|
|
10900
|
+
newly_uncovered: newlyUncovered
|
|
10901
|
+
};
|
|
10902
|
+
}
|
|
10903
|
+
|
|
10904
|
+
async function loadLatestMoquiCapabilityCoverageReport(projectPath) {
|
|
10905
|
+
const reportPath = path.join(projectPath, AUTO_HANDOFF_MOQUI_CAPABILITY_COVERAGE_JSON_FILE);
|
|
10906
|
+
if (!(await fs.pathExists(reportPath))) {
|
|
10907
|
+
return null;
|
|
10908
|
+
}
|
|
10909
|
+
try {
|
|
10910
|
+
const payload = await fs.readJson(reportPath);
|
|
10911
|
+
return payload && typeof payload === 'object' ? payload : null;
|
|
10912
|
+
} catch (_error) {
|
|
10913
|
+
return null;
|
|
10914
|
+
}
|
|
10915
|
+
}
|
|
10916
|
+
|
|
10917
|
+
async function buildAutoHandoffCapabilityCoverageSnapshot(projectPath, handoff = null, policy = {}) {
|
|
10918
|
+
const expectedRaw = Array.isArray(handoff && handoff.capabilities)
|
|
10919
|
+
? handoff.capabilities
|
|
10920
|
+
: [];
|
|
10921
|
+
const expected = Array.from(
|
|
10922
|
+
new Set(
|
|
10923
|
+
expectedRaw
|
|
10924
|
+
.map(item => normalizeMoquiCapabilityToken(item))
|
|
10925
|
+
.filter(Boolean)
|
|
10926
|
+
)
|
|
10927
|
+
);
|
|
10928
|
+
if (expected.length === 0) {
|
|
10929
|
+
return {
|
|
10930
|
+
status: 'skipped',
|
|
10931
|
+
generated: false,
|
|
10932
|
+
reason: 'manifest capabilities not declared',
|
|
10933
|
+
summary: {
|
|
10934
|
+
total_capabilities: 0,
|
|
10935
|
+
covered_capabilities: 0,
|
|
10936
|
+
uncovered_capabilities: 0,
|
|
10937
|
+
coverage_percent: null,
|
|
10938
|
+
min_required_percent: Number(policy.min_capability_coverage_percent),
|
|
10939
|
+
passed: true
|
|
10940
|
+
},
|
|
10941
|
+
coverage: [],
|
|
10942
|
+
gaps: []
|
|
10943
|
+
};
|
|
10944
|
+
}
|
|
10945
|
+
|
|
10946
|
+
const templateRoot = path.join(projectPath, '.kiro', 'templates', 'scene-packages');
|
|
10947
|
+
if (!(await fs.pathExists(templateRoot))) {
|
|
10948
|
+
return {
|
|
10949
|
+
status: 'skipped',
|
|
10950
|
+
generated: false,
|
|
10951
|
+
reason: `template library not found: ${toAutoHandoffCliPath(projectPath, templateRoot)}`,
|
|
10952
|
+
summary: {
|
|
10953
|
+
total_capabilities: expected.length,
|
|
10954
|
+
covered_capabilities: 0,
|
|
10955
|
+
uncovered_capabilities: expected.length,
|
|
10956
|
+
coverage_percent: 0,
|
|
10957
|
+
min_required_percent: Number(policy.min_capability_coverage_percent),
|
|
10958
|
+
passed: false
|
|
10959
|
+
},
|
|
10960
|
+
coverage: expected.map(item => ({ capability: item, covered: false, matched_templates: [], matched_provides: [] })),
|
|
10961
|
+
gaps: expected
|
|
10962
|
+
};
|
|
10963
|
+
}
|
|
10964
|
+
|
|
10965
|
+
const templateEntries = await fs.readdir(templateRoot);
|
|
10966
|
+
const templates = [];
|
|
10967
|
+
for (const entry of templateEntries) {
|
|
10968
|
+
const templateDir = path.join(templateRoot, entry);
|
|
10969
|
+
let stat = null;
|
|
10970
|
+
try {
|
|
10971
|
+
stat = await fs.stat(templateDir);
|
|
10972
|
+
} catch (_error) {
|
|
10973
|
+
stat = null;
|
|
10974
|
+
}
|
|
10975
|
+
if (!stat || !stat.isDirectory()) {
|
|
10976
|
+
continue;
|
|
10977
|
+
}
|
|
10978
|
+
const contractFile = path.join(templateDir, 'scene-package.json');
|
|
10979
|
+
if (!(await fs.pathExists(contractFile))) {
|
|
10980
|
+
continue;
|
|
10981
|
+
}
|
|
10982
|
+
try {
|
|
10983
|
+
const payload = await fs.readJson(contractFile);
|
|
10984
|
+
const providesRaw = [];
|
|
10985
|
+
const contractProvides = payload && payload.contract && payload.contract.capabilities && payload.contract.capabilities.provides;
|
|
10986
|
+
const rootProvides = payload && payload.capabilities && payload.capabilities.provides;
|
|
10987
|
+
if (Array.isArray(contractProvides)) {
|
|
10988
|
+
providesRaw.push(...contractProvides);
|
|
10989
|
+
}
|
|
10990
|
+
if (Array.isArray(rootProvides)) {
|
|
10991
|
+
providesRaw.push(...rootProvides);
|
|
10992
|
+
}
|
|
10993
|
+
const provides = Array.from(
|
|
10994
|
+
new Set(
|
|
10995
|
+
providesRaw
|
|
10996
|
+
.map(item => normalizeMoquiCapabilityToken(item))
|
|
10997
|
+
.filter(Boolean)
|
|
10998
|
+
)
|
|
10999
|
+
);
|
|
11000
|
+
templates.push({
|
|
11001
|
+
template_id: entry,
|
|
11002
|
+
provides
|
|
11003
|
+
});
|
|
11004
|
+
} catch (_error) {
|
|
11005
|
+
// Ignore malformed template package entries.
|
|
11006
|
+
}
|
|
11007
|
+
}
|
|
11008
|
+
|
|
11009
|
+
const coverage = expected.map(capability => {
|
|
11010
|
+
const matchedTemplates = [];
|
|
11011
|
+
const matchedProvides = [];
|
|
11012
|
+
for (const template of templates) {
|
|
11013
|
+
const providedMatched = template.provides.filter(item => moquiCapabilityMatch(capability, item));
|
|
11014
|
+
if (providedMatched.length > 0) {
|
|
11015
|
+
matchedTemplates.push(template.template_id);
|
|
11016
|
+
matchedProvides.push(...providedMatched);
|
|
11017
|
+
}
|
|
11018
|
+
}
|
|
11019
|
+
const uniqueProvides = Array.from(new Set(matchedProvides)).sort();
|
|
11020
|
+
return {
|
|
11021
|
+
capability,
|
|
11022
|
+
covered: matchedTemplates.length > 0,
|
|
11023
|
+
matched_templates: Array.from(new Set(matchedTemplates)).sort(),
|
|
11024
|
+
matched_provides: uniqueProvides
|
|
11025
|
+
};
|
|
11026
|
+
});
|
|
11027
|
+
|
|
11028
|
+
const coveredCount = coverage.filter(item => item.covered).length;
|
|
11029
|
+
const uncovered = coverage.filter(item => !item.covered).map(item => item.capability);
|
|
11030
|
+
const coveragePercent = expected.length > 0
|
|
11031
|
+
? Number(((coveredCount / expected.length) * 100).toFixed(2))
|
|
11032
|
+
: null;
|
|
11033
|
+
const minRequiredPercent = Number(policy.min_capability_coverage_percent);
|
|
11034
|
+
const passed = Number.isFinite(coveragePercent) && Number.isFinite(minRequiredPercent)
|
|
11035
|
+
? coveragePercent >= minRequiredPercent
|
|
11036
|
+
: false;
|
|
11037
|
+
|
|
11038
|
+
const payload = {
|
|
11039
|
+
mode: 'moqui-capability-coverage',
|
|
11040
|
+
generated_at: new Date().toISOString(),
|
|
11041
|
+
expected_capabilities: expected,
|
|
11042
|
+
summary: {
|
|
11043
|
+
total_capabilities: expected.length,
|
|
11044
|
+
covered_capabilities: coveredCount,
|
|
11045
|
+
uncovered_capabilities: expected.length - coveredCount,
|
|
11046
|
+
coverage_percent: coveragePercent,
|
|
11047
|
+
min_required_percent: Number.isFinite(minRequiredPercent) ? minRequiredPercent : 100,
|
|
11048
|
+
passed
|
|
11049
|
+
},
|
|
11050
|
+
coverage,
|
|
11051
|
+
gaps: uncovered
|
|
11052
|
+
};
|
|
11053
|
+
|
|
11054
|
+
const previousPayload = await loadLatestMoquiCapabilityCoverageReport(projectPath);
|
|
11055
|
+
if (previousPayload) {
|
|
11056
|
+
payload.compare = buildCapabilityCoverageComparison(payload, previousPayload);
|
|
11057
|
+
}
|
|
11058
|
+
|
|
11059
|
+
const outputJsonPath = path.join(projectPath, AUTO_HANDOFF_MOQUI_CAPABILITY_COVERAGE_JSON_FILE);
|
|
11060
|
+
const outputMarkdownPath = path.join(projectPath, AUTO_HANDOFF_MOQUI_CAPABILITY_COVERAGE_MARKDOWN_FILE);
|
|
11061
|
+
await fs.ensureDir(path.dirname(outputJsonPath));
|
|
11062
|
+
await fs.writeJson(outputJsonPath, payload, { spaces: 2 });
|
|
11063
|
+
await fs.writeFile(outputMarkdownPath, renderMoquiCapabilityCoverageMarkdown(payload), 'utf8');
|
|
11064
|
+
|
|
11065
|
+
return {
|
|
11066
|
+
status: 'evaluated',
|
|
11067
|
+
generated: true,
|
|
11068
|
+
summary: payload.summary,
|
|
11069
|
+
coverage: payload.coverage,
|
|
11070
|
+
gaps: payload.gaps,
|
|
11071
|
+
compare: payload.compare || null,
|
|
11072
|
+
output: {
|
|
11073
|
+
json: toAutoHandoffCliPath(projectPath, outputJsonPath),
|
|
11074
|
+
markdown: toAutoHandoffCliPath(projectPath, outputMarkdownPath)
|
|
11075
|
+
}
|
|
11076
|
+
};
|
|
11077
|
+
}
|
|
11078
|
+
|
|
11079
|
+
function collectAutoHandoffMoquiRemediationGoals(result) {
|
|
11080
|
+
const goals = [];
|
|
11081
|
+
const seen = new Set();
|
|
11082
|
+
const pushGoal = value => {
|
|
11083
|
+
const text = `${value || ''}`.trim();
|
|
11084
|
+
if (!text || seen.has(text)) {
|
|
11085
|
+
return;
|
|
11086
|
+
}
|
|
11087
|
+
seen.add(text);
|
|
11088
|
+
goals.push(text);
|
|
11089
|
+
};
|
|
11090
|
+
|
|
11091
|
+
const moquiBaseline = result && result.moqui_baseline && typeof result.moqui_baseline === 'object'
|
|
11092
|
+
? result.moqui_baseline
|
|
11093
|
+
: null;
|
|
11094
|
+
const baselineSummary = moquiBaseline && moquiBaseline.summary && typeof moquiBaseline.summary === 'object'
|
|
11095
|
+
? moquiBaseline.summary
|
|
11096
|
+
: null;
|
|
11097
|
+
const baselineCompare = moquiBaseline && moquiBaseline.compare && typeof moquiBaseline.compare === 'object'
|
|
11098
|
+
? moquiBaseline.compare
|
|
11099
|
+
: null;
|
|
11100
|
+
const baselineFailedTemplates = baselineCompare && baselineCompare.failed_templates && typeof baselineCompare.failed_templates === 'object'
|
|
11101
|
+
? baselineCompare.failed_templates
|
|
11102
|
+
: {};
|
|
11103
|
+
|
|
11104
|
+
if (moquiBaseline && moquiBaseline.status === 'error') {
|
|
11105
|
+
pushGoal('repair moqui baseline generation pipeline and regenerate baseline evidence');
|
|
11106
|
+
} else if (baselineSummary && baselineSummary.portfolio_passed === false) {
|
|
11107
|
+
pushGoal(
|
|
11108
|
+
`raise moqui baseline portfolio score (avg=${baselineSummary.avg_score || 'n/a'}, ` +
|
|
11109
|
+
`valid-rate=${baselineSummary.valid_rate_percent || 'n/a'}%) to pass thresholds`
|
|
11110
|
+
);
|
|
11111
|
+
const targetTemplates = Array.isArray(baselineFailedTemplates.current)
|
|
11112
|
+
? baselineFailedTemplates.current
|
|
11113
|
+
: [];
|
|
11114
|
+
for (const templateId of targetTemplates) {
|
|
11115
|
+
pushGoal(`remediate moqui template ${templateId} ontology semantics and close baseline gaps`);
|
|
11116
|
+
}
|
|
11117
|
+
}
|
|
11118
|
+
|
|
11119
|
+
const capabilityCoverage = result && result.moqui_capability_coverage && typeof result.moqui_capability_coverage === 'object'
|
|
11120
|
+
? result.moqui_capability_coverage
|
|
11121
|
+
: null;
|
|
11122
|
+
const capabilitySummary = capabilityCoverage && capabilityCoverage.summary && typeof capabilityCoverage.summary === 'object'
|
|
11123
|
+
? capabilityCoverage.summary
|
|
11124
|
+
: null;
|
|
11125
|
+
const capabilityGaps = capabilityCoverage && Array.isArray(capabilityCoverage.gaps)
|
|
11126
|
+
? capabilityCoverage.gaps
|
|
11127
|
+
: [];
|
|
11128
|
+
if (
|
|
11129
|
+
capabilityCoverage &&
|
|
11130
|
+
capabilityCoverage.status === 'evaluated' &&
|
|
11131
|
+
capabilitySummary &&
|
|
11132
|
+
capabilitySummary.passed === false
|
|
11133
|
+
) {
|
|
11134
|
+
pushGoal(
|
|
11135
|
+
`increase moqui capability coverage to >=${capabilitySummary.min_required_percent}% ` +
|
|
11136
|
+
`(current=${capabilitySummary.coverage_percent || 0}%)`
|
|
11137
|
+
);
|
|
11138
|
+
for (const capability of capabilityGaps) {
|
|
11139
|
+
pushGoal(`implement scene template or ontology mapping for moqui capability ${capability}`);
|
|
11140
|
+
}
|
|
11141
|
+
}
|
|
11142
|
+
|
|
11143
|
+
return goals;
|
|
11144
|
+
}
|
|
11145
|
+
|
|
11146
|
+
async function maybeWriteAutoHandoffMoquiRemediationQueue(projectPath, result) {
|
|
11147
|
+
const goals = collectAutoHandoffMoquiRemediationGoals(result);
|
|
11148
|
+
if (goals.length === 0) {
|
|
11149
|
+
return null;
|
|
11150
|
+
}
|
|
11151
|
+
const queuePath = path.join(projectPath, AUTO_HANDOFF_MOQUI_REMEDIATION_QUEUE_FILE);
|
|
11152
|
+
await fs.ensureDir(path.dirname(queuePath));
|
|
11153
|
+
await fs.writeFile(queuePath, `${goals.join('\n')}\n`, 'utf8');
|
|
11154
|
+
return {
|
|
11155
|
+
file: queuePath,
|
|
11156
|
+
goal_count: goals.length,
|
|
11157
|
+
goals
|
|
11158
|
+
};
|
|
11159
|
+
}
|
|
11160
|
+
|
|
10494
11161
|
async function runAutoHandoff(projectPath, options = {}) {
|
|
10495
11162
|
const startedAtMs = Date.now();
|
|
10496
11163
|
const result = {
|
|
@@ -10513,6 +11180,8 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10513
11180
|
spec_status: null,
|
|
10514
11181
|
ontology_validation: null,
|
|
10515
11182
|
moqui_baseline: null,
|
|
11183
|
+
moqui_capability_coverage: null,
|
|
11184
|
+
remediation_queue: null,
|
|
10516
11185
|
gates: null,
|
|
10517
11186
|
regression: null,
|
|
10518
11187
|
release_evidence: null,
|
|
@@ -10554,6 +11223,85 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10554
11223
|
throw error;
|
|
10555
11224
|
}
|
|
10556
11225
|
|
|
11226
|
+
const baselinePhase = beginAutoHandoffRunPhase(result, 'moqui-baseline', 'Moqui template baseline scorecard');
|
|
11227
|
+
try {
|
|
11228
|
+
result.moqui_baseline = await buildAutoHandoffMoquiBaselineSnapshot(projectPath);
|
|
11229
|
+
completeAutoHandoffRunPhase(
|
|
11230
|
+
baselinePhase,
|
|
11231
|
+
buildAutoHandoffMoquiBaselinePhaseDetails(result.moqui_baseline)
|
|
11232
|
+
);
|
|
11233
|
+
if (result.moqui_baseline && result.moqui_baseline.status === 'error') {
|
|
11234
|
+
result.warnings.push(`moqui baseline generation failed: ${result.moqui_baseline.error || 'unknown error'}`);
|
|
11235
|
+
}
|
|
11236
|
+
const moquiBaselineGateReasons = evaluateAutoHandoffMoquiBaselineGateReasons(
|
|
11237
|
+
result.policy,
|
|
11238
|
+
result.moqui_baseline
|
|
11239
|
+
);
|
|
11240
|
+
if (moquiBaselineGateReasons.length > 0) {
|
|
11241
|
+
throw new Error(`handoff moqui baseline gate failed: ${moquiBaselineGateReasons.join('; ')}`);
|
|
11242
|
+
}
|
|
11243
|
+
} catch (baselineError) {
|
|
11244
|
+
failAutoHandoffRunPhase(baselinePhase, baselineError);
|
|
11245
|
+
if (!result.moqui_baseline) {
|
|
11246
|
+
result.moqui_baseline = {
|
|
11247
|
+
status: 'error',
|
|
11248
|
+
generated: false,
|
|
11249
|
+
error: baselineError && baselineError.message ? baselineError.message : `${baselineError}`
|
|
11250
|
+
};
|
|
11251
|
+
}
|
|
11252
|
+
throw baselineError;
|
|
11253
|
+
}
|
|
11254
|
+
|
|
11255
|
+
const capabilityCoveragePhase = beginAutoHandoffRunPhase(
|
|
11256
|
+
result,
|
|
11257
|
+
'moqui-capability-coverage',
|
|
11258
|
+
'Moqui capability coverage matrix'
|
|
11259
|
+
);
|
|
11260
|
+
try {
|
|
11261
|
+
result.moqui_capability_coverage = await buildAutoHandoffCapabilityCoverageSnapshot(
|
|
11262
|
+
projectPath,
|
|
11263
|
+
result.handoff,
|
|
11264
|
+
result.policy
|
|
11265
|
+
);
|
|
11266
|
+
completeAutoHandoffRunPhase(capabilityCoveragePhase, {
|
|
11267
|
+
status: result.moqui_capability_coverage.status || 'unknown',
|
|
11268
|
+
coverage_percent: Number.isFinite(
|
|
11269
|
+
Number(
|
|
11270
|
+
result.moqui_capability_coverage &&
|
|
11271
|
+
result.moqui_capability_coverage.summary
|
|
11272
|
+
? result.moqui_capability_coverage.summary.coverage_percent
|
|
11273
|
+
: null
|
|
11274
|
+
)
|
|
11275
|
+
)
|
|
11276
|
+
? Number(result.moqui_capability_coverage.summary.coverage_percent)
|
|
11277
|
+
: null,
|
|
11278
|
+
passed: Boolean(
|
|
11279
|
+
result.moqui_capability_coverage &&
|
|
11280
|
+
result.moqui_capability_coverage.summary &&
|
|
11281
|
+
result.moqui_capability_coverage.summary.passed === true
|
|
11282
|
+
)
|
|
11283
|
+
});
|
|
11284
|
+
const capabilityCoverageGateReasons = evaluateAutoHandoffCapabilityCoverageGateReasons(
|
|
11285
|
+
result.policy,
|
|
11286
|
+
result.moqui_capability_coverage
|
|
11287
|
+
);
|
|
11288
|
+
if (capabilityCoverageGateReasons.length > 0) {
|
|
11289
|
+
throw new Error(`handoff capability coverage gate failed: ${capabilityCoverageGateReasons.join('; ')}`);
|
|
11290
|
+
}
|
|
11291
|
+
} catch (capabilityCoverageError) {
|
|
11292
|
+
failAutoHandoffRunPhase(capabilityCoveragePhase, capabilityCoverageError);
|
|
11293
|
+
if (!result.moqui_capability_coverage) {
|
|
11294
|
+
result.moqui_capability_coverage = {
|
|
11295
|
+
status: 'error',
|
|
11296
|
+
generated: false,
|
|
11297
|
+
error: capabilityCoverageError && capabilityCoverageError.message
|
|
11298
|
+
? capabilityCoverageError.message
|
|
11299
|
+
: `${capabilityCoverageError}`
|
|
11300
|
+
};
|
|
11301
|
+
}
|
|
11302
|
+
throw capabilityCoverageError;
|
|
11303
|
+
}
|
|
11304
|
+
|
|
10557
11305
|
const queuePhase = beginAutoHandoffRunPhase(result, 'queue', 'Queue generation');
|
|
10558
11306
|
let queue = null;
|
|
10559
11307
|
try {
|
|
@@ -10614,30 +11362,13 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10614
11362
|
null,
|
|
10615
11363
|
continuationBaselineSummary
|
|
10616
11364
|
);
|
|
10617
|
-
const baselinePhase = beginAutoHandoffRunPhase(result, 'moqui-baseline', 'Moqui template baseline scorecard');
|
|
10618
|
-
try {
|
|
10619
|
-
result.moqui_baseline = await buildAutoHandoffMoquiBaselineSnapshot(projectPath);
|
|
10620
|
-
completeAutoHandoffRunPhase(
|
|
10621
|
-
baselinePhase,
|
|
10622
|
-
buildAutoHandoffMoquiBaselinePhaseDetails(result.moqui_baseline)
|
|
10623
|
-
);
|
|
10624
|
-
if (result.moqui_baseline && result.moqui_baseline.status === 'error') {
|
|
10625
|
-
result.warnings.push(`moqui baseline generation failed: ${result.moqui_baseline.error || 'unknown error'}`);
|
|
10626
|
-
}
|
|
10627
|
-
} catch (baselineError) {
|
|
10628
|
-
failAutoHandoffRunPhase(baselinePhase, baselineError);
|
|
10629
|
-
result.moqui_baseline = {
|
|
10630
|
-
status: 'error',
|
|
10631
|
-
generated: false,
|
|
10632
|
-
error: baselineError && baselineError.message ? baselineError.message : `${baselineError}`
|
|
10633
|
-
};
|
|
10634
|
-
result.warnings.push(`moqui baseline generation failed: ${result.moqui_baseline.error}`);
|
|
10635
|
-
}
|
|
10636
11365
|
result.gates = evaluateAutoHandoffRunGates({
|
|
10637
11366
|
policy: result.policy,
|
|
10638
11367
|
dryRun: true,
|
|
10639
11368
|
specStatus: result.spec_status,
|
|
10640
11369
|
ontology: result.ontology_validation,
|
|
11370
|
+
moquiBaseline: result.moqui_baseline,
|
|
11371
|
+
capabilityCoverage: result.moqui_capability_coverage,
|
|
10641
11372
|
programKpi: {
|
|
10642
11373
|
risk_level: 'low'
|
|
10643
11374
|
}
|
|
@@ -10693,31 +11424,13 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10693
11424
|
throw error;
|
|
10694
11425
|
}
|
|
10695
11426
|
|
|
10696
|
-
const baselinePhase = beginAutoHandoffRunPhase(result, 'moqui-baseline', 'Moqui template baseline scorecard');
|
|
10697
|
-
try {
|
|
10698
|
-
result.moqui_baseline = await buildAutoHandoffMoquiBaselineSnapshot(projectPath);
|
|
10699
|
-
completeAutoHandoffRunPhase(
|
|
10700
|
-
baselinePhase,
|
|
10701
|
-
buildAutoHandoffMoquiBaselinePhaseDetails(result.moqui_baseline)
|
|
10702
|
-
);
|
|
10703
|
-
if (result.moqui_baseline && result.moqui_baseline.status === 'error') {
|
|
10704
|
-
result.warnings.push(`moqui baseline generation failed: ${result.moqui_baseline.error || 'unknown error'}`);
|
|
10705
|
-
}
|
|
10706
|
-
} catch (baselineError) {
|
|
10707
|
-
failAutoHandoffRunPhase(baselinePhase, baselineError);
|
|
10708
|
-
result.moqui_baseline = {
|
|
10709
|
-
status: 'error',
|
|
10710
|
-
generated: false,
|
|
10711
|
-
error: baselineError && baselineError.message ? baselineError.message : `${baselineError}`
|
|
10712
|
-
};
|
|
10713
|
-
result.warnings.push(`moqui baseline generation failed: ${result.moqui_baseline.error}`);
|
|
10714
|
-
}
|
|
10715
|
-
|
|
10716
11427
|
result.gates = evaluateAutoHandoffRunGates({
|
|
10717
11428
|
policy: result.policy,
|
|
10718
11429
|
dryRun: false,
|
|
10719
11430
|
specStatus: result.spec_status,
|
|
10720
11431
|
ontology: result.ontology_validation,
|
|
11432
|
+
moquiBaseline: result.moqui_baseline,
|
|
11433
|
+
capabilityCoverage: result.moqui_capability_coverage,
|
|
10721
11434
|
programKpi: buildProgramKpiSnapshot(result.batch_summary || {})
|
|
10722
11435
|
});
|
|
10723
11436
|
if (!result.gates.passed) {
|
|
@@ -10731,6 +11444,7 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10731
11444
|
result.completed_at = new Date().toISOString();
|
|
10732
11445
|
result.elapsed_ms = Math.max(0, Date.now() - startedAtMs);
|
|
10733
11446
|
result.regression = await buildAutoHandoffRegression(projectPath, result);
|
|
11447
|
+
result.remediation_queue = await maybeWriteAutoHandoffMoquiRemediationQueue(projectPath, result);
|
|
10734
11448
|
result.recommendations = buildAutoHandoffRunRecommendations(projectPath, result);
|
|
10735
11449
|
await writeAutoHandoffRunReport(projectPath, result, options.out);
|
|
10736
11450
|
if (result.dry_run) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kiro-spec-engine",
|
|
3
|
-
"version": "1.47.
|
|
3
|
+
"version": "1.47.33",
|
|
4
4
|
"description": "kiro-spec-engine (kse) - A CLI tool and npm package for spec-driven development with AI coding assistants. NOT the Kiro IDE desktop application.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|