kiro-spec-engine 1.47.31 → 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,15 +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 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
|
+
- 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`.
|
|
774
777
|
- Run result includes `recommendations` with executable follow-up commands (for example, auto-generated `--continue-from <session>` on failed/incomplete batches).
|
|
775
|
-
- Gate defaults: `--min-spec-success-rate` defaults to `100`, `--max-risk-level` defaults to `high`,
|
|
776
|
-
- 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.
|
|
777
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).
|
|
778
781
|
- `--window` (2-50, default `2`) returns multi-run `series`, `window_trend`, and `aggregates` for broader regression visibility.
|
|
779
782
|
- Regression JSON now includes `risk_layers` (low/medium/high/unknown buckets with per-layer session list and quality aggregates).
|
|
@@ -781,11 +784,11 @@ Dual-track handoff integration:
|
|
|
781
784
|
- Markdown report includes `Trend Series` (ASCII success/ontology bars per session) and `Risk Layer View`.
|
|
782
785
|
- `--out` writes the generated regression report using the selected format.
|
|
783
786
|
- Output includes `recommendations` to guide next action when trend degrades or risk escalates.
|
|
784
|
-
- `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/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.
|
|
785
788
|
- Default evidence file is `.kiro/reports/release-evidence/handoff-runs.json`.
|
|
786
789
|
- `--window` (1-50, default `5`) controls how many recent sessions are aggregated in review.
|
|
787
790
|
- JSON output includes `current_overview`, `aggregates.status_counts`, `aggregates.gate_pass_rate_percent`, and `risk_layers`.
|
|
788
|
-
- Markdown output includes `Current Gate`, `Current Ontology`, `Current Regression`, `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`.
|
|
789
792
|
- Add `--release-draft <path>` to auto-generate a release notes draft and evidence review markdown in one run.
|
|
790
793
|
- `--release-version` sets draft version tag (defaults to `v<package.json version>`), and `--release-date` accepts `YYYY-MM-DD` (default: current UTC date).
|
|
791
794
|
- Use `--review-out <path>` to override the generated evidence review markdown path (default `.kiro/reports/release-evidence/handoff-evidence-review.md`).
|
|
@@ -13,6 +13,9 @@ This playbook defines a generic (project-agnostic) path to absorb Moqui capabili
|
|
|
13
13
|
KSE defaults already enforce the baseline below:
|
|
14
14
|
|
|
15
15
|
- `kse auto handoff run`: ontology validation is required by default.
|
|
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%`).
|
|
16
19
|
- `kse scene package-publish-batch`:
|
|
17
20
|
- ontology validation required by default
|
|
18
21
|
- batch ontology gate defaults:
|
|
@@ -22,6 +25,8 @@ KSE defaults already enforce the baseline below:
|
|
|
22
25
|
Emergency bypass exists but is not recommended:
|
|
23
26
|
|
|
24
27
|
- `--no-require-ontology-validation`
|
|
28
|
+
- `--no-require-moqui-baseline`
|
|
29
|
+
- `--no-require-capability-coverage`
|
|
25
30
|
|
|
26
31
|
## One-Shot Intake Flow
|
|
27
32
|
|
|
@@ -62,8 +67,13 @@ Required artifacts for each intake batch:
|
|
|
62
67
|
|
|
63
68
|
- `.kiro/reports/moqui-template-baseline.json`
|
|
64
69
|
- `.kiro/reports/moqui-template-baseline.md`
|
|
70
|
+
- `.kiro/reports/release-evidence/moqui-template-baseline.json`
|
|
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`
|
|
65
74
|
- `.kiro/reports/handoff-runs/<session>.json`
|
|
66
75
|
- `.kiro/reports/scene-package-ontology-batch.json`
|
|
76
|
+
- `.kiro/auto/moqui-remediation.lines` (when baseline/coverage gaps exist)
|
|
67
77
|
- `.kiro/templates/scene-packages/registry.json`
|
|
68
78
|
- gate output/evidence linked from release notes or handoff summary
|
|
69
79
|
|
package/lib/commands/auto.js
CHANGED
|
@@ -9,6 +9,7 @@ const { analyzeGoalSemantics } = require('../auto/semantic-decomposer');
|
|
|
9
9
|
const fs = require('fs-extra');
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const chalk = require('chalk');
|
|
12
|
+
const { spawnSync } = require('child_process');
|
|
12
13
|
|
|
13
14
|
const AUTO_ARCHIVE_SCHEMA_VERSION = '1.0';
|
|
14
15
|
const AUTO_ARCHIVE_SCHEMA_SUPPORTED_VERSIONS = new Set([AUTO_ARCHIVE_SCHEMA_VERSION]);
|
|
@@ -18,6 +19,11 @@ const AUTO_HANDOFF_RELEASE_EVIDENCE_FILE = '.kiro/reports/release-evidence/hando
|
|
|
18
19
|
const AUTO_HANDOFF_EVIDENCE_REVIEW_DEFAULT_FILE = '.kiro/reports/release-evidence/handoff-evidence-review.md';
|
|
19
20
|
const AUTO_HANDOFF_RELEASE_EVIDENCE_DIR = '.kiro/reports/release-evidence';
|
|
20
21
|
const AUTO_HANDOFF_RELEASE_GATE_HISTORY_FILE = '.kiro/reports/release-evidence/release-gate-history.json';
|
|
22
|
+
const AUTO_HANDOFF_MOQUI_BASELINE_JSON_FILE = '.kiro/reports/release-evidence/moqui-template-baseline.json';
|
|
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';
|
|
21
27
|
|
|
22
28
|
/**
|
|
23
29
|
* Register auto commands
|
|
@@ -1647,6 +1653,36 @@ function registerAutoCommands(program) {
|
|
|
1647
1653
|
if (result.current_overview && result.current_overview.gate) {
|
|
1648
1654
|
console.log(chalk.gray(` Gate passed: ${result.current_overview.gate.passed ? 'yes' : 'no'}`));
|
|
1649
1655
|
}
|
|
1656
|
+
if (result.current_overview && result.current_overview.moqui_baseline) {
|
|
1657
|
+
const moquiBaseline = result.current_overview.moqui_baseline;
|
|
1658
|
+
const moquiSummary = moquiBaseline && moquiBaseline.summary ? moquiBaseline.summary : null;
|
|
1659
|
+
console.log(chalk.gray(` Moqui baseline: ${moquiBaseline.status || 'n/a'}`));
|
|
1660
|
+
if (moquiSummary) {
|
|
1661
|
+
const scoreText = Number.isFinite(Number(moquiSummary.avg_score))
|
|
1662
|
+
? `${moquiSummary.avg_score}`
|
|
1663
|
+
: 'n/a';
|
|
1664
|
+
const validRateText = Number.isFinite(Number(moquiSummary.valid_rate_percent))
|
|
1665
|
+
? `${moquiSummary.valid_rate_percent}%`
|
|
1666
|
+
: 'n/a';
|
|
1667
|
+
console.log(chalk.gray(` Portfolio: ${moquiSummary.portfolio_passed === true ? 'pass' : 'fail'} | avg=${scoreText} | valid-rate=${validRateText}`));
|
|
1668
|
+
}
|
|
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
|
+
}
|
|
1650
1686
|
if (result.output_file) {
|
|
1651
1687
|
console.log(chalk.gray(` Output: ${result.output_file}`));
|
|
1652
1688
|
}
|
|
@@ -1748,6 +1784,11 @@ function registerAutoCommands(program) {
|
|
|
1748
1784
|
.option('--max-undecided-decisions <n>', 'Gate: maximum allowed undecided decisions (optional)', parseInt)
|
|
1749
1785
|
.option('--require-ontology-validation', 'Gate: require manifest ontology_validation to be present and passed (default: enabled)')
|
|
1750
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)')
|
|
1751
1792
|
.option('--release-evidence-window <n>', 'Release evidence trend window size (2-50, default: 5)', parseInt)
|
|
1752
1793
|
.option('--json', 'Output machine-readable JSON')
|
|
1753
1794
|
.action(async (options) => {
|
|
@@ -1771,6 +1812,40 @@ function registerAutoCommands(program) {
|
|
|
1771
1812
|
if (result.gates) {
|
|
1772
1813
|
console.log(chalk.gray(` Gate passed: ${result.gates.passed ? 'yes' : 'no'}`));
|
|
1773
1814
|
}
|
|
1815
|
+
if (result.moqui_baseline) {
|
|
1816
|
+
console.log(chalk.gray(` Moqui baseline: ${result.moqui_baseline.status || 'unknown'}`));
|
|
1817
|
+
if (result.moqui_baseline.summary) {
|
|
1818
|
+
const baselineSummary = result.moqui_baseline.summary;
|
|
1819
|
+
const scoreText = Number.isFinite(Number(baselineSummary.avg_score))
|
|
1820
|
+
? `${baselineSummary.avg_score}`
|
|
1821
|
+
: 'n/a';
|
|
1822
|
+
const validRateText = Number.isFinite(Number(baselineSummary.valid_rate_percent))
|
|
1823
|
+
? `${baselineSummary.valid_rate_percent}%`
|
|
1824
|
+
: 'n/a';
|
|
1825
|
+
console.log(chalk.gray(` Portfolio: ${baselineSummary.portfolio_passed ? 'pass' : 'fail'} | avg=${scoreText} | valid-rate=${validRateText}`));
|
|
1826
|
+
}
|
|
1827
|
+
if (result.moqui_baseline.output && result.moqui_baseline.output.json) {
|
|
1828
|
+
console.log(chalk.gray(` Baseline report: ${result.moqui_baseline.output.json}`));
|
|
1829
|
+
}
|
|
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
|
+
}
|
|
1774
1849
|
if (result.output_file) {
|
|
1775
1850
|
console.log(chalk.gray(` Report: ${result.output_file}`));
|
|
1776
1851
|
}
|
|
@@ -6878,6 +6953,16 @@ function normalizeAutoHandoffManifest(payload = {}) {
|
|
|
6878
6953
|
validationWarnings.push('templates is empty');
|
|
6879
6954
|
}
|
|
6880
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
|
+
|
|
6881
6966
|
const knownGapCollected = collectKnownGaps(payload.known_gaps);
|
|
6882
6967
|
validationWarnings.push(...knownGapCollected.warnings);
|
|
6883
6968
|
|
|
@@ -6899,6 +6984,7 @@ function normalizeAutoHandoffManifest(payload = {}) {
|
|
|
6899
6984
|
spec_descriptors: specsCollected.descriptors,
|
|
6900
6985
|
dependency_batches: dependencyBatches,
|
|
6901
6986
|
templates: templatesCollected.values,
|
|
6987
|
+
capabilities: capabilitiesCollected.values,
|
|
6902
6988
|
known_gaps: knownGapCollected.gaps,
|
|
6903
6989
|
ontology_validation: ontologyValidation,
|
|
6904
6990
|
next_batch: nextBatch,
|
|
@@ -7006,11 +7092,13 @@ async function buildAutoHandoffPlan(projectPath, options = {}) {
|
|
|
7006
7092
|
timestamp: handoff.timestamp,
|
|
7007
7093
|
spec_count: handoff.specs.length,
|
|
7008
7094
|
template_count: handoff.templates.length,
|
|
7095
|
+
capability_count: Array.isArray(handoff.capabilities) ? handoff.capabilities.length : 0,
|
|
7009
7096
|
known_gap_count: handoff.known_gaps.length,
|
|
7010
7097
|
specs: handoff.specs,
|
|
7011
7098
|
spec_descriptors: handoff.spec_descriptors,
|
|
7012
7099
|
dependency_batches: handoff.dependency_batches,
|
|
7013
7100
|
templates: handoff.templates,
|
|
7101
|
+
capabilities: handoff.capabilities,
|
|
7014
7102
|
known_gaps: handoff.known_gaps,
|
|
7015
7103
|
ontology_validation: handoff.ontology_validation,
|
|
7016
7104
|
next_batch: handoff.next_batch
|
|
@@ -8890,6 +8978,19 @@ function buildAutoHandoffEvidenceSnapshot(entry = {}) {
|
|
|
8890
8978
|
),
|
|
8891
8979
|
ontology_business_rule_pass_rate_percent: toNumber(ontologyMetrics.business_rule_pass_rate_percent),
|
|
8892
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
|
+
),
|
|
8893
8994
|
generated_at: normalizeHandoffText(entry.merged_at)
|
|
8894
8995
|
};
|
|
8895
8996
|
}
|
|
@@ -8937,6 +9038,33 @@ function renderAutoHandoffEvidenceReviewMarkdown(payload = {}) {
|
|
|
8937
9038
|
const regression = currentOverview.regression && typeof currentOverview.regression === 'object'
|
|
8938
9039
|
? currentOverview.regression
|
|
8939
9040
|
: {};
|
|
9041
|
+
const moquiBaseline = currentOverview.moqui_baseline && typeof currentOverview.moqui_baseline === 'object'
|
|
9042
|
+
? currentOverview.moqui_baseline
|
|
9043
|
+
: {};
|
|
9044
|
+
const moquiSummary = moquiBaseline && moquiBaseline.summary && typeof moquiBaseline.summary === 'object'
|
|
9045
|
+
? moquiBaseline.summary
|
|
9046
|
+
: {};
|
|
9047
|
+
const moquiCompare = moquiBaseline && moquiBaseline.compare && typeof moquiBaseline.compare === 'object'
|
|
9048
|
+
? moquiBaseline.compare
|
|
9049
|
+
: {};
|
|
9050
|
+
const moquiDeltas = moquiCompare && moquiCompare.deltas && typeof moquiCompare.deltas === 'object'
|
|
9051
|
+
? moquiCompare.deltas
|
|
9052
|
+
: {};
|
|
9053
|
+
const moquiFailedTemplates = moquiCompare && moquiCompare.failed_templates && typeof moquiCompare.failed_templates === 'object'
|
|
9054
|
+
? moquiCompare.failed_templates
|
|
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
|
+
: [];
|
|
8940
9068
|
const window = payload.window || { requested: 5, actual: 0 };
|
|
8941
9069
|
const series = Array.isArray(payload.series) ? payload.series : [];
|
|
8942
9070
|
const riskLayers = payload.risk_layers && typeof payload.risk_layers === 'object'
|
|
@@ -8951,7 +9079,11 @@ function renderAutoHandoffEvidenceReviewMarkdown(payload = {}) {
|
|
|
8951
9079
|
const failedGoals = formatAutoHandoffRegressionValue(item.failed_goals);
|
|
8952
9080
|
const successBar = renderAutoHandoffRegressionAsciiBar(item.spec_success_rate_percent, 100, 20);
|
|
8953
9081
|
const ontologyBar = renderAutoHandoffRegressionAsciiBar(item.ontology_quality_score, 100, 20);
|
|
8954
|
-
|
|
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
|
+
);
|
|
8955
9087
|
})
|
|
8956
9088
|
: ['- None'];
|
|
8957
9089
|
const riskLayerLines = ['low', 'medium', 'high', 'unknown'].map(level => {
|
|
@@ -9001,6 +9133,34 @@ function renderAutoHandoffEvidenceReviewMarkdown(payload = {}) {
|
|
|
9001
9133
|
`- Delta risk rank: ${formatAutoHandoffRegressionValue(regression.delta && regression.delta.risk_level_rank)}`,
|
|
9002
9134
|
`- Delta failed goals: ${formatAutoHandoffRegressionValue(regression.delta && regression.delta.failed_goals)}`,
|
|
9003
9135
|
'',
|
|
9136
|
+
'## Current Moqui Baseline',
|
|
9137
|
+
'',
|
|
9138
|
+
`- Status: ${formatAutoHandoffRegressionValue(moquiBaseline.status)}`,
|
|
9139
|
+
`- Portfolio passed: ${moquiSummary.portfolio_passed === true ? 'yes' : (moquiSummary.portfolio_passed === false ? 'no' : 'n/a')}`,
|
|
9140
|
+
`- Avg score: ${formatAutoHandoffRegressionValue(moquiSummary.avg_score)}`,
|
|
9141
|
+
`- Valid-rate: ${formatAutoHandoffRegressionValue(moquiSummary.valid_rate_percent)}%`,
|
|
9142
|
+
`- Baseline failed templates: ${formatAutoHandoffRegressionValue(moquiSummary.baseline_failed)}`,
|
|
9143
|
+
`- Delta avg score: ${formatAutoHandoffRegressionValue(moquiDeltas.avg_score)}`,
|
|
9144
|
+
`- Delta valid-rate: ${formatAutoHandoffRegressionValue(moquiDeltas.valid_rate_percent)}%`,
|
|
9145
|
+
`- Newly failed templates: ${Array.isArray(moquiFailedTemplates.newly_failed) && moquiFailedTemplates.newly_failed.length > 0 ? moquiFailedTemplates.newly_failed.join(', ') : 'none'}`,
|
|
9146
|
+
`- Recovered templates: ${Array.isArray(moquiFailedTemplates.recovered) && moquiFailedTemplates.recovered.length > 0 ? moquiFailedTemplates.recovered.join(', ') : 'none'}`,
|
|
9147
|
+
`- Baseline JSON: ${formatAutoHandoffRegressionValue(moquiBaseline.output && moquiBaseline.output.json)}`,
|
|
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
|
+
'',
|
|
9004
9164
|
'## Trend Series',
|
|
9005
9165
|
'',
|
|
9006
9166
|
...trendSeriesLines,
|
|
@@ -9092,6 +9252,33 @@ function renderAutoHandoffReleaseNotesDraft(payload = {}, context = {}) {
|
|
|
9092
9252
|
const regression = currentOverview.regression && typeof currentOverview.regression === 'object'
|
|
9093
9253
|
? currentOverview.regression
|
|
9094
9254
|
: {};
|
|
9255
|
+
const moquiBaseline = currentOverview.moqui_baseline && typeof currentOverview.moqui_baseline === 'object'
|
|
9256
|
+
? currentOverview.moqui_baseline
|
|
9257
|
+
: {};
|
|
9258
|
+
const moquiSummary = moquiBaseline && moquiBaseline.summary && typeof moquiBaseline.summary === 'object'
|
|
9259
|
+
? moquiBaseline.summary
|
|
9260
|
+
: {};
|
|
9261
|
+
const moquiCompare = moquiBaseline && moquiBaseline.compare && typeof moquiBaseline.compare === 'object'
|
|
9262
|
+
? moquiBaseline.compare
|
|
9263
|
+
: {};
|
|
9264
|
+
const moquiDeltas = moquiCompare && moquiCompare.deltas && typeof moquiCompare.deltas === 'object'
|
|
9265
|
+
? moquiCompare.deltas
|
|
9266
|
+
: {};
|
|
9267
|
+
const moquiFailedTemplates = moquiCompare && moquiCompare.failed_templates && typeof moquiCompare.failed_templates === 'object'
|
|
9268
|
+
? moquiCompare.failed_templates
|
|
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
|
+
: [];
|
|
9095
9282
|
const riskLayers = payload.risk_layers && typeof payload.risk_layers === 'object'
|
|
9096
9283
|
? payload.risk_layers
|
|
9097
9284
|
: {};
|
|
@@ -9136,6 +9323,20 @@ function renderAutoHandoffReleaseNotesDraft(payload = {}, context = {}) {
|
|
|
9136
9323
|
`- Regression trend: ${formatAutoHandoffRegressionValue(regression.trend, formatAutoHandoffRegressionValue(payload.trend))}`,
|
|
9137
9324
|
`- Window trend: ${formatAutoHandoffRegressionValue(payload.window_trend && payload.window_trend.trend)}`,
|
|
9138
9325
|
`- Gate pass rate (window): ${formatAutoHandoffRegressionValue(payload.aggregates && payload.aggregates.gate_pass_rate_percent)}%`,
|
|
9326
|
+
`- Moqui baseline portfolio passed: ${moquiSummary.portfolio_passed === true ? 'yes' : (moquiSummary.portfolio_passed === false ? 'no' : 'n/a')}`,
|
|
9327
|
+
`- Moqui baseline avg score: ${formatAutoHandoffRegressionValue(moquiSummary.avg_score)}`,
|
|
9328
|
+
`- Moqui baseline valid-rate: ${formatAutoHandoffRegressionValue(moquiSummary.valid_rate_percent)}%`,
|
|
9329
|
+
`- Moqui baseline failed templates: ${formatAutoHandoffRegressionValue(moquiSummary.baseline_failed)}`,
|
|
9330
|
+
`- Moqui baseline avg score delta: ${formatAutoHandoffRegressionValue(moquiDeltas.avg_score)}`,
|
|
9331
|
+
`- Moqui baseline valid-rate delta: ${formatAutoHandoffRegressionValue(moquiDeltas.valid_rate_percent)}%`,
|
|
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'}`,
|
|
9139
9340
|
'',
|
|
9140
9341
|
'## Status Breakdown',
|
|
9141
9342
|
'',
|
|
@@ -9154,6 +9355,10 @@ function renderAutoHandoffReleaseNotesDraft(payload = {}, context = {}) {
|
|
|
9154
9355
|
`- Evidence review report: ${reviewFile || 'n/a'}`,
|
|
9155
9356
|
`- Handoff report: ${formatAutoHandoffRegressionValue(currentOverview.handoff_report_file)}`,
|
|
9156
9357
|
`- Release evidence JSON: ${formatAutoHandoffRegressionValue(payload.evidence_file)}`,
|
|
9358
|
+
`- Moqui baseline JSON: ${formatAutoHandoffRegressionValue(moquiBaseline.output && moquiBaseline.output.json)}`,
|
|
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)}`,
|
|
9157
9362
|
'',
|
|
9158
9363
|
'## Recommendations'
|
|
9159
9364
|
];
|
|
@@ -9369,6 +9574,17 @@ function normalizeHandoffMinOntologyScore(scoreCandidate) {
|
|
|
9369
9574
|
return Number(parsed.toFixed(2));
|
|
9370
9575
|
}
|
|
9371
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
|
+
|
|
9372
9588
|
function normalizeHandoffOptionalNonNegativeInteger(valueCandidate, optionName) {
|
|
9373
9589
|
if (valueCandidate === undefined || valueCandidate === null || valueCandidate === '') {
|
|
9374
9590
|
return null;
|
|
@@ -9396,6 +9612,7 @@ function buildAutoHandoffRunPolicy(options = {}) {
|
|
|
9396
9612
|
min_spec_success_rate: normalizeHandoffMinSpecSuccessRate(options.minSpecSuccessRate),
|
|
9397
9613
|
max_risk_level: normalizeHandoffRiskLevel(options.maxRiskLevel),
|
|
9398
9614
|
min_ontology_score: normalizeHandoffMinOntologyScore(options.minOntologyScore),
|
|
9615
|
+
min_capability_coverage_percent: normalizeHandoffMinCapabilityCoverage(options.minCapabilityCoverage),
|
|
9399
9616
|
max_unmapped_rules: normalizeHandoffOptionalNonNegativeInteger(
|
|
9400
9617
|
options.maxUnmappedRules,
|
|
9401
9618
|
'--max-unmapped-rules'
|
|
@@ -9405,6 +9622,8 @@ function buildAutoHandoffRunPolicy(options = {}) {
|
|
|
9405
9622
|
'--max-undecided-decisions'
|
|
9406
9623
|
),
|
|
9407
9624
|
require_ontology_validation: options.requireOntologyValidation !== false,
|
|
9625
|
+
require_moqui_baseline: options.requireMoquiBaseline !== false,
|
|
9626
|
+
require_capability_coverage: options.requireCapabilityCoverage !== false,
|
|
9408
9627
|
dependency_batching: options.dependencyBatching !== false,
|
|
9409
9628
|
release_evidence_window: normalizeHandoffReleaseEvidenceWindow(options.releaseEvidenceWindow)
|
|
9410
9629
|
};
|
|
@@ -9708,6 +9927,84 @@ function evaluateAutoHandoffOntologyGateReasons(policy = {}, ontology = {}) {
|
|
|
9708
9927
|
return reasons;
|
|
9709
9928
|
}
|
|
9710
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
|
+
|
|
9711
10008
|
function collectHandoffBlockers(resultItem) {
|
|
9712
10009
|
const blockers = [];
|
|
9713
10010
|
if (!resultItem) {
|
|
@@ -9792,6 +10089,12 @@ function evaluateAutoHandoffRunGates(context = {}) {
|
|
|
9792
10089
|
present: false,
|
|
9793
10090
|
passed: false
|
|
9794
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;
|
|
9795
10098
|
const kpi = context.programKpi || {
|
|
9796
10099
|
risk_level: 'high'
|
|
9797
10100
|
};
|
|
@@ -9817,6 +10120,8 @@ function evaluateAutoHandoffRunGates(context = {}) {
|
|
|
9817
10120
|
}
|
|
9818
10121
|
|
|
9819
10122
|
reasons.push(...evaluateAutoHandoffOntologyGateReasons(policy, ontology));
|
|
10123
|
+
reasons.push(...evaluateAutoHandoffMoquiBaselineGateReasons(policy, moquiBaseline));
|
|
10124
|
+
reasons.push(...evaluateAutoHandoffCapabilityCoverageGateReasons(policy, capabilityCoverage));
|
|
9820
10125
|
|
|
9821
10126
|
return {
|
|
9822
10127
|
passed: reasons.length === 0,
|
|
@@ -9850,6 +10155,18 @@ function evaluateAutoHandoffRunGates(context = {}) {
|
|
|
9850
10155
|
Number(ontology && ontology.metrics ? ontology.metrics.decision_resolved_rate_percent : null)
|
|
9851
10156
|
)
|
|
9852
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)
|
|
9853
10170
|
: null
|
|
9854
10171
|
},
|
|
9855
10172
|
reasons
|
|
@@ -9939,6 +10256,47 @@ function buildAutoHandoffRunRecommendations(projectPath, result) {
|
|
|
9939
10256
|
push('kse auto governance stats --days 14 --json');
|
|
9940
10257
|
}
|
|
9941
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
|
+
|
|
10267
|
+
const moquiBaseline = result && result.moqui_baseline && typeof result.moqui_baseline === 'object'
|
|
10268
|
+
? result.moqui_baseline
|
|
10269
|
+
: null;
|
|
10270
|
+
const moquiSummary = moquiBaseline && moquiBaseline.summary && typeof moquiBaseline.summary === 'object'
|
|
10271
|
+
? moquiBaseline.summary
|
|
10272
|
+
: null;
|
|
10273
|
+
if (moquiBaseline && moquiBaseline.status === 'error') {
|
|
10274
|
+
push('kse scene moqui-baseline --json');
|
|
10275
|
+
} else if (moquiSummary && moquiSummary.portfolio_passed === false) {
|
|
10276
|
+
push(
|
|
10277
|
+
'kse scene moqui-baseline --include-all ' +
|
|
10278
|
+
'--compare-with .kiro/reports/release-evidence/moqui-template-baseline.json --json'
|
|
10279
|
+
);
|
|
10280
|
+
push(
|
|
10281
|
+
'kse scene package-publish-batch --manifest docs/handoffs/handoff-manifest.json ' +
|
|
10282
|
+
'--dry-run --ontology-task-queue-out .kiro/auto/ontology-remediation.lines --json'
|
|
10283
|
+
);
|
|
10284
|
+
}
|
|
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
|
+
|
|
9942
10300
|
return recommendations;
|
|
9943
10301
|
}
|
|
9944
10302
|
|
|
@@ -10026,6 +10384,33 @@ function buildAutoHandoffReleaseEvidenceEntry(projectPath, result, reportFile =
|
|
|
10026
10384
|
const regressionDelta = regression && regression.delta && typeof regression.delta === 'object'
|
|
10027
10385
|
? regression.delta
|
|
10028
10386
|
: {};
|
|
10387
|
+
const moquiBaseline = result && result.moqui_baseline && typeof result.moqui_baseline === 'object'
|
|
10388
|
+
? result.moqui_baseline
|
|
10389
|
+
: {};
|
|
10390
|
+
const moquiSummary = moquiBaseline && moquiBaseline.summary && typeof moquiBaseline.summary === 'object'
|
|
10391
|
+
? moquiBaseline.summary
|
|
10392
|
+
: {};
|
|
10393
|
+
const moquiCompare = moquiBaseline && moquiBaseline.compare && typeof moquiBaseline.compare === 'object'
|
|
10394
|
+
? moquiBaseline.compare
|
|
10395
|
+
: {};
|
|
10396
|
+
const moquiDeltas = moquiCompare && moquiCompare.deltas && typeof moquiCompare.deltas === 'object'
|
|
10397
|
+
? moquiCompare.deltas
|
|
10398
|
+
: {};
|
|
10399
|
+
const moquiFailedTemplates = moquiCompare && moquiCompare.failed_templates && typeof moquiCompare.failed_templates === 'object'
|
|
10400
|
+
? moquiCompare.failed_templates
|
|
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
|
+
: [];
|
|
10029
10414
|
const batchSummary = result && result.batch_summary && typeof result.batch_summary === 'object'
|
|
10030
10415
|
? result.batch_summary
|
|
10031
10416
|
: {};
|
|
@@ -10084,6 +10469,70 @@ function buildAutoHandoffReleaseEvidenceEntry(projectPath, result, reportFile =
|
|
|
10084
10469
|
ontology_undecided_decisions: toNumber(regressionDelta.ontology_undecided_decisions)
|
|
10085
10470
|
}
|
|
10086
10471
|
},
|
|
10472
|
+
moqui_baseline: {
|
|
10473
|
+
status: normalizeHandoffText(moquiBaseline.status),
|
|
10474
|
+
generated: moquiBaseline.generated === true,
|
|
10475
|
+
reason: normalizeHandoffText(moquiBaseline.reason),
|
|
10476
|
+
error: normalizeHandoffText(moquiBaseline.error),
|
|
10477
|
+
summary: {
|
|
10478
|
+
total_templates: toNumber(moquiSummary.total_templates),
|
|
10479
|
+
scoped_templates: toNumber(moquiSummary.scoped_templates),
|
|
10480
|
+
avg_score: toNumber(moquiSummary.avg_score),
|
|
10481
|
+
valid_rate_percent: toNumber(moquiSummary.valid_rate_percent),
|
|
10482
|
+
baseline_passed: toNumber(moquiSummary.baseline_passed),
|
|
10483
|
+
baseline_failed: toNumber(moquiSummary.baseline_failed),
|
|
10484
|
+
portfolio_passed: moquiSummary.portfolio_passed === true
|
|
10485
|
+
},
|
|
10486
|
+
compare: Object.keys(moquiCompare).length === 0
|
|
10487
|
+
? null
|
|
10488
|
+
: {
|
|
10489
|
+
previous_generated_at: normalizeHandoffText(moquiCompare.previous_generated_at),
|
|
10490
|
+
previous_template_root: normalizeHandoffText(moquiCompare.previous_template_root),
|
|
10491
|
+
deltas: {
|
|
10492
|
+
scoped_templates: toNumber(moquiDeltas.scoped_templates),
|
|
10493
|
+
avg_score: toNumber(moquiDeltas.avg_score),
|
|
10494
|
+
valid_rate_percent: toNumber(moquiDeltas.valid_rate_percent),
|
|
10495
|
+
baseline_passed: toNumber(moquiDeltas.baseline_passed),
|
|
10496
|
+
baseline_failed: toNumber(moquiDeltas.baseline_failed)
|
|
10497
|
+
},
|
|
10498
|
+
failed_templates: {
|
|
10499
|
+
newly_failed: Array.isArray(moquiFailedTemplates.newly_failed) ? moquiFailedTemplates.newly_failed : [],
|
|
10500
|
+
recovered: Array.isArray(moquiFailedTemplates.recovered) ? moquiFailedTemplates.recovered : []
|
|
10501
|
+
}
|
|
10502
|
+
},
|
|
10503
|
+
output: {
|
|
10504
|
+
json: normalizeHandoffText(moquiBaseline && moquiBaseline.output ? moquiBaseline.output.json : null),
|
|
10505
|
+
markdown: normalizeHandoffText(moquiBaseline && moquiBaseline.output ? moquiBaseline.output.markdown : null)
|
|
10506
|
+
}
|
|
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
|
+
},
|
|
10087
10536
|
batch_summary: {
|
|
10088
10537
|
status: normalizeHandoffText(batchSummary.status),
|
|
10089
10538
|
total_goals: toNumber(batchSummary.total_goals),
|
|
@@ -10218,6 +10667,497 @@ async function writeAutoHandoffRunReport(projectPath, result, outCandidate = nul
|
|
|
10218
10667
|
await maybeWriteOutput(result, defaultFile, projectPath);
|
|
10219
10668
|
}
|
|
10220
10669
|
|
|
10670
|
+
function buildAutoHandoffMoquiBaselinePhaseDetails(payload) {
|
|
10671
|
+
const baseline = payload && typeof payload === 'object' ? payload : {};
|
|
10672
|
+
const summary = baseline.summary && typeof baseline.summary === 'object' ? baseline.summary : null;
|
|
10673
|
+
return {
|
|
10674
|
+
status: baseline.status || 'unknown',
|
|
10675
|
+
generated: baseline.generated === true,
|
|
10676
|
+
output: baseline.output || null,
|
|
10677
|
+
portfolio_passed: summary ? summary.portfolio_passed === true : null,
|
|
10678
|
+
avg_score: summary && Number.isFinite(Number(summary.avg_score))
|
|
10679
|
+
? Number(summary.avg_score)
|
|
10680
|
+
: null,
|
|
10681
|
+
valid_rate_percent: summary && Number.isFinite(Number(summary.valid_rate_percent))
|
|
10682
|
+
? Number(summary.valid_rate_percent)
|
|
10683
|
+
: null
|
|
10684
|
+
};
|
|
10685
|
+
}
|
|
10686
|
+
|
|
10687
|
+
async function buildAutoHandoffMoquiBaselineSnapshot(projectPath) {
|
|
10688
|
+
const scriptPath = path.join(projectPath, 'scripts', 'moqui-template-baseline-report.js');
|
|
10689
|
+
if (!(await fs.pathExists(scriptPath))) {
|
|
10690
|
+
return {
|
|
10691
|
+
status: 'skipped',
|
|
10692
|
+
generated: false,
|
|
10693
|
+
reason: `baseline script missing: ${toAutoHandoffCliPath(projectPath, scriptPath)}`
|
|
10694
|
+
};
|
|
10695
|
+
}
|
|
10696
|
+
|
|
10697
|
+
const outputJsonPath = path.join(projectPath, AUTO_HANDOFF_MOQUI_BASELINE_JSON_FILE);
|
|
10698
|
+
const outputMarkdownPath = path.join(projectPath, AUTO_HANDOFF_MOQUI_BASELINE_MARKDOWN_FILE);
|
|
10699
|
+
await fs.ensureDir(path.dirname(outputJsonPath));
|
|
10700
|
+
|
|
10701
|
+
const scriptArgs = [
|
|
10702
|
+
scriptPath,
|
|
10703
|
+
'--out', outputJsonPath,
|
|
10704
|
+
'--markdown-out', outputMarkdownPath,
|
|
10705
|
+
'--json'
|
|
10706
|
+
];
|
|
10707
|
+
|
|
10708
|
+
if (await fs.pathExists(outputJsonPath)) {
|
|
10709
|
+
scriptArgs.push('--compare-with', outputJsonPath);
|
|
10710
|
+
}
|
|
10711
|
+
|
|
10712
|
+
const execution = spawnSync(process.execPath, scriptArgs, {
|
|
10713
|
+
cwd: projectPath,
|
|
10714
|
+
encoding: 'utf8'
|
|
10715
|
+
});
|
|
10716
|
+
|
|
10717
|
+
const stdout = typeof execution.stdout === 'string' ? execution.stdout.trim() : '';
|
|
10718
|
+
const stderr = typeof execution.stderr === 'string' ? execution.stderr.trim() : '';
|
|
10719
|
+
|
|
10720
|
+
if (execution.error) {
|
|
10721
|
+
return {
|
|
10722
|
+
status: 'error',
|
|
10723
|
+
generated: false,
|
|
10724
|
+
error: execution.error.message
|
|
10725
|
+
};
|
|
10726
|
+
}
|
|
10727
|
+
|
|
10728
|
+
if (execution.status !== 0) {
|
|
10729
|
+
return {
|
|
10730
|
+
status: 'error',
|
|
10731
|
+
generated: false,
|
|
10732
|
+
error: stderr || stdout || `baseline script exited with code ${execution.status}`
|
|
10733
|
+
};
|
|
10734
|
+
}
|
|
10735
|
+
|
|
10736
|
+
let reportPayload = null;
|
|
10737
|
+
try {
|
|
10738
|
+
reportPayload = stdout ? JSON.parse(stdout) : await fs.readJson(outputJsonPath);
|
|
10739
|
+
} catch (error) {
|
|
10740
|
+
return {
|
|
10741
|
+
status: 'error',
|
|
10742
|
+
generated: false,
|
|
10743
|
+
error: `failed to parse baseline payload: ${error.message}`
|
|
10744
|
+
};
|
|
10745
|
+
}
|
|
10746
|
+
|
|
10747
|
+
const summary = reportPayload && reportPayload.summary && typeof reportPayload.summary === 'object'
|
|
10748
|
+
? reportPayload.summary
|
|
10749
|
+
: {};
|
|
10750
|
+
const compare = reportPayload && reportPayload.compare && typeof reportPayload.compare === 'object'
|
|
10751
|
+
? reportPayload.compare
|
|
10752
|
+
: null;
|
|
10753
|
+
const failedTemplates = compare && compare.failed_templates && typeof compare.failed_templates === 'object'
|
|
10754
|
+
? compare.failed_templates
|
|
10755
|
+
: {};
|
|
10756
|
+
|
|
10757
|
+
return {
|
|
10758
|
+
status: summary.portfolio_passed === true ? 'passed' : 'failed',
|
|
10759
|
+
generated: true,
|
|
10760
|
+
summary: {
|
|
10761
|
+
total_templates: Number(summary.total_templates) || 0,
|
|
10762
|
+
scoped_templates: Number(summary.scoped_templates) || 0,
|
|
10763
|
+
avg_score: Number.isFinite(Number(summary.avg_score)) ? Number(summary.avg_score) : null,
|
|
10764
|
+
valid_rate_percent: Number.isFinite(Number(summary.valid_rate_percent)) ? Number(summary.valid_rate_percent) : null,
|
|
10765
|
+
baseline_passed: Number(summary.baseline_passed) || 0,
|
|
10766
|
+
baseline_failed: Number(summary.baseline_failed) || 0,
|
|
10767
|
+
portfolio_passed: summary.portfolio_passed === true
|
|
10768
|
+
},
|
|
10769
|
+
compare: compare
|
|
10770
|
+
? {
|
|
10771
|
+
previous_generated_at: compare.previous_generated_at || null,
|
|
10772
|
+
previous_template_root: compare.previous_template_root || null,
|
|
10773
|
+
deltas: compare.deltas || null,
|
|
10774
|
+
failed_templates: {
|
|
10775
|
+
previous: Array.isArray(failedTemplates.previous) ? failedTemplates.previous : [],
|
|
10776
|
+
current: Array.isArray(failedTemplates.current) ? failedTemplates.current : [],
|
|
10777
|
+
newly_failed: Array.isArray(failedTemplates.newly_failed) ? failedTemplates.newly_failed : [],
|
|
10778
|
+
recovered: Array.isArray(failedTemplates.recovered) ? failedTemplates.recovered : []
|
|
10779
|
+
}
|
|
10780
|
+
}
|
|
10781
|
+
: null,
|
|
10782
|
+
output: {
|
|
10783
|
+
json: toAutoHandoffCliPath(projectPath, outputJsonPath),
|
|
10784
|
+
markdown: toAutoHandoffCliPath(projectPath, outputMarkdownPath)
|
|
10785
|
+
},
|
|
10786
|
+
warnings: stderr ? [stderr] : []
|
|
10787
|
+
};
|
|
10788
|
+
}
|
|
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
|
+
|
|
10221
11161
|
async function runAutoHandoff(projectPath, options = {}) {
|
|
10222
11162
|
const startedAtMs = Date.now();
|
|
10223
11163
|
const result = {
|
|
@@ -10239,6 +11179,9 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10239
11179
|
observability_snapshot: null,
|
|
10240
11180
|
spec_status: null,
|
|
10241
11181
|
ontology_validation: null,
|
|
11182
|
+
moqui_baseline: null,
|
|
11183
|
+
moqui_capability_coverage: null,
|
|
11184
|
+
remediation_queue: null,
|
|
10242
11185
|
gates: null,
|
|
10243
11186
|
regression: null,
|
|
10244
11187
|
release_evidence: null,
|
|
@@ -10280,6 +11223,85 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10280
11223
|
throw error;
|
|
10281
11224
|
}
|
|
10282
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
|
+
|
|
10283
11305
|
const queuePhase = beginAutoHandoffRunPhase(result, 'queue', 'Queue generation');
|
|
10284
11306
|
let queue = null;
|
|
10285
11307
|
try {
|
|
@@ -10345,6 +11367,8 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10345
11367
|
dryRun: true,
|
|
10346
11368
|
specStatus: result.spec_status,
|
|
10347
11369
|
ontology: result.ontology_validation,
|
|
11370
|
+
moquiBaseline: result.moqui_baseline,
|
|
11371
|
+
capabilityCoverage: result.moqui_capability_coverage,
|
|
10348
11372
|
programKpi: {
|
|
10349
11373
|
risk_level: 'low'
|
|
10350
11374
|
}
|
|
@@ -10405,6 +11429,8 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10405
11429
|
dryRun: false,
|
|
10406
11430
|
specStatus: result.spec_status,
|
|
10407
11431
|
ontology: result.ontology_validation,
|
|
11432
|
+
moquiBaseline: result.moqui_baseline,
|
|
11433
|
+
capabilityCoverage: result.moqui_capability_coverage,
|
|
10408
11434
|
programKpi: buildProgramKpiSnapshot(result.batch_summary || {})
|
|
10409
11435
|
});
|
|
10410
11436
|
if (!result.gates.passed) {
|
|
@@ -10418,6 +11444,7 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
10418
11444
|
result.completed_at = new Date().toISOString();
|
|
10419
11445
|
result.elapsed_ms = Math.max(0, Date.now() - startedAtMs);
|
|
10420
11446
|
result.regression = await buildAutoHandoffRegression(projectPath, result);
|
|
11447
|
+
result.remediation_queue = await maybeWriteAutoHandoffMoquiRemediationQueue(projectPath, result);
|
|
10421
11448
|
result.recommendations = buildAutoHandoffRunRecommendations(projectPath, result);
|
|
10422
11449
|
await writeAutoHandoffRunReport(projectPath, result, options.out);
|
|
10423
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": {
|