@neurcode-ai/cli 0.9.66 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.telemetry-bundle/dist/__tests__/harvest-verify.test.d.ts +1 -0
- package/.telemetry-bundle/dist/__tests__/harvest-verify.test.js +86 -0
- package/.telemetry-bundle/dist/contracts.d.ts +58 -0
- package/.telemetry-bundle/dist/contracts.js +8 -0
- package/.telemetry-bundle/dist/harvest-verify.d.ts +9 -0
- package/.telemetry-bundle/dist/harvest-verify.js +128 -0
- package/.telemetry-bundle/dist/index.d.ts +10 -0
- package/.telemetry-bundle/dist/index.js +22 -0
- package/.telemetry-bundle/dist/precision/leaderboards.d.ts +20 -0
- package/.telemetry-bundle/dist/precision/leaderboards.js +72 -0
- package/.telemetry-bundle/dist/reader.d.ts +5 -0
- package/.telemetry-bundle/dist/reader.js +46 -0
- package/.telemetry-bundle/dist/stable-json.d.ts +5 -0
- package/.telemetry-bundle/dist/stable-json.js +24 -0
- package/.telemetry-bundle/dist/store.d.ts +10 -0
- package/.telemetry-bundle/dist/store.js +52 -0
- package/.telemetry-bundle/dist/trust-scoring.d.ts +20 -0
- package/.telemetry-bundle/dist/trust-scoring.js +58 -0
- package/.telemetry-bundle/package.json +8 -0
- package/dist/commands/governance.d.ts +3 -0
- package/dist/commands/governance.d.ts.map +1 -0
- package/dist/commands/governance.js +390 -0
- package/dist/commands/governance.js.map +1 -0
- package/dist/commands/quickstart.js +3 -3
- package/dist/commands/quickstart.js.map +1 -1
- package/dist/commands/remediate-export.d.ts +5 -0
- package/dist/commands/remediate-export.d.ts.map +1 -1
- package/dist/commands/remediate-export.js +803 -14
- package/dist/commands/remediate-export.js.map +1 -1
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +14 -0
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/session.d.ts +7 -0
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +156 -0
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/start-intent.d.ts.map +1 -1
- package/dist/commands/start-intent.js +61 -11
- package/dist/commands/start-intent.js.map +1 -1
- package/dist/commands/verify-guidance.d.ts +5 -0
- package/dist/commands/verify-guidance.d.ts.map +1 -0
- package/dist/commands/verify-guidance.js +49 -0
- package/dist/commands/verify-guidance.js.map +1 -0
- package/dist/commands/verify-output.d.ts +37 -0
- package/dist/commands/verify-output.d.ts.map +1 -0
- package/dist/commands/verify-output.js +572 -0
- package/dist/commands/verify-output.js.map +1 -0
- package/dist/commands/verify-render.d.ts +41 -0
- package/dist/commands/verify-render.d.ts.map +1 -0
- package/dist/commands/verify-render.js +457 -0
- package/dist/commands/verify-render.js.map +1 -0
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +278 -1081
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/workspace.d.ts.map +1 -1
- package/dist/commands/workspace.js +3 -14
- package/dist/commands/workspace.js.map +1 -1
- package/dist/context-engine/graph.d.ts.map +1 -1
- package/dist/context-engine/graph.js +69 -7
- package/dist/context-engine/graph.js.map +1 -1
- package/dist/context-engine/scanner.d.ts.map +1 -1
- package/dist/context-engine/scanner.js +9 -2
- package/dist/context-engine/scanner.js.map +1 -1
- package/dist/daemon/compatibility/execution.d.ts +42 -0
- package/dist/daemon/compatibility/execution.d.ts.map +1 -0
- package/dist/daemon/compatibility/execution.js +183 -0
- package/dist/daemon/compatibility/execution.js.map +1 -0
- package/dist/daemon/compatibility/mutation.d.ts +24 -0
- package/dist/daemon/compatibility/mutation.d.ts.map +1 -0
- package/dist/daemon/compatibility/mutation.js +724 -0
- package/dist/daemon/compatibility/mutation.js.map +1 -0
- package/dist/daemon/routes.d.ts +19 -0
- package/dist/daemon/routes.d.ts.map +1 -0
- package/dist/daemon/routes.js +123 -0
- package/dist/daemon/routes.js.map +1 -0
- package/dist/daemon/runtime/execution-bus.d.ts +217 -0
- package/dist/daemon/runtime/execution-bus.d.ts.map +1 -0
- package/dist/daemon/runtime/execution-bus.js +1420 -0
- package/dist/daemon/runtime/execution-bus.js.map +1 -0
- package/dist/daemon/runtime/workspace-runtime.d.ts +280 -0
- package/dist/daemon/runtime/workspace-runtime.d.ts.map +1 -0
- package/dist/daemon/runtime/workspace-runtime.js +1473 -0
- package/dist/daemon/runtime/workspace-runtime.js.map +1 -0
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +171 -874
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/shaping.d.ts +11 -0
- package/dist/daemon/shaping.d.ts.map +1 -0
- package/dist/daemon/shaping.js +240 -0
- package/dist/daemon/shaping.js.map +1 -0
- package/dist/governance/canonical-pipeline.d.ts +2 -1
- package/dist/governance/canonical-pipeline.d.ts.map +1 -1
- package/dist/governance/canonical-pipeline.js +259 -84
- package/dist/governance/canonical-pipeline.js.map +1 -1
- package/dist/governance/structural-cache.d.ts.map +1 -1
- package/dist/governance/structural-cache.js +2 -7
- package/dist/governance/structural-cache.js.map +1 -1
- package/dist/index.js +230 -66
- package/dist/index.js.map +1 -1
- package/dist/utils/active-engineering-context.d.ts +12 -0
- package/dist/utils/active-engineering-context.d.ts.map +1 -0
- package/dist/utils/active-engineering-context.js +67 -0
- package/dist/utils/active-engineering-context.js.map +1 -0
- package/dist/utils/artifact-io.d.ts +33 -0
- package/dist/utils/artifact-io.d.ts.map +1 -0
- package/dist/utils/artifact-io.js +183 -0
- package/dist/utils/artifact-io.js.map +1 -0
- package/dist/utils/change-contract.d.ts +6 -2
- package/dist/utils/change-contract.d.ts.map +1 -1
- package/dist/utils/change-contract.js +175 -0
- package/dist/utils/change-contract.js.map +1 -1
- package/dist/utils/context-pack.d.ts +12 -0
- package/dist/utils/context-pack.d.ts.map +1 -0
- package/dist/utils/context-pack.js +147 -0
- package/dist/utils/context-pack.js.map +1 -0
- package/dist/utils/control-plane.d.ts +18 -0
- package/dist/utils/control-plane.d.ts.map +1 -1
- package/dist/utils/control-plane.js +31 -4
- package/dist/utils/control-plane.js.map +1 -1
- package/dist/utils/drift-intelligence.d.ts +47 -0
- package/dist/utils/drift-intelligence.d.ts.map +1 -0
- package/dist/utils/drift-intelligence.js +2099 -0
- package/dist/utils/drift-intelligence.js.map +1 -0
- package/dist/utils/execution-actions.d.ts +22 -0
- package/dist/utils/execution-actions.d.ts.map +1 -0
- package/dist/utils/execution-actions.js +103 -0
- package/dist/utils/execution-actions.js.map +1 -0
- package/dist/utils/execution-bus.d.ts +1 -214
- package/dist/utils/execution-bus.d.ts.map +1 -1
- package/dist/utils/execution-bus.js +15 -1359
- package/dist/utils/execution-bus.js.map +1 -1
- package/dist/utils/git.d.ts +1 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +13 -3
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/governance-decisions.d.ts +75 -0
- package/dist/utils/governance-decisions.d.ts.map +1 -0
- package/dist/utils/governance-decisions.js +412 -0
- package/dist/utils/governance-decisions.js.map +1 -0
- package/dist/utils/governance-provenance.d.ts +1 -1
- package/dist/utils/governance-provenance.d.ts.map +1 -1
- package/dist/utils/governance-provenance.js +5 -7
- package/dist/utils/governance-provenance.js.map +1 -1
- package/dist/utils/governance.d.ts +108 -0
- package/dist/utils/governance.d.ts.map +1 -1
- package/dist/utils/governance.js +209 -7
- package/dist/utils/governance.js.map +1 -1
- package/dist/utils/intelligence-runtime-common.d.ts +30 -0
- package/dist/utils/intelligence-runtime-common.d.ts.map +1 -0
- package/dist/utils/intelligence-runtime-common.js +156 -0
- package/dist/utils/intelligence-runtime-common.js.map +1 -0
- package/dist/utils/intent-contract-diagnostics.d.ts +9 -0
- package/dist/utils/intent-contract-diagnostics.d.ts.map +1 -0
- package/dist/utils/intent-contract-diagnostics.js +322 -0
- package/dist/utils/intent-contract-diagnostics.js.map +1 -0
- package/dist/utils/intent-pack.d.ts +15 -0
- package/dist/utils/intent-pack.d.ts.map +1 -0
- package/dist/utils/intent-pack.js +196 -0
- package/dist/utils/intent-pack.js.map +1 -0
- package/dist/utils/plan-sync.d.ts +1 -0
- package/dist/utils/plan-sync.d.ts.map +1 -1
- package/dist/utils/plan-sync.js +23 -0
- package/dist/utils/plan-sync.js.map +1 -1
- package/dist/utils/policy-decision.d.ts +5 -0
- package/dist/utils/policy-decision.d.ts.map +1 -0
- package/dist/utils/policy-decision.js +17 -0
- package/dist/utils/policy-decision.js.map +1 -0
- package/dist/utils/replay-custody.d.ts +43 -0
- package/dist/utils/replay-custody.d.ts.map +1 -0
- package/dist/utils/replay-custody.js +168 -0
- package/dist/utils/replay-custody.js.map +1 -0
- package/dist/utils/replay-runtime.d.ts +13 -0
- package/dist/utils/replay-runtime.d.ts.map +1 -1
- package/dist/utils/replay-runtime.js +96 -9
- package/dist/utils/replay-runtime.js.map +1 -1
- package/dist/utils/repository-intelligence.d.ts +9 -0
- package/dist/utils/repository-intelligence.d.ts.map +1 -0
- package/dist/utils/repository-intelligence.js +372 -0
- package/dist/utils/repository-intelligence.js.map +1 -0
- package/dist/utils/runtime-events.d.ts.map +1 -1
- package/dist/utils/runtime-events.js +25 -6
- package/dist/utils/runtime-events.js.map +1 -1
- package/dist/utils/semantic-contract-intelligence.d.ts +20 -0
- package/dist/utils/semantic-contract-intelligence.d.ts.map +1 -0
- package/dist/utils/semantic-contract-intelligence.js +825 -0
- package/dist/utils/semantic-contract-intelligence.js.map +1 -0
- package/dist/utils/session-continuity.d.ts +56 -0
- package/dist/utils/session-continuity.d.ts.map +1 -0
- package/dist/utils/session-continuity.js +318 -0
- package/dist/utils/session-continuity.js.map +1 -0
- package/dist/utils/verification-evidence.d.ts.map +1 -1
- package/dist/utils/verification-evidence.js +4 -1
- package/dist/utils/verification-evidence.js.map +1 -1
- package/dist/utils/workspace-runtime.d.ts +1 -266
- package/dist/utils/workspace-runtime.d.ts.map +1 -1
- package/dist/utils/workspace-runtime.js +15 -1412
- package/dist/utils/workspace-runtime.js.map +1 -1
- package/package.json +13 -11
- package/LICENSE +0 -201
package/dist/commands/verify.js
CHANGED
|
@@ -67,6 +67,9 @@ const policy_compiler_1 = require("../utils/policy-compiler");
|
|
|
67
67
|
const change_contract_1 = require("../utils/change-contract");
|
|
68
68
|
const diff_symbols_1 = require("../utils/diff-symbols");
|
|
69
69
|
const advisory_signals_1 = require("../utils/advisory-signals");
|
|
70
|
+
const verify_guidance_1 = require("./verify-guidance");
|
|
71
|
+
const verify_output_1 = require("./verify-output");
|
|
72
|
+
const verify_render_1 = require("./verify-render");
|
|
70
73
|
const structural_rules_1 = require("../structural-rules");
|
|
71
74
|
const canonical_pipeline_1 = require("../governance/canonical-pipeline");
|
|
72
75
|
const canonical_invariants_1 = require("../governance/canonical-invariants");
|
|
@@ -76,15 +79,16 @@ const structural_on_diff_1 = require("../governance/structural-on-diff");
|
|
|
76
79
|
// into the canonical pipeline. Merging them into policyViolations caused
|
|
77
80
|
// duplicate GovernanceFinding objects (fixed in Phase 1 canonical graph hardening).
|
|
78
81
|
const telemetry_1 = require("@neurcode-ai/telemetry");
|
|
79
|
-
const governance_provenance_1 = require("../utils/governance-provenance");
|
|
80
82
|
const pilot_metrics_1 = require("../utils/pilot-metrics");
|
|
81
|
-
const
|
|
83
|
+
const replay_custody_1 = require("../utils/replay-custody");
|
|
82
84
|
const runtime_guard_1 = require("../utils/runtime-guard");
|
|
83
85
|
const artifact_signature_1 = require("../utils/artifact-signature");
|
|
84
86
|
const policy_1 = require("@neurcode-ai/policy");
|
|
87
|
+
const active_engineering_context_1 = require("../utils/active-engineering-context");
|
|
85
88
|
const ai_debt_budget_1 = require("../utils/ai-debt-budget");
|
|
86
89
|
const verification_evidence_1 = require("../utils/verification-evidence");
|
|
87
90
|
const verify_runtime_stability_1 = require("../utils/verify-runtime-stability");
|
|
91
|
+
const policy_decision_1 = require("../utils/policy-decision");
|
|
88
92
|
// Import chalk with fallback
|
|
89
93
|
let chalk;
|
|
90
94
|
try {
|
|
@@ -137,6 +141,42 @@ function logCiPolicyOnlyOutcomeExplainability(params) {
|
|
|
137
141
|
}
|
|
138
142
|
console.log(chalk.dim(' Next: resolve BLOCKING first → `neurcode remediate-export` (optional) → re-run `neurcode verify --ci`.\n'));
|
|
139
143
|
}
|
|
144
|
+
function driftSeverityToPolicySeverity(severity) {
|
|
145
|
+
return severity === 'critical' || severity === 'high' ? 'block' : 'warn';
|
|
146
|
+
}
|
|
147
|
+
function driftGateToPolicySeverity(gate, fallbackSeverity) {
|
|
148
|
+
if (gate === 'policy-blocker' || gate === 'rollout-blocker' || gate === 'architecture-blocker') {
|
|
149
|
+
return 'block';
|
|
150
|
+
}
|
|
151
|
+
if (gate === 'review-blocker' || gate === 'advisory') {
|
|
152
|
+
return 'warn';
|
|
153
|
+
}
|
|
154
|
+
return driftSeverityToPolicySeverity(fallbackSeverity);
|
|
155
|
+
}
|
|
156
|
+
function driftFindingsToVerificationViolations(drift) {
|
|
157
|
+
if (!drift || !Array.isArray(drift.findings)) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
if (Array.isArray(drift.narratives) && drift.narratives.length > 0) {
|
|
161
|
+
return drift.narratives.map((narrative) => ({
|
|
162
|
+
file: narrative.affectedFiles[0]
|
|
163
|
+
|| narrative.affectedModules[0]
|
|
164
|
+
|| narrative.affectedServices[0]
|
|
165
|
+
|| '.neurcode/intent-pack.json',
|
|
166
|
+
rule: `drift_narrative:${narrative.category}`,
|
|
167
|
+
severity: driftGateToPolicySeverity(drift.riskSynthesis?.governanceGate, narrative.severity),
|
|
168
|
+
message: narrative.summary,
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
return drift.findings.map((finding) => ({
|
|
172
|
+
file: finding.file || finding.module || finding.service || '.neurcode/intent-pack.json',
|
|
173
|
+
rule: `drift_intelligence:${finding.category}`,
|
|
174
|
+
severity: driftGateToPolicySeverity(finding.governanceGate, finding.severity),
|
|
175
|
+
message: finding.priority
|
|
176
|
+
? `${finding.message} (${finding.priority}; ${finding.governanceGate || 'review-blocker'})`
|
|
177
|
+
: finding.message,
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
140
180
|
;
|
|
141
181
|
function toArtifactSignatureSummary(status) {
|
|
142
182
|
return {
|
|
@@ -697,569 +737,6 @@ function runtimeGuardViolationsToReport(summary) {
|
|
|
697
737
|
message: item.message,
|
|
698
738
|
}));
|
|
699
739
|
}
|
|
700
|
-
function asObjectRecord(value) {
|
|
701
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
702
|
-
return null;
|
|
703
|
-
}
|
|
704
|
-
return value;
|
|
705
|
-
}
|
|
706
|
-
function asObjectArray(value) {
|
|
707
|
-
if (!Array.isArray(value)) {
|
|
708
|
-
return [];
|
|
709
|
-
}
|
|
710
|
-
return value
|
|
711
|
-
.map((item) => asObjectRecord(item))
|
|
712
|
-
.filter((item) => item !== null);
|
|
713
|
-
}
|
|
714
|
-
function asBooleanFlag(value) {
|
|
715
|
-
return typeof value === 'boolean' ? value : null;
|
|
716
|
-
}
|
|
717
|
-
function asNumberValue(value) {
|
|
718
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
719
|
-
}
|
|
720
|
-
function asStringValue(value) {
|
|
721
|
-
return typeof value === 'string' && value.trim().length > 0 ? value : null;
|
|
722
|
-
}
|
|
723
|
-
const EXPEDITE_FOLLOW_UP_CHECKLIST = [
|
|
724
|
-
'Add validation back',
|
|
725
|
-
'Move logic to proper layer',
|
|
726
|
-
'Remove temporary code',
|
|
727
|
-
];
|
|
728
|
-
function containsAnyToken(value, tokens) {
|
|
729
|
-
const normalized = value.toLowerCase();
|
|
730
|
-
return tokens.some((token) => normalized.includes(token));
|
|
731
|
-
}
|
|
732
|
-
function isSecurityOrAuthViolation(fileRaw, policyRaw, messageRaw) {
|
|
733
|
-
const combined = `${fileRaw} ${policyRaw} ${messageRaw}`.toLowerCase();
|
|
734
|
-
return containsAnyToken(combined, [
|
|
735
|
-
'auth',
|
|
736
|
-
'authentication',
|
|
737
|
-
'authorization',
|
|
738
|
-
'security',
|
|
739
|
-
'permission',
|
|
740
|
-
'access control',
|
|
741
|
-
'access_control',
|
|
742
|
-
'token',
|
|
743
|
-
'secret',
|
|
744
|
-
'credential',
|
|
745
|
-
'encryption',
|
|
746
|
-
'encrypt',
|
|
747
|
-
'decrypt',
|
|
748
|
-
'csrf',
|
|
749
|
-
'xss',
|
|
750
|
-
'sql injection',
|
|
751
|
-
'sqli',
|
|
752
|
-
'insecure',
|
|
753
|
-
'vulnerability',
|
|
754
|
-
]);
|
|
755
|
-
}
|
|
756
|
-
function isCriticalScopeBreach(fileRaw, messageRaw) {
|
|
757
|
-
const combined = `${fileRaw} ${messageRaw}`.toLowerCase();
|
|
758
|
-
return containsAnyToken(combined, [
|
|
759
|
-
'auth',
|
|
760
|
-
'security',
|
|
761
|
-
'secret',
|
|
762
|
-
'token',
|
|
763
|
-
'credential',
|
|
764
|
-
'permission',
|
|
765
|
-
'infra/terraform',
|
|
766
|
-
'terraform',
|
|
767
|
-
'k8s',
|
|
768
|
-
'helm',
|
|
769
|
-
'migration',
|
|
770
|
-
'database/migration',
|
|
771
|
-
'policy',
|
|
772
|
-
'contract',
|
|
773
|
-
]);
|
|
774
|
-
}
|
|
775
|
-
function resolveExpediteModeFromPayload(payload) {
|
|
776
|
-
const explicit = asBooleanFlag(payload.expediteMode);
|
|
777
|
-
if (explicit !== null) {
|
|
778
|
-
return explicit;
|
|
779
|
-
}
|
|
780
|
-
const message = asStringValue(payload.message) || '';
|
|
781
|
-
return containsAnyToken(message, ['hotfix', 'urgent', 'prod down', 'incident', 'expedite']);
|
|
782
|
-
}
|
|
783
|
-
function toVerifySeverity(value) {
|
|
784
|
-
const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
785
|
-
if (normalized === 'critical' || normalized === 'block')
|
|
786
|
-
return 'critical';
|
|
787
|
-
if (normalized === 'high')
|
|
788
|
-
return 'high';
|
|
789
|
-
if (normalized === 'warn'
|
|
790
|
-
|| normalized === 'warning'
|
|
791
|
-
|| normalized === 'medium'
|
|
792
|
-
|| normalized === 'low') {
|
|
793
|
-
return 'warning';
|
|
794
|
-
}
|
|
795
|
-
return 'info';
|
|
796
|
-
}
|
|
797
|
-
function toVerifyVerdict(value) {
|
|
798
|
-
const normalized = typeof value === 'string' ? value.trim().toUpperCase() : '';
|
|
799
|
-
if (normalized === 'PASS' || normalized === 'WARN' || normalized === 'FAIL') {
|
|
800
|
-
return normalized;
|
|
801
|
-
}
|
|
802
|
-
return 'FAIL';
|
|
803
|
-
}
|
|
804
|
-
function normalizeScopeIssueMessage(rawMessage) {
|
|
805
|
-
const message = asStringValue(rawMessage);
|
|
806
|
-
return message || 'File modified outside intended scope';
|
|
807
|
-
}
|
|
808
|
-
function pushVerifyIssue(target, seen, key, value) {
|
|
809
|
-
if (seen.has(key))
|
|
810
|
-
return;
|
|
811
|
-
seen.add(key);
|
|
812
|
-
target.push(value);
|
|
813
|
-
}
|
|
814
|
-
function dedupeTriageItems(items) {
|
|
815
|
-
const seen = new Set();
|
|
816
|
-
const output = [];
|
|
817
|
-
for (const item of items) {
|
|
818
|
-
const key = `${item.source}|${item.file.toLowerCase()}|${item.policy.toLowerCase()}|${item.message.toLowerCase()}`;
|
|
819
|
-
if (seen.has(key))
|
|
820
|
-
continue;
|
|
821
|
-
seen.add(key);
|
|
822
|
-
output.push(item);
|
|
823
|
-
}
|
|
824
|
-
return output;
|
|
825
|
-
}
|
|
826
|
-
function toCanonicalVerifyOutput(payload) {
|
|
827
|
-
const verdict = toVerifyVerdict(payload.verdict);
|
|
828
|
-
const violations = [];
|
|
829
|
-
const warnings = [];
|
|
830
|
-
const scopeIssues = [];
|
|
831
|
-
const seenViolations = new Set();
|
|
832
|
-
const seenWarnings = new Set();
|
|
833
|
-
const seenScopeIssues = new Set();
|
|
834
|
-
const addScopeIssue = (fileRaw, messageRaw) => {
|
|
835
|
-
const file = asStringValue(fileRaw) || 'unknown';
|
|
836
|
-
const message = normalizeScopeIssueMessage(messageRaw);
|
|
837
|
-
const key = file.toLowerCase();
|
|
838
|
-
pushVerifyIssue(scopeIssues, seenScopeIssues, key, { file, message });
|
|
839
|
-
};
|
|
840
|
-
const addWarning = (fileRaw, messageRaw, policyRaw) => {
|
|
841
|
-
const file = asStringValue(fileRaw) || 'unknown';
|
|
842
|
-
const message = asStringValue(messageRaw) || 'Warning detected';
|
|
843
|
-
const policy = asStringValue(policyRaw) || 'warning';
|
|
844
|
-
const key = `${file.toLowerCase()}|${message.toLowerCase()}|${policy.toLowerCase()}`;
|
|
845
|
-
pushVerifyIssue(warnings, seenWarnings, key, { file, message, policy });
|
|
846
|
-
};
|
|
847
|
-
const addViolation = (fileRaw, messageRaw, policyRaw, severityRaw) => {
|
|
848
|
-
const file = asStringValue(fileRaw) || 'unknown';
|
|
849
|
-
const message = asStringValue(messageRaw) || 'Policy violation detected';
|
|
850
|
-
const policy = asStringValue(policyRaw) || 'unknown_policy';
|
|
851
|
-
const severity = toVerifySeverity(severityRaw);
|
|
852
|
-
const key = `${file.toLowerCase()}|${message.toLowerCase()}|${policy.toLowerCase()}|${severity}`;
|
|
853
|
-
pushVerifyIssue(violations, seenViolations, key, { file, message, policy, severity });
|
|
854
|
-
};
|
|
855
|
-
const rawScopeIssues = Array.isArray(payload.scopeIssues) ? payload.scopeIssues : [];
|
|
856
|
-
for (const item of rawScopeIssues) {
|
|
857
|
-
const record = asObjectRecord(item);
|
|
858
|
-
if (record) {
|
|
859
|
-
addScopeIssue(record.file, record.message);
|
|
860
|
-
}
|
|
861
|
-
else {
|
|
862
|
-
addScopeIssue(item, null);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
const rawBloatFiles = Array.isArray(payload.bloatFiles) ? payload.bloatFiles : [];
|
|
866
|
-
for (const item of rawBloatFiles) {
|
|
867
|
-
addScopeIssue(item, null);
|
|
868
|
-
}
|
|
869
|
-
const rawWarnings = Array.isArray(payload.warnings) ? payload.warnings : [];
|
|
870
|
-
for (const item of rawWarnings) {
|
|
871
|
-
const record = asObjectRecord(item);
|
|
872
|
-
if (record) {
|
|
873
|
-
addWarning(record.file, record.message, record.policy ?? record.rule);
|
|
874
|
-
}
|
|
875
|
-
else if (typeof item === 'string') {
|
|
876
|
-
addWarning('unknown', item, 'warning');
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
const rawViolations = Array.isArray(payload.violations) ? payload.violations : [];
|
|
880
|
-
for (const item of rawViolations) {
|
|
881
|
-
const record = asObjectRecord(item);
|
|
882
|
-
if (!record)
|
|
883
|
-
continue;
|
|
884
|
-
const file = record.file;
|
|
885
|
-
const message = record.message;
|
|
886
|
-
const policy = record.policy ?? record.rule;
|
|
887
|
-
const severity = toVerifySeverity(record.severity);
|
|
888
|
-
const combined = `${String(policy || '').toLowerCase()} ${String(message || '').toLowerCase()}`;
|
|
889
|
-
const isScopeIssue = combined.includes('scope_guard')
|
|
890
|
-
|| combined.includes('scope')
|
|
891
|
-
|| combined.includes('outside the plan')
|
|
892
|
-
|| combined.includes('out of scope');
|
|
893
|
-
if (isScopeIssue) {
|
|
894
|
-
addScopeIssue(file, message);
|
|
895
|
-
continue;
|
|
896
|
-
}
|
|
897
|
-
// Artifact presence/signature checks are advisory — they must never block a PR.
|
|
898
|
-
// Real governance signal (policy violations, scope drift) should not be obscured
|
|
899
|
-
// by infrastructure setup state.
|
|
900
|
-
const policyStr = String(policy || '').toLowerCase();
|
|
901
|
-
const isArtifactCheck = policyStr === 'deterministic_artifacts_required'
|
|
902
|
-
|| policyStr === 'signed_artifacts_required';
|
|
903
|
-
if (isArtifactCheck) {
|
|
904
|
-
addWarning(file, message, policy);
|
|
905
|
-
continue;
|
|
906
|
-
}
|
|
907
|
-
if (severity === 'warning' || severity === 'info') {
|
|
908
|
-
addWarning(file, message, policy);
|
|
909
|
-
continue;
|
|
910
|
-
}
|
|
911
|
-
addViolation(file, message, policy, severity);
|
|
912
|
-
}
|
|
913
|
-
const payloadMessage = asStringValue(payload.message);
|
|
914
|
-
if (payloadMessage
|
|
915
|
-
&& violations.length === 0
|
|
916
|
-
&& warnings.length === 0
|
|
917
|
-
&& scopeIssues.length === 0) {
|
|
918
|
-
addWarning('unknown', payloadMessage, 'verify_result');
|
|
919
|
-
}
|
|
920
|
-
const summaryRecord = asObjectRecord(payload.summary);
|
|
921
|
-
const fileSet = new Set();
|
|
922
|
-
for (const violation of violations)
|
|
923
|
-
fileSet.add(violation.file);
|
|
924
|
-
for (const warning of warnings)
|
|
925
|
-
fileSet.add(warning.file);
|
|
926
|
-
for (const scopeIssue of scopeIssues)
|
|
927
|
-
fileSet.add(scopeIssue.file);
|
|
928
|
-
const totalFilesChanged = (() => {
|
|
929
|
-
const fromSummary = summaryRecord ? asNumberValue(summaryRecord.totalFilesChanged) : null;
|
|
930
|
-
if (fromSummary !== null)
|
|
931
|
-
return Math.max(0, Math.floor(fromSummary));
|
|
932
|
-
const blastRadius = asObjectRecord(payload.blastRadius);
|
|
933
|
-
const fromBlastRadius = blastRadius ? asNumberValue(blastRadius.filesChanged) : null;
|
|
934
|
-
if (fromBlastRadius !== null)
|
|
935
|
-
return Math.max(0, Math.floor(fromBlastRadius));
|
|
936
|
-
return fileSet.size;
|
|
937
|
-
})();
|
|
938
|
-
const driftScoreRaw = asNumberValue(payload.driftScore);
|
|
939
|
-
const driftScore = driftScoreRaw === null
|
|
940
|
-
? undefined
|
|
941
|
-
: Math.max(0, Math.min(100, Math.round(driftScoreRaw)));
|
|
942
|
-
const expediteModeUsed = resolveExpediteModeFromPayload(payload);
|
|
943
|
-
const scopeTriageItems = scopeIssues.map((item) => ({
|
|
944
|
-
file: item.file,
|
|
945
|
-
message: item.message,
|
|
946
|
-
policy: 'scope_guard',
|
|
947
|
-
severity: 'block',
|
|
948
|
-
source: 'scope',
|
|
949
|
-
}));
|
|
950
|
-
const violationTriageItems = violations.map((item) => ({
|
|
951
|
-
file: item.file,
|
|
952
|
-
message: item.message,
|
|
953
|
-
policy: item.policy,
|
|
954
|
-
severity: item.severity,
|
|
955
|
-
source: 'violation',
|
|
956
|
-
}));
|
|
957
|
-
const warningTriageItems = warnings.map((item) => ({
|
|
958
|
-
file: item.file,
|
|
959
|
-
message: item.message,
|
|
960
|
-
policy: item.policy,
|
|
961
|
-
severity: 'warning',
|
|
962
|
-
source: 'warning',
|
|
963
|
-
}));
|
|
964
|
-
const defaultBlockingItems = dedupeTriageItems([
|
|
965
|
-
...scopeTriageItems,
|
|
966
|
-
...violationTriageItems.filter((item) => item.severity === 'critical' || item.severity === 'high'),
|
|
967
|
-
]);
|
|
968
|
-
const defaultAdvisoryItems = dedupeTriageItems([
|
|
969
|
-
...warningTriageItems,
|
|
970
|
-
...violationTriageItems.filter((item) => item.severity === 'warning' || item.severity === 'info'),
|
|
971
|
-
]);
|
|
972
|
-
const expediteBlockingItems = dedupeTriageItems([
|
|
973
|
-
...scopeTriageItems.filter((item) => isCriticalScopeBreach(item.file, item.message)),
|
|
974
|
-
...violationTriageItems.filter((item) => isSecurityOrAuthViolation(item.file, item.policy, item.message)),
|
|
975
|
-
...warningTriageItems
|
|
976
|
-
.filter((item) => isSecurityOrAuthViolation(item.file, item.policy, item.message))
|
|
977
|
-
.map((item) => ({
|
|
978
|
-
...item,
|
|
979
|
-
source: 'violation',
|
|
980
|
-
})),
|
|
981
|
-
]);
|
|
982
|
-
const expediteItems = dedupeTriageItems([
|
|
983
|
-
...scopeTriageItems
|
|
984
|
-
.filter((item) => !isCriticalScopeBreach(item.file, item.message))
|
|
985
|
-
.map((item) => ({
|
|
986
|
-
...item,
|
|
987
|
-
source: 'expedite',
|
|
988
|
-
})),
|
|
989
|
-
...violationTriageItems
|
|
990
|
-
.filter((item) => !isSecurityOrAuthViolation(item.file, item.policy, item.message))
|
|
991
|
-
.map((item) => ({
|
|
992
|
-
...item,
|
|
993
|
-
source: 'expedite',
|
|
994
|
-
})),
|
|
995
|
-
...warningTriageItems
|
|
996
|
-
.filter((item) => !isSecurityOrAuthViolation(item.file, item.policy, item.message))
|
|
997
|
-
.map((item) => ({
|
|
998
|
-
...item,
|
|
999
|
-
source: 'expedite',
|
|
1000
|
-
})),
|
|
1001
|
-
]);
|
|
1002
|
-
// ── Intent issues and summary from engine ───────────────────────────────
|
|
1003
|
-
const rawIntentIssues = Array.isArray(payload.intentIssues) ? payload.intentIssues : [];
|
|
1004
|
-
const intentDomains = Array.isArray(payload.intentDomains) ? payload.intentDomains : [];
|
|
1005
|
-
const intentSummary = (payload.intentSummary ?? null);
|
|
1006
|
-
const rawFlowIssues = Array.isArray(payload.flowIssues) ? payload.flowIssues : [];
|
|
1007
|
-
const rawRegressions = Array.isArray(payload.regressions) ? payload.regressions : [];
|
|
1008
|
-
// High-severity intent issues become blocking; medium become advisory.
|
|
1009
|
-
const intentBlockingTriageItems = rawIntentIssues
|
|
1010
|
-
.filter((i) => i.severity === 'high')
|
|
1011
|
-
.map((i) => ({
|
|
1012
|
-
file: (i.files?.[0]) ?? 'intent-analysis',
|
|
1013
|
-
message: i.message,
|
|
1014
|
-
policy: i.rule,
|
|
1015
|
-
severity: 'high',
|
|
1016
|
-
source: 'violation',
|
|
1017
|
-
}));
|
|
1018
|
-
const intentAdvisoryTriageItems = rawIntentIssues
|
|
1019
|
-
.filter((i) => i.severity === 'medium')
|
|
1020
|
-
.map((i) => ({
|
|
1021
|
-
file: (i.files?.[0]) ?? 'intent-analysis',
|
|
1022
|
-
message: i.message,
|
|
1023
|
-
policy: i.rule,
|
|
1024
|
-
severity: 'warning',
|
|
1025
|
-
source: 'warning',
|
|
1026
|
-
}));
|
|
1027
|
-
// V5: flow issues — high → blocking, medium → advisory
|
|
1028
|
-
const flowBlockingTriageItems = rawFlowIssues
|
|
1029
|
-
.filter((i) => i.severity === 'high')
|
|
1030
|
-
.map((i) => ({
|
|
1031
|
-
file: (i.files?.[0]) ?? 'flow-analysis',
|
|
1032
|
-
message: i.message,
|
|
1033
|
-
policy: i.rule,
|
|
1034
|
-
severity: 'high',
|
|
1035
|
-
source: 'violation',
|
|
1036
|
-
}));
|
|
1037
|
-
const flowAdvisoryTriageItems = rawFlowIssues
|
|
1038
|
-
.filter((i) => i.severity === 'medium')
|
|
1039
|
-
.map((i) => ({
|
|
1040
|
-
file: (i.files?.[0]) ?? 'flow-analysis',
|
|
1041
|
-
message: i.message,
|
|
1042
|
-
policy: i.rule,
|
|
1043
|
-
severity: 'warning',
|
|
1044
|
-
source: 'warning',
|
|
1045
|
-
}));
|
|
1046
|
-
let blockingItems = expediteModeUsed ? expediteBlockingItems : defaultBlockingItems;
|
|
1047
|
-
let advisoryItems = expediteModeUsed ? expediteItems : defaultAdvisoryItems;
|
|
1048
|
-
if (intentBlockingTriageItems.length > 0) {
|
|
1049
|
-
blockingItems = dedupeTriageItems([...blockingItems, ...intentBlockingTriageItems]);
|
|
1050
|
-
}
|
|
1051
|
-
if (intentAdvisoryTriageItems.length > 0) {
|
|
1052
|
-
advisoryItems = dedupeTriageItems([...advisoryItems, ...intentAdvisoryTriageItems]);
|
|
1053
|
-
}
|
|
1054
|
-
if (flowBlockingTriageItems.length > 0) {
|
|
1055
|
-
blockingItems = dedupeTriageItems([...blockingItems, ...flowBlockingTriageItems]);
|
|
1056
|
-
}
|
|
1057
|
-
if (flowAdvisoryTriageItems.length > 0) {
|
|
1058
|
-
advisoryItems = dedupeTriageItems([...advisoryItems, ...flowAdvisoryTriageItems]);
|
|
1059
|
-
}
|
|
1060
|
-
// V6: regressions — always blocking
|
|
1061
|
-
const regressionBlockingTriageItems = rawRegressions.map((r) => ({
|
|
1062
|
-
file: 'regression-analysis',
|
|
1063
|
-
message: r.message,
|
|
1064
|
-
policy: r.rule,
|
|
1065
|
-
severity: 'high',
|
|
1066
|
-
source: 'violation',
|
|
1067
|
-
}));
|
|
1068
|
-
if (regressionBlockingTriageItems.length > 0) {
|
|
1069
|
-
blockingItems = dedupeTriageItems([...regressionBlockingTriageItems, ...blockingItems]);
|
|
1070
|
-
}
|
|
1071
|
-
const grade = verdict === 'PASS' ? 'A' : verdict === 'WARN' ? 'C' : 'F';
|
|
1072
|
-
const canonical = {
|
|
1073
|
-
grade,
|
|
1074
|
-
score: violations.length === 0 && warnings.length === 0 && scopeIssues.length === 0 ? 100 : 0,
|
|
1075
|
-
verdict,
|
|
1076
|
-
summary: {
|
|
1077
|
-
totalFilesChanged,
|
|
1078
|
-
totalViolations: violations.length,
|
|
1079
|
-
totalWarnings: warnings.length,
|
|
1080
|
-
totalScopeIssues: scopeIssues.length,
|
|
1081
|
-
},
|
|
1082
|
-
violations,
|
|
1083
|
-
warnings,
|
|
1084
|
-
scopeIssues,
|
|
1085
|
-
blockingCount: blockingItems.length,
|
|
1086
|
-
advisoryCount: advisoryItems.length,
|
|
1087
|
-
blockingItems,
|
|
1088
|
-
advisoryItems,
|
|
1089
|
-
intentIssues: rawIntentIssues,
|
|
1090
|
-
intentDomains,
|
|
1091
|
-
intentSummary,
|
|
1092
|
-
flowIssues: rawFlowIssues,
|
|
1093
|
-
regressions: rawRegressions,
|
|
1094
|
-
expediteModeUsed,
|
|
1095
|
-
expediteCount: expediteModeUsed ? expediteItems.length : 0,
|
|
1096
|
-
expediteItems: expediteModeUsed ? expediteItems : [],
|
|
1097
|
-
expediteFollowUpChecklist: expediteModeUsed ? [...EXPEDITE_FOLLOW_UP_CHECKLIST] : [],
|
|
1098
|
-
...(expediteModeUsed ? { expediteNote: 'Expedite Mode used' } : {}),
|
|
1099
|
-
...(typeof driftScore === 'number' ? { driftScore } : {}),
|
|
1100
|
-
};
|
|
1101
|
-
// Preserve actionable metadata from rich verify payloads so downstream
|
|
1102
|
-
// consumers (Action, CI contracts, dashboards) keep structured context.
|
|
1103
|
-
const passthroughKeys = [
|
|
1104
|
-
'message',
|
|
1105
|
-
'mode',
|
|
1106
|
-
'ciMode',
|
|
1107
|
-
'policyOnly',
|
|
1108
|
-
'policyOnlySource',
|
|
1109
|
-
'policySources',
|
|
1110
|
-
'scopeGuardPassed',
|
|
1111
|
-
'policyLock',
|
|
1112
|
-
'policyCompilation',
|
|
1113
|
-
'policyExceptions',
|
|
1114
|
-
'policyGovernance',
|
|
1115
|
-
'changeContract',
|
|
1116
|
-
'runtimeGuard',
|
|
1117
|
-
'governanceDecision',
|
|
1118
|
-
'orgGovernance',
|
|
1119
|
-
'aiChangeLog',
|
|
1120
|
-
'verificationSource',
|
|
1121
|
-
'tier',
|
|
1122
|
-
'aiDebt',
|
|
1123
|
-
'blastRadius',
|
|
1124
|
-
'suspiciousChange',
|
|
1125
|
-
'policyDecision',
|
|
1126
|
-
'policyPack',
|
|
1127
|
-
'changeContractViolations',
|
|
1128
|
-
'governanceVerification',
|
|
1129
|
-
'governanceFindings',
|
|
1130
|
-
'structuralViolations',
|
|
1131
|
-
'structuralRulesApplied',
|
|
1132
|
-
'structuralSuppressedCount',
|
|
1133
|
-
];
|
|
1134
|
-
const canonicalMutable = canonical;
|
|
1135
|
-
for (const key of passthroughKeys) {
|
|
1136
|
-
const v = payload[key];
|
|
1137
|
-
if (Object.prototype.hasOwnProperty.call(payload, key) && v !== undefined && v !== null) {
|
|
1138
|
-
canonicalMutable[key] = v;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
// Backward-compatibility alias: older integrations and tests expect `rule`
|
|
1142
|
-
// while canonical contract uses `policy`.
|
|
1143
|
-
canonical.violations = canonical.violations.map((item) => ({
|
|
1144
|
-
...item,
|
|
1145
|
-
rule: item.policy,
|
|
1146
|
-
}));
|
|
1147
|
-
canonical.warnings = canonical.warnings.map((item) => ({
|
|
1148
|
-
...item,
|
|
1149
|
-
rule: item.policy,
|
|
1150
|
-
}));
|
|
1151
|
-
return canonical;
|
|
1152
|
-
}
|
|
1153
|
-
function emitCanonicalVerifyJson(payload, onEmit) {
|
|
1154
|
-
const canonical = toCanonicalVerifyOutput((0, canonical_pipeline_1.attachCanonicalGovernance)(payload));
|
|
1155
|
-
onEmit?.(canonical);
|
|
1156
|
-
// Use sync stdout write so immediate process.exit paths do not truncate JSON.
|
|
1157
|
-
const serialized = Buffer.from(`${JSON.stringify(canonical, null, 2)}\n`, 'utf-8');
|
|
1158
|
-
try {
|
|
1159
|
-
let offset = 0;
|
|
1160
|
-
while (offset < serialized.length) {
|
|
1161
|
-
try {
|
|
1162
|
-
const written = (0, fs_1.writeSync)(1, serialized, offset, serialized.length - offset);
|
|
1163
|
-
if (written <= 0)
|
|
1164
|
-
break;
|
|
1165
|
-
offset += written;
|
|
1166
|
-
}
|
|
1167
|
-
catch (error) {
|
|
1168
|
-
const code = error.code;
|
|
1169
|
-
if (code === 'EAGAIN' || code === 'EWOULDBLOCK') {
|
|
1170
|
-
continue;
|
|
1171
|
-
}
|
|
1172
|
-
throw error;
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
catch {
|
|
1177
|
-
process.stdout.write(serialized.toString('utf-8'));
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
function buildDeterministicLayerSummary(payload) {
|
|
1181
|
-
const verdict = asStringValue(payload.verdict) || 'UNKNOWN';
|
|
1182
|
-
const mode = asStringValue(payload.mode) || 'unknown';
|
|
1183
|
-
const policyOnly = payload.policyOnly === true;
|
|
1184
|
-
const scopeGuardPassed = asBooleanFlag(payload.scopeGuardPassed);
|
|
1185
|
-
const violations = asObjectArray(payload.violations);
|
|
1186
|
-
const policyViolations = violations.filter((entry) => {
|
|
1187
|
-
const rule = String(entry.rule || '').toLowerCase();
|
|
1188
|
-
return (!rule.includes('scope_guard')
|
|
1189
|
-
&& !rule.includes('change_contract')
|
|
1190
|
-
&& !rule.includes('runtime_guard')
|
|
1191
|
-
&& !rule.includes('deterministic_artifacts_required')
|
|
1192
|
-
&& !rule.includes('signed_artifacts_required'));
|
|
1193
|
-
});
|
|
1194
|
-
const policyBlocking = policyViolations.filter((entry) => String(entry.severity || '').toLowerCase() === 'block');
|
|
1195
|
-
const policyWarnings = policyViolations.filter((entry) => String(entry.severity || '').toLowerCase() === 'warn');
|
|
1196
|
-
const changeContract = asObjectRecord(payload.changeContract);
|
|
1197
|
-
const changeContractValid = asBooleanFlag(changeContract?.valid);
|
|
1198
|
-
const changeContractEnforced = changeContract?.enforced === true;
|
|
1199
|
-
const changeContractViolations = Array.isArray(changeContract?.violations)
|
|
1200
|
-
? (changeContract?.violations).length
|
|
1201
|
-
: 0;
|
|
1202
|
-
const explicitContractViolations = violations.filter((entry) => {
|
|
1203
|
-
const rule = String(entry.rule || '').toLowerCase();
|
|
1204
|
-
return rule.includes('scope_guard') || rule.includes('change_contract');
|
|
1205
|
-
}).length;
|
|
1206
|
-
const runtimeGuard = asObjectRecord(payload.runtimeGuard);
|
|
1207
|
-
const runtimeGuardRequired = runtimeGuard?.required === true;
|
|
1208
|
-
const runtimeGuardPass = asBooleanFlag(runtimeGuard?.pass);
|
|
1209
|
-
const runtimeGuardViolations = Array.isArray(runtimeGuard?.violations)
|
|
1210
|
-
? (runtimeGuard?.violations).length
|
|
1211
|
-
: violations.filter((entry) => String(entry.rule || '').toLowerCase().includes('runtime_guard')).length;
|
|
1212
|
-
const policyCompilation = asObjectRecord(payload.policyCompilation);
|
|
1213
|
-
const deterministicRuleCount = asNumberValue(policyCompilation?.deterministicRuleCount);
|
|
1214
|
-
const unmatchedStatements = asNumberValue(policyCompilation?.unmatchedStatements);
|
|
1215
|
-
let policyGateStatus = 'pass';
|
|
1216
|
-
if (policyBlocking.length > 0) {
|
|
1217
|
-
policyGateStatus = 'fail';
|
|
1218
|
-
}
|
|
1219
|
-
else if (policyWarnings.length > 0 || verdict === 'WARN') {
|
|
1220
|
-
policyGateStatus = 'warn';
|
|
1221
|
-
}
|
|
1222
|
-
let contractGateStatus = 'not_applicable';
|
|
1223
|
-
if (!policyOnly) {
|
|
1224
|
-
contractGateStatus = 'pass';
|
|
1225
|
-
if (changeContractEnforced
|
|
1226
|
-
&& (changeContractValid === false || changeContractViolations > 0 || explicitContractViolations > 0 || scopeGuardPassed === false)) {
|
|
1227
|
-
contractGateStatus = 'fail';
|
|
1228
|
-
}
|
|
1229
|
-
else if (!changeContractEnforced && (changeContractViolations > 0 || explicitContractViolations > 0)) {
|
|
1230
|
-
contractGateStatus = 'warn';
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
let runtimeGuardStatus = 'not_applicable';
|
|
1234
|
-
if (runtimeGuardRequired) {
|
|
1235
|
-
runtimeGuardStatus = runtimeGuardPass === false || runtimeGuardViolations > 0 ? 'fail' : 'pass';
|
|
1236
|
-
}
|
|
1237
|
-
else if (runtimeGuardViolations > 0) {
|
|
1238
|
-
runtimeGuardStatus = 'fail';
|
|
1239
|
-
}
|
|
1240
|
-
return {
|
|
1241
|
-
policyGate: {
|
|
1242
|
-
status: policyGateStatus,
|
|
1243
|
-
blockingViolations: policyBlocking.length,
|
|
1244
|
-
warningViolations: policyWarnings.length,
|
|
1245
|
-
deterministicRuleCount: deterministicRuleCount ?? null,
|
|
1246
|
-
unmatchedStatements: unmatchedStatements ?? null,
|
|
1247
|
-
},
|
|
1248
|
-
contractGate: {
|
|
1249
|
-
status: contractGateStatus,
|
|
1250
|
-
enforced: changeContractEnforced,
|
|
1251
|
-
valid: changeContractValid,
|
|
1252
|
-
violationCount: changeContractViolations + explicitContractViolations,
|
|
1253
|
-
mode,
|
|
1254
|
-
},
|
|
1255
|
-
runtimeGuardGate: {
|
|
1256
|
-
status: runtimeGuardStatus,
|
|
1257
|
-
required: runtimeGuardRequired,
|
|
1258
|
-
pass: runtimeGuardPass,
|
|
1259
|
-
violationCount: runtimeGuardViolations,
|
|
1260
|
-
},
|
|
1261
|
-
};
|
|
1262
|
-
}
|
|
1263
740
|
function toAiDebtSummary(evaluation) {
|
|
1264
741
|
return {
|
|
1265
742
|
mode: evaluation.mode,
|
|
@@ -1363,7 +840,7 @@ function resolveVerifyExpediteMode(projectRoot) {
|
|
|
1363
840
|
return true;
|
|
1364
841
|
}
|
|
1365
842
|
const branchName = (0, git_1.detectCurrentGitBranch)(projectRoot) || process.env.GITHUB_REF_NAME || '';
|
|
1366
|
-
return containsAnyToken(branchName, ['hotfix', 'urgent', 'prod-down', 'prod_down', 'prod down', 'incident', 'expedite']);
|
|
843
|
+
return (0, verify_output_1.containsAnyToken)(branchName, ['hotfix', 'urgent', 'prod-down', 'prod_down', 'prod down', 'incident', 'expedite']);
|
|
1367
844
|
}
|
|
1368
845
|
function isSignedAiLogsRequired(orgGovernanceSettings) {
|
|
1369
846
|
const explicitRequirement = isEnabledFlag(process.env.NEURCODE_GOVERNANCE_REQUIRE_SIGNED_LOGS) ||
|
|
@@ -1388,19 +865,6 @@ function toPolicyLockViolations(mismatches) {
|
|
|
1388
865
|
message: item.message,
|
|
1389
866
|
}));
|
|
1390
867
|
}
|
|
1391
|
-
function resolvePolicyDecisionFromViolations(violations) {
|
|
1392
|
-
let hasWarn = false;
|
|
1393
|
-
for (const violation of violations) {
|
|
1394
|
-
const severity = String(violation.severity || '').toLowerCase();
|
|
1395
|
-
if (severity === 'block') {
|
|
1396
|
-
return 'block';
|
|
1397
|
-
}
|
|
1398
|
-
if (severity === 'warn') {
|
|
1399
|
-
hasWarn = true;
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
return hasWarn ? 'warn' : 'allow';
|
|
1403
|
-
}
|
|
1404
868
|
function explainExceptionEligibilityReason(reason) {
|
|
1405
869
|
switch (reason) {
|
|
1406
870
|
case 'reason_required':
|
|
@@ -1537,12 +1001,15 @@ async function recordVerificationIfRequested(options, config, payload) {
|
|
|
1537
1001
|
* Returns the exit code to use
|
|
1538
1002
|
*/
|
|
1539
1003
|
async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRoot, config, client, source, ciModeEnabled, scopeTelemetry, projectId, orgGovernanceSettings, aiLogSigningKey, aiLogSigningKeyId, aiLogSigningKeys, aiLogSigner, expediteModeEnabled, compiledPolicyArtifact, compiledPolicyMetadata, changeContractSummary, onCanonicalEmit) {
|
|
1540
|
-
const emitPolicyOnlyJson = (payload) => {
|
|
1541
|
-
emitCanonicalVerifyJson({
|
|
1004
|
+
const emitPolicyOnlyJson = (payload, onEmit) => {
|
|
1005
|
+
(0, verify_output_1.emitCanonicalVerifyJson)({
|
|
1542
1006
|
...payload,
|
|
1543
1007
|
ciMode: payload.ciMode ?? ciModeEnabled,
|
|
1544
1008
|
expediteMode: expediteModeEnabled,
|
|
1545
|
-
},
|
|
1009
|
+
}, (canonical) => {
|
|
1010
|
+
onEmit?.(canonical);
|
|
1011
|
+
onCanonicalEmit?.(canonical);
|
|
1012
|
+
});
|
|
1546
1013
|
};
|
|
1547
1014
|
const policyOnlyVerificationSource = 'policy_only';
|
|
1548
1015
|
const recordPolicyOnlyVerification = async (payload) => recordVerificationIfRequested(options, config, {
|
|
@@ -1559,18 +1026,22 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
|
|
|
1559
1026
|
const diffFilesForPolicy = diffFiles.filter((f) => !ignoreFilter(f.path));
|
|
1560
1027
|
const expectedPolicyOnlyFiles = diffFilesForPolicy.map((file) => file.path);
|
|
1561
1028
|
const signedLogsRequired = isSignedAiLogsRequired(orgGovernanceSettings);
|
|
1029
|
+
const activeEngineeringContext = (0, active_engineering_context_1.loadActiveEngineeringContext)(projectRoot);
|
|
1562
1030
|
const governanceAnalysis = (0, governance_1.evaluateGovernance)({
|
|
1563
1031
|
projectRoot,
|
|
1564
1032
|
task: 'Policy-only verification',
|
|
1565
1033
|
expectedFiles: expectedPolicyOnlyFiles,
|
|
1566
1034
|
diffFiles: diffFilesForPolicy,
|
|
1567
|
-
contextCandidates:
|
|
1035
|
+
contextCandidates: activeEngineeringContext
|
|
1036
|
+
? activeEngineeringContext.contextPack.selectedFiles.map((item) => item.path)
|
|
1037
|
+
: expectedPolicyOnlyFiles,
|
|
1568
1038
|
orgGovernance: orgGovernanceSettings,
|
|
1569
1039
|
requireSignedAiLogs: signedLogsRequired,
|
|
1570
1040
|
signingKey: aiLogSigningKey,
|
|
1571
1041
|
signingKeyId: aiLogSigningKeyId,
|
|
1572
1042
|
signingKeys: aiLogSigningKeys,
|
|
1573
1043
|
signer: aiLogSigner,
|
|
1044
|
+
activeEngineeringContext,
|
|
1574
1045
|
});
|
|
1575
1046
|
const governancePayload = buildGovernancePayload(governanceAnalysis, orgGovernanceSettings, {
|
|
1576
1047
|
compiledPolicy: compiledPolicyMetadata,
|
|
@@ -1636,19 +1107,23 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
|
|
|
1636
1107
|
const message = governanceAnalysis.governanceDecision.summary
|
|
1637
1108
|
|| 'Governance decision matrix returned BLOCK.';
|
|
1638
1109
|
const reasonCodes = governanceAnalysis.governanceDecision.reasonCodes || [];
|
|
1110
|
+
const driftViolations = driftFindingsToVerificationViolations(governanceAnalysis.driftIntelligence)
|
|
1111
|
+
.filter((item) => !ignoreFilter(item.file));
|
|
1112
|
+
const governanceBlockViolations = [
|
|
1113
|
+
{
|
|
1114
|
+
file: '.neurcode/ai-change-log.json',
|
|
1115
|
+
rule: 'governance_decision_block',
|
|
1116
|
+
severity: 'block',
|
|
1117
|
+
message,
|
|
1118
|
+
},
|
|
1119
|
+
...driftViolations,
|
|
1120
|
+
];
|
|
1639
1121
|
if (options.json) {
|
|
1640
1122
|
emitPolicyOnlyJson({
|
|
1641
1123
|
grade: 'F',
|
|
1642
1124
|
score: 0,
|
|
1643
1125
|
verdict: 'FAIL',
|
|
1644
|
-
violations:
|
|
1645
|
-
{
|
|
1646
|
-
file: '.neurcode/ai-change-log.json',
|
|
1647
|
-
rule: 'governance_decision_block',
|
|
1648
|
-
severity: 'block',
|
|
1649
|
-
message,
|
|
1650
|
-
},
|
|
1651
|
-
],
|
|
1126
|
+
violations: governanceBlockViolations,
|
|
1652
1127
|
message,
|
|
1653
1128
|
scopeGuardPassed: false,
|
|
1654
1129
|
bloatCount: 0,
|
|
@@ -1671,14 +1146,7 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
|
|
|
1671
1146
|
}
|
|
1672
1147
|
await recordPolicyOnlyVerification({
|
|
1673
1148
|
grade: 'F',
|
|
1674
|
-
violations:
|
|
1675
|
-
{
|
|
1676
|
-
file: '.neurcode/ai-change-log.json',
|
|
1677
|
-
rule: 'governance_decision_block',
|
|
1678
|
-
severity: 'block',
|
|
1679
|
-
message,
|
|
1680
|
-
},
|
|
1681
|
-
],
|
|
1149
|
+
violations: governanceBlockViolations,
|
|
1682
1150
|
verifyResult: {
|
|
1683
1151
|
adherenceScore: 0,
|
|
1684
1152
|
verdict: 'FAIL',
|
|
@@ -1968,11 +1436,15 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
|
|
|
1968
1436
|
message: `Policy audit chain is invalid: ${auditIntegrityStatus.issues.join('; ') || 'unknown issue'}`,
|
|
1969
1437
|
});
|
|
1970
1438
|
}
|
|
1439
|
+
if (governanceAnalysis.driftIntelligence) {
|
|
1440
|
+
const driftViolations = driftFindingsToVerificationViolations(governanceAnalysis.driftIntelligence);
|
|
1441
|
+
policyViolations.push(...driftViolations.filter((item) => !ignoreFilter(item.file)));
|
|
1442
|
+
}
|
|
1971
1443
|
const policyOnlyStructural = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFilesForPolicy);
|
|
1972
1444
|
// Structural violations are passed to the canonical pipeline via payload.structuralViolations
|
|
1973
1445
|
// (see line ~2584). Do NOT merge them into policyViolations — that would create structural:*
|
|
1974
1446
|
// duplicates that contaminate the canonical finding graph.
|
|
1975
|
-
policyDecision = resolvePolicyDecisionFromViolations(policyViolations);
|
|
1447
|
+
policyDecision = (0, policy_decision_1.resolvePolicyDecisionFromViolations)(policyViolations);
|
|
1976
1448
|
const effectiveVerdict = policyDecision === 'block' ? 'FAIL' : policyDecision === 'warn' ? 'WARN' : 'PASS';
|
|
1977
1449
|
const grade = effectiveVerdict === 'PASS' ? 'A' : effectiveVerdict === 'WARN' ? 'C' : 'F';
|
|
1978
1450
|
const score = effectiveVerdict === 'PASS' ? 100 : effectiveVerdict === 'WARN' ? 50 : 0;
|
|
@@ -2073,15 +1545,46 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
|
|
|
2073
1545
|
}
|
|
2074
1546
|
: {}),
|
|
2075
1547
|
};
|
|
1548
|
+
const policyOnlyReplayCustody = (0, replay_custody_1.captureVerifyReplayCustody)({
|
|
1549
|
+
projectRoot,
|
|
1550
|
+
diffContext: `${options.base || 'HEAD'} vs working tree`,
|
|
1551
|
+
filesAnalyzed: diffFiles.length,
|
|
1552
|
+
planId: null,
|
|
1553
|
+
verificationSource: policyOnlyVerificationSource,
|
|
1554
|
+
policyLockFingerprint: (0, policy_packs_1.readPolicyLockFile)(projectRoot).lock?.effective.fingerprint || null,
|
|
1555
|
+
compiledPolicyFingerprint: compiledPolicyArtifact?.fingerprint || null,
|
|
1556
|
+
ruleIds: policyOnlyStructural.rulesApplied,
|
|
1557
|
+
blockingCount: policyViolations.filter((v) => v.severity === 'block').length
|
|
1558
|
+
+ policyOnlyStructural.violations.filter((v) => v.severity === 'BLOCKING').length,
|
|
1559
|
+
advisoryCount: policyViolations.filter((v) => v.severity !== 'block').length
|
|
1560
|
+
+ policyOnlyStructural.violations.filter((v) => v.severity !== 'BLOCKING').length,
|
|
1561
|
+
suppressedCount: policyOnlyStructural.suppressedCount,
|
|
1562
|
+
structuralBlockingCount: policyOnlyStructural.violations.filter((v) => v.severity === 'BLOCKING').length,
|
|
1563
|
+
structuralAdvisoryCount: policyOnlyStructural.violations.filter((v) => v.severity !== 'BLOCKING').length,
|
|
1564
|
+
deterministicSignals: policyOnlyStructural.violations.filter((v) => v.determinism === 'deterministic-structural').length,
|
|
1565
|
+
heuristicSignals: policyOnlyStructural.violations.filter((v) => v.determinism === 'heuristic-advisory').length,
|
|
1566
|
+
overallTrustScore: policyOnlyStructural.violations.length > 0
|
|
1567
|
+
? Math.round((policyOnlyStructural.violations.filter((v) => v.determinism === 'deterministic-structural').length / policyOnlyStructural.violations.length) * 100)
|
|
1568
|
+
: 100,
|
|
1569
|
+
verdict: effectiveVerdict,
|
|
1570
|
+
governanceDecision: governanceAnalysis.governanceDecision.summary || 'policy-only',
|
|
1571
|
+
actor: ciModeEnabled ? 'ci-runner' : 'local-user',
|
|
1572
|
+
source: ciModeEnabled ? 'ci' : 'cli',
|
|
1573
|
+
replayChecksum: policyOnlyReplayChecksum,
|
|
1574
|
+
});
|
|
2076
1575
|
if (options.json) {
|
|
2077
|
-
emitPolicyOnlyJson(policyOnlyPayload)
|
|
1576
|
+
emitPolicyOnlyJson(policyOnlyPayload, (canonical) => {
|
|
1577
|
+
(0, replay_custody_1.applyReplayCustodyToCanonicalOutput)(canonical, policyOnlyReplayCustody);
|
|
1578
|
+
});
|
|
2078
1579
|
}
|
|
2079
1580
|
else {
|
|
2080
|
-
|
|
1581
|
+
const policyOnlyCanonical = (0, verify_output_1.toCanonicalVerifyOutput)((0, canonical_pipeline_1.attachCanonicalGovernance)({
|
|
2081
1582
|
...policyOnlyPayload,
|
|
2082
1583
|
ciMode: ciModeEnabled,
|
|
2083
1584
|
expediteMode: expediteModeEnabled,
|
|
2084
1585
|
}));
|
|
1586
|
+
(0, replay_custody_1.applyReplayCustodyToCanonicalOutput)(policyOnlyCanonical, policyOnlyReplayCustody);
|
|
1587
|
+
onCanonicalEmit?.(policyOnlyCanonical);
|
|
2085
1588
|
if (effectiveVerdict === 'PASS') {
|
|
2086
1589
|
console.log(chalk.green('✅ Policy check passed'));
|
|
2087
1590
|
}
|
|
@@ -2101,7 +1604,7 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
|
|
|
2101
1604
|
if (governance.audit.requireIntegrity && !auditIntegrityStatus.valid) {
|
|
2102
1605
|
console.log(chalk.red(' Policy audit integrity check failed'));
|
|
2103
1606
|
}
|
|
2104
|
-
displayGovernanceInsights(governanceAnalysis, { explain: options.explain });
|
|
1607
|
+
(0, verify_render_1.displayGovernanceInsights)(chalk, governanceAnalysis, { explain: options.explain });
|
|
2105
1608
|
console.log(chalk.dim(`\n${message}`));
|
|
2106
1609
|
logCiPolicyOnlyOutcomeExplainability({
|
|
2107
1610
|
ciModeEnabled,
|
|
@@ -2148,6 +1651,8 @@ async function verifyCommand(options) {
|
|
|
2148
1651
|
let lastCanonicalOutput = null;
|
|
2149
1652
|
let lastEvidenceFallbackOutput = null;
|
|
2150
1653
|
let evidenceFinalizeAttempted = false;
|
|
1654
|
+
const custodySource = ciModeEnabled ? 'ci' : 'cli';
|
|
1655
|
+
const custodyActor = ciModeEnabled ? 'ci-runner' : 'local-user';
|
|
2151
1656
|
// ── Phase 1 Runtime Stability: create context early so all subsystems share it ──
|
|
2152
1657
|
// Structural governance is NEVER gated by this context — it always runs.
|
|
2153
1658
|
const runtimeCtx = (0, verify_runtime_stability_1.createVerifyRuntimeContext)(ciModeEnabled);
|
|
@@ -2162,8 +1667,16 @@ async function verifyCommand(options) {
|
|
|
2162
1667
|
options.asyncMode = false;
|
|
2163
1668
|
}
|
|
2164
1669
|
const captureEvidencePayload = (payload) => {
|
|
2165
|
-
|
|
2166
|
-
|
|
1670
|
+
const enrichedPayload = (0, canonical_pipeline_1.attachCanonicalGovernance)(payload);
|
|
1671
|
+
lastEvidenceFallbackOutput = enrichedPayload;
|
|
1672
|
+
lastCanonicalOutput = (0, verify_output_1.toCanonicalVerifyOutput)(enrichedPayload);
|
|
1673
|
+
};
|
|
1674
|
+
const applyCapturedReplayCustody = (canonical, custody) => {
|
|
1675
|
+
if (!canonical || !custody) {
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
(0, replay_custody_1.applyReplayCustodyToCanonicalOutput)(canonical, custody);
|
|
1679
|
+
lastProvenanceRunId = custody.provenanceRecord?.runId ?? lastProvenanceRunId;
|
|
2167
1680
|
};
|
|
2168
1681
|
const finalizeEvidence = (exitCode) => {
|
|
2169
1682
|
if (!evidenceEnabled || evidenceFinalizeAttempted) {
|
|
@@ -2225,7 +1738,7 @@ async function verifyCommand(options) {
|
|
|
2225
1738
|
let structuralViolations = [];
|
|
2226
1739
|
let structuralRulesApplied = [];
|
|
2227
1740
|
let structuralSuppressedCount = 0;
|
|
2228
|
-
const emitVerifyJson = (payload) => {
|
|
1741
|
+
const emitVerifyJson = (payload, onEmit) => {
|
|
2229
1742
|
// Check memory pressure immediately before emission (may have changed during long verify)
|
|
2230
1743
|
(0, verify_runtime_stability_1.applyMemoryPressureDegradation)(runtimeCtx);
|
|
2231
1744
|
const runtimeStabilityReport = (0, verify_runtime_stability_1.buildVerifyRuntimeReport)(runtimeCtx);
|
|
@@ -2248,8 +1761,9 @@ async function verifyCommand(options) {
|
|
|
2248
1761
|
runtimeStabilityReport,
|
|
2249
1762
|
};
|
|
2250
1763
|
lastEvidenceFallbackOutput = enrichedPayload;
|
|
2251
|
-
emitCanonicalVerifyJson(enrichedPayload, (canonical) => {
|
|
1764
|
+
(0, verify_output_1.emitCanonicalVerifyJson)(enrichedPayload, (canonical) => {
|
|
2252
1765
|
lastCanonicalOutput = canonical;
|
|
1766
|
+
onEmit?.(lastCanonicalOutput);
|
|
2253
1767
|
});
|
|
2254
1768
|
};
|
|
2255
1769
|
if (!isGitRepository(projectRoot)) {
|
|
@@ -2854,34 +2368,70 @@ async function verifyCommand(options) {
|
|
|
2854
2368
|
console.log(chalk.cyan('\n🔍 Local-only mode: deterministic structural verification (no API required)...'));
|
|
2855
2369
|
}
|
|
2856
2370
|
const localStructural = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFiles);
|
|
2371
|
+
const localStructuralFindings = localStructural.violations.map(canonical_pipeline_1.findingFromStructural);
|
|
2372
|
+
const localReplayChecksum = (0, canonical_invariants_1.computeCanonicalFindingChecksum)(localStructuralFindings);
|
|
2857
2373
|
const blockingViolations = localStructural.violations.filter((v) => v.severity === 'BLOCKING');
|
|
2374
|
+
const advisoryViolations = localStructural.violations.filter((v) => v.severity !== 'BLOCKING');
|
|
2858
2375
|
const localVerdict = blockingViolations.length > 0 ? 'FAIL' : 'PASS';
|
|
2859
2376
|
const localGrade = blockingViolations.length > 0 ? 'F' : 'B';
|
|
2860
2377
|
const localScore = blockingViolations.length > 0 ? 0 : 70;
|
|
2378
|
+
const localPayload = {
|
|
2379
|
+
grade: localGrade,
|
|
2380
|
+
score: localScore,
|
|
2381
|
+
verdict: localVerdict,
|
|
2382
|
+
violations: localStructural.violations.map((v) => ({
|
|
2383
|
+
file: v.filePath,
|
|
2384
|
+
rule: v.ruleId,
|
|
2385
|
+
severity: v.severity === 'BLOCKING' ? 'block' : 'warn',
|
|
2386
|
+
message: `${v.ruleName}: ${v.evidence.slice(0, 120)}`,
|
|
2387
|
+
})),
|
|
2388
|
+
adherenceScore: localScore,
|
|
2389
|
+
bloatCount: 0,
|
|
2390
|
+
bloatFiles: [],
|
|
2391
|
+
plannedFilesModified: 0,
|
|
2392
|
+
totalPlannedFiles: 0,
|
|
2393
|
+
message: `Local-only structural verification: ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking.`,
|
|
2394
|
+
scopeGuardPassed: true,
|
|
2395
|
+
mode: 'local_only_structural',
|
|
2396
|
+
policyOnly: true,
|
|
2397
|
+
replayChecksum: localReplayChecksum,
|
|
2398
|
+
replayMode: 'local-structural',
|
|
2399
|
+
structuralViolations: localStructural.violations,
|
|
2400
|
+
structuralBlockingCount: blockingViolations.length,
|
|
2401
|
+
structuralRulesApplied: localStructural.rulesApplied,
|
|
2402
|
+
changeContract: changeContractSummary,
|
|
2403
|
+
};
|
|
2404
|
+
captureEvidencePayload((0, canonical_pipeline_1.attachCanonicalGovernance)(localPayload));
|
|
2405
|
+
const localReplayCustody = (0, replay_custody_1.captureVerifyReplayCustody)({
|
|
2406
|
+
projectRoot,
|
|
2407
|
+
diffContext: `${options.base || 'HEAD'} vs working tree`,
|
|
2408
|
+
filesAnalyzed: diffFiles.length,
|
|
2409
|
+
planId: null,
|
|
2410
|
+
verificationSource: 'local_only_structural',
|
|
2411
|
+
policyLockFingerprint: null,
|
|
2412
|
+
compiledPolicyFingerprint: null,
|
|
2413
|
+
ruleIds: localStructural.rulesApplied,
|
|
2414
|
+
blockingCount: blockingViolations.length,
|
|
2415
|
+
advisoryCount: advisoryViolations.length,
|
|
2416
|
+
suppressedCount: localStructural.suppressedCount,
|
|
2417
|
+
structuralBlockingCount: blockingViolations.length,
|
|
2418
|
+
structuralAdvisoryCount: advisoryViolations.length,
|
|
2419
|
+
deterministicSignals: localStructural.violations.filter((v) => v.determinism === 'deterministic-structural').length,
|
|
2420
|
+
heuristicSignals: localStructural.violations.filter((v) => v.determinism === 'heuristic-advisory').length,
|
|
2421
|
+
overallTrustScore: localStructural.violations.length > 0
|
|
2422
|
+
? Math.round((localStructural.violations.filter((v) => v.determinism === 'deterministic-structural').length / localStructural.violations.length) * 100)
|
|
2423
|
+
: 100,
|
|
2424
|
+
verdict: localVerdict,
|
|
2425
|
+
governanceDecision: 'local deterministic structural verification',
|
|
2426
|
+
actor: custodyActor,
|
|
2427
|
+
source: custodySource,
|
|
2428
|
+
replayChecksum: localReplayChecksum,
|
|
2429
|
+
});
|
|
2430
|
+
applyCapturedReplayCustody(lastCanonicalOutput, localReplayCustody);
|
|
2861
2431
|
if (options.json) {
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
verdict: localVerdict,
|
|
2866
|
-
violations: localStructural.violations.map((v) => ({
|
|
2867
|
-
file: v.filePath,
|
|
2868
|
-
rule: v.ruleId,
|
|
2869
|
-
severity: v.severity === 'BLOCKING' ? 'block' : 'warn',
|
|
2870
|
-
message: `${v.ruleName}: ${v.evidence.slice(0, 120)}`,
|
|
2871
|
-
})),
|
|
2872
|
-
adherenceScore: localScore,
|
|
2873
|
-
bloatCount: 0,
|
|
2874
|
-
bloatFiles: [],
|
|
2875
|
-
plannedFilesModified: 0,
|
|
2876
|
-
totalPlannedFiles: 0,
|
|
2877
|
-
message: `Local-only structural verification: ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking.`,
|
|
2878
|
-
scopeGuardPassed: true,
|
|
2879
|
-
mode: 'local_only_structural',
|
|
2880
|
-
policyOnly: true,
|
|
2881
|
-
structuralViolations: localStructural.violations,
|
|
2882
|
-
structuralBlockingCount: blockingViolations.length,
|
|
2883
|
-
structuralRulesApplied: localStructural.rulesApplied,
|
|
2884
|
-
changeContract: changeContractSummary,
|
|
2432
|
+
(0, verify_output_1.emitCanonicalVerifyJson)(localPayload, (canonical) => {
|
|
2433
|
+
applyCapturedReplayCustody(canonical, localReplayCustody);
|
|
2434
|
+
lastCanonicalOutput = canonical;
|
|
2885
2435
|
});
|
|
2886
2436
|
}
|
|
2887
2437
|
else {
|
|
@@ -3278,6 +2828,10 @@ async function verifyCommand(options) {
|
|
|
3278
2828
|
missingExpectedFiles: 0,
|
|
3279
2829
|
blockedFilesTouched: 0,
|
|
3280
2830
|
actionMismatches: 0,
|
|
2831
|
+
serviceBoundaryBreaches: 0,
|
|
2832
|
+
infraBoundaryBreaches: 0,
|
|
2833
|
+
dependencyBoundaryBreaches: 0,
|
|
2834
|
+
sensitiveBoundaryBreaches: 0,
|
|
3281
2835
|
expectedSymbols: advisoryContract.expectedSymbols?.length || 0,
|
|
3282
2836
|
changedSymbols: 0,
|
|
3283
2837
|
missingExpectedSymbols: 0,
|
|
@@ -3387,8 +2941,8 @@ async function verifyCommand(options) {
|
|
|
3387
2941
|
});
|
|
3388
2942
|
}
|
|
3389
2943
|
else {
|
|
3390
|
-
printFirstRunAdvisoryMessage(options.demo === true);
|
|
3391
|
-
printAdvisorySignals(advisorySignals, options.demo === true);
|
|
2944
|
+
(0, verify_guidance_1.printFirstRunAdvisoryMessage)(chalk, options.demo === true);
|
|
2945
|
+
(0, verify_guidance_1.printAdvisorySignals)(chalk, advisorySignals, options.demo === true);
|
|
3392
2946
|
if (autoContractPath) {
|
|
3393
2947
|
console.log(chalk.green(`✅ Auto-generated minimal advisory contract: ${autoContractPath}`));
|
|
3394
2948
|
}
|
|
@@ -3426,6 +2980,7 @@ async function verifyCommand(options) {
|
|
|
3426
2980
|
let planFiles = [];
|
|
3427
2981
|
let planDependencies = [];
|
|
3428
2982
|
let remotePlanSessionId = null;
|
|
2983
|
+
const activeEngineeringContext = (0, active_engineering_context_1.loadActiveEngineeringContext)(projectRoot);
|
|
3429
2984
|
if (useLocalPlanSync) {
|
|
3430
2985
|
const localIntent = (localPlanSync.intent || '').trim();
|
|
3431
2986
|
const localConstraintText = localPlanSync.constraints.length > 0
|
|
@@ -3460,6 +3015,27 @@ async function verifyCommand(options) {
|
|
|
3460
3015
|
}
|
|
3461
3016
|
planFilesForVerification = [...new Set([...planFiles, ...localPlanExpectedFiles])];
|
|
3462
3017
|
intentConstraintsForVerification = originalIntent || undefined;
|
|
3018
|
+
if (activeEngineeringContext) {
|
|
3019
|
+
if (activeEngineeringContext.intentPack.approvedScope.files.length > 0) {
|
|
3020
|
+
planFilesForVerification = [...activeEngineeringContext.intentPack.approvedScope.files];
|
|
3021
|
+
}
|
|
3022
|
+
if (activeEngineeringContext.intentPack.intent.normalized) {
|
|
3023
|
+
intentConstraintsForVerification = activeEngineeringContext.intentPack.intent.normalized;
|
|
3024
|
+
governanceTask = activeEngineeringContext.intentPack.intent.normalized;
|
|
3025
|
+
}
|
|
3026
|
+
planDependencies = [...new Set([
|
|
3027
|
+
...planDependencies,
|
|
3028
|
+
...activeEngineeringContext.intentPack.expectedDependencies,
|
|
3029
|
+
])];
|
|
3030
|
+
if (!options.json) {
|
|
3031
|
+
console.log(chalk.dim(` Intent runtime loaded: ${activeEngineeringContext.sessionRuntime.sessionId} ` +
|
|
3032
|
+
`(${planFilesForVerification.length} approved file(s), ` +
|
|
3033
|
+
`${activeEngineeringContext.contextPack.selectedFiles.length} context file(s))`));
|
|
3034
|
+
activeEngineeringContext.warnings.slice(0, 3).forEach((warning) => {
|
|
3035
|
+
console.log(chalk.yellow(` Context warning: ${warning}`));
|
|
3036
|
+
});
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3463
3039
|
// ── Intent-Aware Engine ─────────────────────────────────────────────
|
|
3464
3040
|
// Run once we have both diffFiles and the resolved intent text.
|
|
3465
3041
|
// Stored in outer scope so all emitCanonicalVerifyJson call sites can
|
|
@@ -3513,13 +3089,16 @@ async function verifyCommand(options) {
|
|
|
3513
3089
|
expectedFiles: planFilesForVerification,
|
|
3514
3090
|
expectedDependencies: planDependencies,
|
|
3515
3091
|
diffFiles,
|
|
3516
|
-
contextCandidates:
|
|
3092
|
+
contextCandidates: activeEngineeringContext
|
|
3093
|
+
? activeEngineeringContext.contextPack.selectedFiles.map((item) => item.path)
|
|
3094
|
+
: planFilesForVerification,
|
|
3517
3095
|
orgGovernance: orgGovernanceSettings,
|
|
3518
3096
|
requireSignedAiLogs: signedLogsRequired,
|
|
3519
3097
|
signingKey: aiLogSigningKey,
|
|
3520
3098
|
signingKeyId: aiLogSigningKeyId,
|
|
3521
3099
|
signingKeys: aiLogSigningKeys,
|
|
3522
3100
|
signer: aiLogSigner,
|
|
3101
|
+
activeEngineeringContext,
|
|
3523
3102
|
});
|
|
3524
3103
|
// Get sessionId from state file (.neurcode/state.json) first, then fallback to config
|
|
3525
3104
|
// Fallback to sessionId from plan if not in state/config
|
|
@@ -3561,13 +3140,17 @@ async function verifyCommand(options) {
|
|
|
3561
3140
|
}
|
|
3562
3141
|
}
|
|
3563
3142
|
// Step C: The Intersection Logic
|
|
3564
|
-
const approvedSet = new Set([
|
|
3143
|
+
const approvedSet = new Set([
|
|
3144
|
+
...planFilesForVerification,
|
|
3145
|
+
...allowedFiles,
|
|
3146
|
+
...(governanceResult.engineeringContext?.approvedScope?.files || []),
|
|
3147
|
+
]);
|
|
3565
3148
|
const violations = modifiedFiles.filter(f => !approvedSet.has(f));
|
|
3566
3149
|
const filteredViolations = violations.filter((p) => !shouldIgnore(p));
|
|
3567
3150
|
// Step D: The Block (only report scope violations for non-ignored files)
|
|
3568
3151
|
if (filteredViolations.length > 0) {
|
|
3569
3152
|
const criticalScopeViolations = expediteModeEnabled
|
|
3570
|
-
? filteredViolations.filter((file) => isCriticalScopeBreach(file, 'File modified outside the plan'))
|
|
3153
|
+
? filteredViolations.filter((file) => (0, verify_output_1.isCriticalScopeBreach)(file, 'File modified outside the plan'))
|
|
3571
3154
|
: filteredViolations;
|
|
3572
3155
|
const expediteScopeViolations = expediteModeEnabled
|
|
3573
3156
|
? filteredViolations.filter((file) => !criticalScopeViolations.includes(file))
|
|
@@ -3686,7 +3269,7 @@ async function verifyCommand(options) {
|
|
|
3686
3269
|
}
|
|
3687
3270
|
}
|
|
3688
3271
|
if (governanceResult) {
|
|
3689
|
-
displayGovernanceInsights(governanceResult, { explain: options.explain });
|
|
3272
|
+
(0, verify_render_1.displayGovernanceInsights)(chalk, governanceResult, { explain: options.explain });
|
|
3690
3273
|
}
|
|
3691
3274
|
// ── Intent Status in scope-violation path ──────────────────────
|
|
3692
3275
|
if (intentEngineSummary) {
|
|
@@ -3755,7 +3338,7 @@ async function verifyCommand(options) {
|
|
|
3755
3338
|
console.log(chalk.yellow(` • ${file}`));
|
|
3756
3339
|
});
|
|
3757
3340
|
console.log(chalk.dim(' Follow-up checklist:'));
|
|
3758
|
-
EXPEDITE_FOLLOW_UP_CHECKLIST.forEach((item) => {
|
|
3341
|
+
verify_output_1.EXPEDITE_FOLLOW_UP_CHECKLIST.forEach((item) => {
|
|
3759
3342
|
console.log(chalk.dim(` - ${item}`));
|
|
3760
3343
|
});
|
|
3761
3344
|
console.log(chalk.dim(' Note: Expedite Mode used\n'));
|
|
@@ -4056,10 +3639,14 @@ async function verifyCommand(options) {
|
|
|
4056
3639
|
message: `Policy audit chain is invalid: ${auditIntegrityStatus.issues.join('; ') || 'unknown issue'}`,
|
|
4057
3640
|
});
|
|
4058
3641
|
}
|
|
3642
|
+
if (governanceResult?.driftIntelligence) {
|
|
3643
|
+
const driftViolations = driftFindingsToVerificationViolations(governanceResult.driftIntelligence);
|
|
3644
|
+
policyViolations.push(...driftViolations.filter((item) => !shouldIgnore(item.file)));
|
|
3645
|
+
}
|
|
4059
3646
|
// Structural violations are passed to the canonical pipeline via payload.structuralViolations
|
|
4060
3647
|
// (see line ~5281). Do NOT merge them into policyViolations — that would create structural:*
|
|
4061
3648
|
// duplicates that contaminate the canonical finding graph.
|
|
4062
|
-
policyDecision = resolvePolicyDecisionFromViolations(policyViolations);
|
|
3649
|
+
policyDecision = (0, policy_decision_1.resolvePolicyDecisionFromViolations)(policyViolations);
|
|
4063
3650
|
const policyExceptionsSummary = {
|
|
4064
3651
|
sourceMode: policyExceptionResolution.mode,
|
|
4065
3652
|
sourceWarning: policyExceptionResolution.warning,
|
|
@@ -4201,7 +3788,7 @@ async function verifyCommand(options) {
|
|
|
4201
3788
|
message: violation,
|
|
4202
3789
|
}));
|
|
4203
3790
|
policyViolations.push(...intentProofPolicyViolations);
|
|
4204
|
-
policyDecision = resolvePolicyDecisionFromViolations(policyViolations);
|
|
3791
|
+
policyDecision = (0, policy_decision_1.resolvePolicyDecisionFromViolations)(policyViolations);
|
|
4205
3792
|
}
|
|
4206
3793
|
if (!options.json) {
|
|
4207
3794
|
if (intentProofSummary.pass) {
|
|
@@ -4280,7 +3867,7 @@ async function verifyCommand(options) {
|
|
|
4280
3867
|
});
|
|
4281
3868
|
}
|
|
4282
3869
|
else {
|
|
4283
|
-
displayChangeContractDrift(changeContractSummary, { advisory: false });
|
|
3870
|
+
(0, verify_render_1.displayChangeContractDrift)(chalk, changeContractSummary, { advisory: false });
|
|
4284
3871
|
}
|
|
4285
3872
|
await recordVerificationIfRequested(options, config, {
|
|
4286
3873
|
grade: 'F',
|
|
@@ -4304,7 +3891,7 @@ async function verifyCommand(options) {
|
|
|
4304
3891
|
exitWithEvidence(2);
|
|
4305
3892
|
}
|
|
4306
3893
|
else if (!changeContractEvaluation.valid && !options.json) {
|
|
4307
|
-
displayChangeContractDrift(changeContractSummary, { advisory: true });
|
|
3894
|
+
(0, verify_render_1.displayChangeContractDrift)(chalk, changeContractSummary, { advisory: true });
|
|
4308
3895
|
}
|
|
4309
3896
|
}
|
|
4310
3897
|
// Call verify API (or deterministic local evaluation for Plan Sync scope mode)
|
|
@@ -4538,9 +4125,50 @@ async function verifyCommand(options) {
|
|
|
4538
4125
|
: {}),
|
|
4539
4126
|
};
|
|
4540
4127
|
captureEvidencePayload(verifyEvidencePayload);
|
|
4128
|
+
const canonicalReplayChecksum = (() => {
|
|
4129
|
+
const direct = lastCanonicalOutput?.['replayChecksum'];
|
|
4130
|
+
if (typeof direct === 'string') {
|
|
4131
|
+
return direct;
|
|
4132
|
+
}
|
|
4133
|
+
const envelope = lastCanonicalOutput?.['governanceVerification'] ?? undefined;
|
|
4134
|
+
return typeof envelope?.replayChecksum === 'string' ? envelope.replayChecksum : null;
|
|
4135
|
+
})();
|
|
4136
|
+
const structuralBlocking = structuralViolations.filter(v => v.severity === 'BLOCKING').length;
|
|
4137
|
+
const structuralAdvisory = structuralViolations.filter(v => v.severity === 'ADVISORY').length;
|
|
4138
|
+
const deterministicSigs = structuralViolations.filter(v => v.determinism === 'deterministic-structural').length;
|
|
4139
|
+
const heuristicSigs = structuralViolations.filter(v => v.determinism === 'heuristic-advisory').length;
|
|
4140
|
+
const trustScore = structuralViolations.length > 0
|
|
4141
|
+
? Math.round((deterministicSigs / structuralViolations.length) * 100)
|
|
4142
|
+
: 100;
|
|
4143
|
+
const mainReplayCustody = (0, replay_custody_1.captureVerifyReplayCustody)({
|
|
4144
|
+
projectRoot,
|
|
4145
|
+
diffContext: `${options.base || 'HEAD'} vs working tree`,
|
|
4146
|
+
filesAnalyzed: diffFiles.length,
|
|
4147
|
+
planId: finalPlanId || null,
|
|
4148
|
+
verificationSource: verifySource,
|
|
4149
|
+
policyLockFingerprint: (0, policy_packs_1.readPolicyLockFile)(projectRoot).lock?.effective.fingerprint || null,
|
|
4150
|
+
compiledPolicyFingerprint: effectiveCompiledPolicy?.fingerprint || null,
|
|
4151
|
+
ruleIds: structuralRulesApplied,
|
|
4152
|
+
blockingCount: policyViolations.filter((v) => v.severity === 'block').length + structuralBlocking,
|
|
4153
|
+
advisoryCount: policyViolations.filter((v) => v.severity !== 'block').length + structuralAdvisory,
|
|
4154
|
+
suppressedCount: structuralSuppressedCount,
|
|
4155
|
+
structuralBlockingCount: structuralBlocking,
|
|
4156
|
+
structuralAdvisoryCount: structuralAdvisory,
|
|
4157
|
+
deterministicSignals: deterministicSigs,
|
|
4158
|
+
heuristicSignals: heuristicSigs,
|
|
4159
|
+
overallTrustScore: trustScore,
|
|
4160
|
+
verdict: effectiveVerdict,
|
|
4161
|
+
governanceDecision: governanceResult?.governanceDecision?.summary || 'automatic',
|
|
4162
|
+
actor: custodyActor,
|
|
4163
|
+
source: custodySource,
|
|
4164
|
+
replayChecksum: canonicalReplayChecksum,
|
|
4165
|
+
});
|
|
4166
|
+
applyCapturedReplayCustody(lastCanonicalOutput, mainReplayCustody);
|
|
4541
4167
|
// If JSON output requested, output JSON and exit
|
|
4542
4168
|
if (options.json) {
|
|
4543
|
-
emitVerifyJson(verifyEvidencePayload)
|
|
4169
|
+
emitVerifyJson(verifyEvidencePayload, (canonical) => {
|
|
4170
|
+
applyCapturedReplayCustody(canonical, mainReplayCustody);
|
|
4171
|
+
});
|
|
4544
4172
|
await recordVerificationIfRequested(options, config, {
|
|
4545
4173
|
grade,
|
|
4546
4174
|
violations: violations,
|
|
@@ -4574,7 +4202,7 @@ async function verifyCommand(options) {
|
|
|
4574
4202
|
// Display results (only if not in json mode; exclude ignored paths from bloat)
|
|
4575
4203
|
if (!options.json) {
|
|
4576
4204
|
const displayBloatFiles = (verifyResult.bloatFiles || []).filter((f) => !shouldIgnore(f));
|
|
4577
|
-
displayVerifyResults({
|
|
4205
|
+
(0, verify_render_1.displayVerifyResults)(chalk, {
|
|
4578
4206
|
...verifyResult,
|
|
4579
4207
|
verdict: effectiveVerdict,
|
|
4580
4208
|
message: effectiveMessage,
|
|
@@ -4582,7 +4210,7 @@ async function verifyCommand(options) {
|
|
|
4582
4210
|
bloatCount: displayBloatFiles.length,
|
|
4583
4211
|
}, policyViolations, expediteModeEnabled, intentEngineIssues, intentEngineSummary, intentEngineFlowIssues, intentEngineRegressions, structuralViolations);
|
|
4584
4212
|
if (governanceResult) {
|
|
4585
|
-
displayGovernanceInsights(governanceResult, { explain: options.explain });
|
|
4213
|
+
(0, verify_render_1.displayGovernanceInsights)(chalk, governanceResult, { explain: options.explain });
|
|
4586
4214
|
}
|
|
4587
4215
|
if (aiDebtSummary.mode !== 'off') {
|
|
4588
4216
|
const header = aiDebtSummary.mode === 'enforce'
|
|
@@ -4656,34 +4284,7 @@ async function verifyCommand(options) {
|
|
|
4656
4284
|
// ── Governance Provenance Chain + Pilot Metrics ───────────────────────
|
|
4657
4285
|
// Best-effort: never throws, never changes the verification outcome.
|
|
4658
4286
|
try {
|
|
4659
|
-
|
|
4660
|
-
const structuralAdvisory = structuralViolations.filter(v => v.severity === 'ADVISORY').length;
|
|
4661
|
-
const deterministicSigs = structuralViolations.filter(v => v.determinism === 'deterministic-structural').length;
|
|
4662
|
-
const heuristicSigs = structuralViolations.filter(v => v.determinism === 'heuristic-advisory').length;
|
|
4663
|
-
const trustScore = structuralViolations.length > 0
|
|
4664
|
-
? Math.round((deterministicSigs / structuralViolations.length) * 100)
|
|
4665
|
-
: 100;
|
|
4666
|
-
const prov = (0, governance_provenance_1.buildProvenanceRecord)({
|
|
4667
|
-
repoRoot: projectRoot,
|
|
4668
|
-
filesAnalyzed: diffFiles.length,
|
|
4669
|
-
diffContext: `${options.base || 'HEAD'} vs working tree`,
|
|
4670
|
-
planId: finalPlanId || null,
|
|
4671
|
-
intentHash: null,
|
|
4672
|
-
policyHash: null,
|
|
4673
|
-
ruleIds: structuralRulesApplied,
|
|
4674
|
-
blockingCount: policyViolations.filter((v) => v.severity === 'block').length + structuralBlocking,
|
|
4675
|
-
advisoryCount: policyViolations.filter((v) => v.severity !== 'block').length + structuralAdvisory,
|
|
4676
|
-
suppressedCount: structuralSuppressedCount,
|
|
4677
|
-
structuralBlockingCount: structuralBlocking,
|
|
4678
|
-
structuralAdvisoryCount: structuralAdvisory,
|
|
4679
|
-
deterministicSignals: deterministicSigs,
|
|
4680
|
-
heuristicSignals: heuristicSigs,
|
|
4681
|
-
overallTrustScore: trustScore,
|
|
4682
|
-
verdict: effectiveVerdict,
|
|
4683
|
-
governanceDecision: governanceResult?.governanceDecision?.summary || 'automatic',
|
|
4684
|
-
});
|
|
4685
|
-
(0, governance_provenance_1.saveProvenanceRecord)(projectRoot, prov);
|
|
4686
|
-
lastProvenanceRunId = prov.runId;
|
|
4287
|
+
lastProvenanceRunId = mainReplayCustody.provenanceRecord?.runId ?? lastProvenanceRunId;
|
|
4687
4288
|
// Tally per-rule counts for pilot metrics
|
|
4688
4289
|
const ruleCounts = {};
|
|
4689
4290
|
for (const v of structuralViolations) {
|
|
@@ -4694,8 +4295,8 @@ async function verifyCommand(options) {
|
|
|
4694
4295
|
verifyCount: 1,
|
|
4695
4296
|
passCount: effectiveVerdict === 'PASS' ? 1 : 0,
|
|
4696
4297
|
failCount: effectiveVerdict === 'FAIL' ? 1 : 0,
|
|
4697
|
-
blockingCaught:
|
|
4698
|
-
advisoryCaught:
|
|
4298
|
+
blockingCaught: mainReplayCustody.provenanceRecord?.blockingCount ?? (policyViolations.filter((v) => v.severity === 'block').length + structuralBlocking),
|
|
4299
|
+
advisoryCaught: mainReplayCustody.provenanceRecord?.advisoryCount ?? (policyViolations.filter((v) => v.severity !== 'block').length + structuralAdvisory),
|
|
4699
4300
|
suppressions: structuralSuppressedCount,
|
|
4700
4301
|
structuralCaught: structuralViolations.length,
|
|
4701
4302
|
aiDebtDelta: aiDebtSummary?.score ?? 0,
|
|
@@ -4817,7 +4418,7 @@ async function verifyCommand(options) {
|
|
|
4817
4418
|
catch (error) {
|
|
4818
4419
|
if (options.json) {
|
|
4819
4420
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
4820
|
-
emitCanonicalVerifyJson({
|
|
4421
|
+
(0, verify_output_1.emitCanonicalVerifyJson)({
|
|
4821
4422
|
verdict: 'FAIL',
|
|
4822
4423
|
summary: {
|
|
4823
4424
|
totalFilesChanged: 0,
|
|
@@ -5068,6 +4669,8 @@ function buildGovernancePayload(governance, orgGovernanceSettings, options) {
|
|
|
5068
4669
|
suspiciousChange: governance.suspiciousChange,
|
|
5069
4670
|
changeJustification: governance.changeJustification,
|
|
5070
4671
|
governanceDecision: governance.governanceDecision,
|
|
4672
|
+
engineeringContext: governance.engineeringContext,
|
|
4673
|
+
driftIntelligence: governance.driftIntelligence,
|
|
5071
4674
|
aiChangeLog: {
|
|
5072
4675
|
path: governance.aiChangeLogPath,
|
|
5073
4676
|
auditPath: governance.aiChangeLogAuditPath,
|
|
@@ -5090,412 +4693,6 @@ function buildGovernancePayload(governance, orgGovernanceSettings, options) {
|
|
|
5090
4693
|
...(options?.aiDebt ? { aiDebt: options.aiDebt } : {}),
|
|
5091
4694
|
};
|
|
5092
4695
|
}
|
|
5093
|
-
function displayGovernanceInsights(governance, options = {}) {
|
|
5094
|
-
const maxUnexpectedFiles = options.maxUnexpectedFiles ?? 20;
|
|
5095
|
-
const decision = governance.governanceDecision;
|
|
5096
|
-
console.log(chalk.bold.white('\nBlast Radius:'));
|
|
5097
|
-
console.log(chalk.dim(` Files touched: ${governance.blastRadius.filesChanged}`));
|
|
5098
|
-
console.log(chalk.dim(` Functions impacted: ${governance.blastRadius.functionsAffected}`));
|
|
5099
|
-
console.log(chalk.dim(` Modules impacted: ${governance.blastRadius.modulesAffected.join(', ') || 'none'}`));
|
|
5100
|
-
if (governance.blastRadius.dependenciesAdded.length > 0) {
|
|
5101
|
-
console.log(chalk.dim(` Dependencies added: ${governance.blastRadius.dependenciesAdded.join(', ')}`));
|
|
5102
|
-
}
|
|
5103
|
-
console.log(chalk.dim(` Risk level: ${governance.blastRadius.riskScore.toUpperCase()}`));
|
|
5104
|
-
console.log(chalk.dim(` Governance decision: ${decision.decision.toUpperCase().replace('_', ' ')} | Avg relevance: ${decision.averageRelevanceScore}`));
|
|
5105
|
-
console.log(chalk.dim(` Policy source: ${governance.policySources.mode}${governance.policySources.orgPolicy ? ' (org + local)' : ' (local)'}`));
|
|
5106
|
-
console.log(governance.aiChangeLogIntegrity.valid
|
|
5107
|
-
? chalk.dim(` AI change-log integrity: valid (${governance.aiChangeLogIntegrity.signed ? 'signed' : 'unsigned'})`)
|
|
5108
|
-
: chalk.red(` AI change-log integrity: invalid (${governance.aiChangeLogIntegrity.issues.join('; ') || 'unknown'})`));
|
|
5109
|
-
if (governance.aiChangeLogIntegrity.signed) {
|
|
5110
|
-
const keyId = typeof governance.aiChangeLogIntegrity.keyId === 'string'
|
|
5111
|
-
? governance.aiChangeLogIntegrity.keyId
|
|
5112
|
-
: null;
|
|
5113
|
-
const verifiedWithKeyId = typeof governance.aiChangeLogIntegrity.verifiedWithKeyId === 'string'
|
|
5114
|
-
? governance.aiChangeLogIntegrity.verifiedWithKeyId
|
|
5115
|
-
: null;
|
|
5116
|
-
if (keyId || verifiedWithKeyId) {
|
|
5117
|
-
console.log(chalk.dim(` Signing key: ${keyId || 'n/a'}${verifiedWithKeyId ? ` (verified via ${verifiedWithKeyId})` : ''}`));
|
|
5118
|
-
}
|
|
5119
|
-
}
|
|
5120
|
-
if (governance.suspiciousChange.flagged) {
|
|
5121
|
-
console.log(chalk.red('\nSuspicious Change Detected'));
|
|
5122
|
-
console.log(chalk.red(` Plan expected files: ${governance.suspiciousChange.expectedFiles} | AI modified files: ${governance.suspiciousChange.actualFiles}`));
|
|
5123
|
-
governance.suspiciousChange.unexpectedFiles.slice(0, maxUnexpectedFiles).forEach((filePath) => {
|
|
5124
|
-
console.log(chalk.red(` • ${filePath}`));
|
|
5125
|
-
});
|
|
5126
|
-
console.log(chalk.red(` Confidence: ${governance.suspiciousChange.confidence}`));
|
|
5127
|
-
}
|
|
5128
|
-
if (decision.lowRelevanceFiles.length > 0) {
|
|
5129
|
-
console.log(chalk.yellow('\nLow Relevance Files'));
|
|
5130
|
-
decision.lowRelevanceFiles.slice(0, 10).forEach((item) => {
|
|
5131
|
-
console.log(chalk.yellow(` • ${item.file} (score ${item.relevanceScore}, ${item.planLink.replace('_', ' ')})`));
|
|
5132
|
-
});
|
|
5133
|
-
}
|
|
5134
|
-
if (options.explain) {
|
|
5135
|
-
console.log(chalk.bold.white('\nAI Change Justification:'));
|
|
5136
|
-
console.log(chalk.dim(` Task: ${governance.changeJustification.task}`));
|
|
5137
|
-
governance.changeJustification.changes.forEach((item) => {
|
|
5138
|
-
const relevance = typeof item.relevanceScore === 'number' ? ` [score ${item.relevanceScore}]` : '';
|
|
5139
|
-
console.log(chalk.dim(` • ${item.file} — ${item.reason}${relevance}`));
|
|
5140
|
-
});
|
|
5141
|
-
}
|
|
5142
|
-
}
|
|
5143
|
-
function displayChangeContractDrift(summary, options = { advisory: false }) {
|
|
5144
|
-
const groups = (0, change_contract_1.groupChangeContractViolations)(summary.violations.map((item) => ({
|
|
5145
|
-
code: item.code,
|
|
5146
|
-
message: item.message,
|
|
5147
|
-
...(item.file ? { file: item.file } : {}),
|
|
5148
|
-
...(item.symbol ? { symbol: item.symbol } : {}),
|
|
5149
|
-
...(item.symbolType ? { symbolType: item.symbolType } : {}),
|
|
5150
|
-
...(item.expected ? { expected: item.expected } : {}),
|
|
5151
|
-
...(item.actual ? { actual: item.actual } : {}),
|
|
5152
|
-
})));
|
|
5153
|
-
if (groups.length === 0)
|
|
5154
|
-
return;
|
|
5155
|
-
const maxItemsPerGroup = options.maxItemsPerGroup ?? 12;
|
|
5156
|
-
const header = options.advisory
|
|
5157
|
-
? chalk.yellow('\nWARN ⚠️ Change contract drift detected')
|
|
5158
|
-
: chalk.red('\nFAIL ❌ Change contract enforcement failed');
|
|
5159
|
-
console.log(header);
|
|
5160
|
-
for (const group of groups) {
|
|
5161
|
-
console.log(chalk.white(`\n${group.title}:`));
|
|
5162
|
-
group.items.slice(0, maxItemsPerGroup).forEach((entry) => {
|
|
5163
|
-
console.log(` - ${entry}`);
|
|
5164
|
-
});
|
|
5165
|
-
if (group.items.length > maxItemsPerGroup) {
|
|
5166
|
-
console.log(chalk.dim(` - ... ${group.items.length - maxItemsPerGroup} more`));
|
|
5167
|
-
}
|
|
5168
|
-
console.log(chalk.dim(` Why it matters: ${group.impact}`));
|
|
5169
|
-
}
|
|
5170
|
-
console.log(chalk.dim('\nSummary:'));
|
|
5171
|
-
console.log(chalk.dim('Implementation deviates from intended contract.'));
|
|
5172
|
-
console.log(chalk.dim(`Contract path: ${summary.path}`));
|
|
5173
|
-
}
|
|
5174
|
-
/**
|
|
5175
|
-
* Display verification results in a formatted report card
|
|
5176
|
-
*/
|
|
5177
|
-
function displayVerifyResults(result, policyViolations, expediteModeUsed = false, intentIssuesForDisplay = [], intentSummaryForDisplay = null, flowIssuesForDisplay = [], regressionsForDisplay = [], structuralViolationsForDisplay = []) {
|
|
5178
|
-
// ── Header ────────────────────────────────────────────────────────────────
|
|
5179
|
-
const headerLabel = result.verdict === 'PASS'
|
|
5180
|
-
? chalk.bold.green('\n✅ VERIFICATION PASSED')
|
|
5181
|
-
: result.verdict === 'WARN'
|
|
5182
|
-
? chalk.bold.yellow('\n⚠️ VERIFICATION PASSED WITH WARNINGS')
|
|
5183
|
-
: chalk.bold.red('\n❌ VERIFICATION FAILED');
|
|
5184
|
-
console.log(headerLabel);
|
|
5185
|
-
// ── Intent Status block ──────────────────────────────────────────────────
|
|
5186
|
-
if (intentSummaryForDisplay) {
|
|
5187
|
-
const s = intentSummaryForDisplay;
|
|
5188
|
-
const domainLabel = s.domain.charAt(0).toUpperCase() + s.domain.slice(1);
|
|
5189
|
-
const confColor = s.confidence === 'HIGH'
|
|
5190
|
-
? chalk.green
|
|
5191
|
-
: s.confidence === 'MEDIUM'
|
|
5192
|
-
? chalk.yellow
|
|
5193
|
-
: chalk.red;
|
|
5194
|
-
// V4: weighted coverage bar
|
|
5195
|
-
const wCovPct = s.weightedCoverage != null
|
|
5196
|
-
? Math.round(s.weightedCoverage * 100)
|
|
5197
|
-
: s.coveragePct;
|
|
5198
|
-
const barWidth = 20;
|
|
5199
|
-
const filled = Math.round((wCovPct / 100) * barWidth);
|
|
5200
|
-
const bar = chalk.cyan('█'.repeat(filled)) + chalk.dim('░'.repeat(barWidth - filled));
|
|
5201
|
-
// V4: system status label
|
|
5202
|
-
const sysStatus = s.status;
|
|
5203
|
-
const statusLabel = sysStatus === 'CRITICAL'
|
|
5204
|
-
? chalk.bold.red('[CRITICAL]')
|
|
5205
|
-
: sysStatus === 'AT RISK'
|
|
5206
|
-
? chalk.bold.yellow('[AT RISK]')
|
|
5207
|
-
: chalk.bold.green('[SECURE]');
|
|
5208
|
-
console.log(chalk.bold('\n━━━ INTENT STATUS ━━━━━━━━━━━━━━━━━━━━━━'));
|
|
5209
|
-
console.log(` ${statusLabel} ${chalk.bold(`${domainLabel} Implementation:`)} ${bar} ${chalk.bold(`${wCovPct}%`)} (weighted)`);
|
|
5210
|
-
console.log(` Confidence: ${confColor(s.confidence)}`);
|
|
5211
|
-
if (s.foundList.length > 0) {
|
|
5212
|
-
const foundLabels = s.foundList
|
|
5213
|
-
.map((k) => k.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' '))
|
|
5214
|
-
.slice(0, 4);
|
|
5215
|
-
console.log(` Found: ${chalk.green(foundLabels.join(', '))}${s.foundList.length > 4 ? chalk.dim(` +${s.foundList.length - 4} more`) : ''}`);
|
|
5216
|
-
}
|
|
5217
|
-
// V4: show critical missing and non-critical missing separately
|
|
5218
|
-
const critMissing = s.criticalMissing ?? [];
|
|
5219
|
-
const otherMissing = s.missing.filter((k) => !critMissing.includes(k));
|
|
5220
|
-
if (critMissing.length > 0) {
|
|
5221
|
-
console.log(` ${chalk.bold.red('Critical missing:')}`);
|
|
5222
|
-
critMissing.forEach((k) => {
|
|
5223
|
-
const label = k.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
5224
|
-
console.log(chalk.red(` ✗ ${label}`));
|
|
5225
|
-
});
|
|
5226
|
-
}
|
|
5227
|
-
if (otherMissing.length > 0) {
|
|
5228
|
-
console.log(` ${chalk.bold.yellow('Missing:')}`);
|
|
5229
|
-
otherMissing.forEach((k) => {
|
|
5230
|
-
const label = k.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
5231
|
-
console.log(chalk.yellow(` • ${label}`));
|
|
5232
|
-
});
|
|
5233
|
-
}
|
|
5234
|
-
if (critMissing.length === 0 && otherMissing.length === 0) {
|
|
5235
|
-
console.log(` Missing: ${chalk.green('none — all components detected')}`);
|
|
5236
|
-
}
|
|
5237
|
-
console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
5238
|
-
}
|
|
5239
|
-
// ── Triage items ──────────────────────────────────────────────────────────
|
|
5240
|
-
const maxBlockingItems = 20;
|
|
5241
|
-
const maxAdvisoryItems = 8;
|
|
5242
|
-
const maxExpediteItems = 12;
|
|
5243
|
-
const policyItems = policyViolations || [];
|
|
5244
|
-
const isBlockingSeverity = (severityRaw) => {
|
|
5245
|
-
const normalized = String(severityRaw || '').toLowerCase();
|
|
5246
|
-
return normalized === 'block' || normalized === 'critical' || normalized === 'high';
|
|
5247
|
-
};
|
|
5248
|
-
const scopeItems = result.bloatFiles.map((file) => ({
|
|
5249
|
-
file,
|
|
5250
|
-
message: 'File modified outside intended scope',
|
|
5251
|
-
policy: 'scope_guard',
|
|
5252
|
-
}));
|
|
5253
|
-
const policyTriageItems = policyItems.map((item) => ({
|
|
5254
|
-
file: item.file,
|
|
5255
|
-
message: item.message || item.rule,
|
|
5256
|
-
policy: item.rule || 'policy_violation',
|
|
5257
|
-
severity: item.severity,
|
|
5258
|
-
}));
|
|
5259
|
-
// Structural rule violations — split by severity
|
|
5260
|
-
const structuralBlocking = structuralViolationsForDisplay
|
|
5261
|
-
.filter((v) => v.severity === 'BLOCKING')
|
|
5262
|
-
.map((v) => ({
|
|
5263
|
-
file: v.filePath,
|
|
5264
|
-
message: `${v.ruleId} · ${v.ruleName} (line ${v.line}) — ${v.operationalRisk}`,
|
|
5265
|
-
}));
|
|
5266
|
-
const structuralAdvisory = structuralViolationsForDisplay
|
|
5267
|
-
.filter((v) => v.severity === 'ADVISORY')
|
|
5268
|
-
.map((v) => ({
|
|
5269
|
-
file: v.filePath,
|
|
5270
|
-
message: `${v.ruleId} · ${v.ruleName} (line ${v.line}) — ${v.operationalRisk}`,
|
|
5271
|
-
}));
|
|
5272
|
-
let blockingItems = [
|
|
5273
|
-
...scopeItems.map((item) => ({
|
|
5274
|
-
file: item.file,
|
|
5275
|
-
message: item.message,
|
|
5276
|
-
})),
|
|
5277
|
-
...policyTriageItems
|
|
5278
|
-
.filter((item) => isBlockingSeverity(item.severity))
|
|
5279
|
-
.map((item) => ({
|
|
5280
|
-
file: item.file,
|
|
5281
|
-
message: item.message,
|
|
5282
|
-
})),
|
|
5283
|
-
...structuralBlocking,
|
|
5284
|
-
];
|
|
5285
|
-
let advisoryItems = [
|
|
5286
|
-
...policyTriageItems
|
|
5287
|
-
.filter((item) => !isBlockingSeverity(item.severity))
|
|
5288
|
-
.map((item) => ({
|
|
5289
|
-
file: item.file,
|
|
5290
|
-
message: item.message,
|
|
5291
|
-
})),
|
|
5292
|
-
...structuralAdvisory,
|
|
5293
|
-
];
|
|
5294
|
-
let expediteItems = [];
|
|
5295
|
-
if (expediteModeUsed) {
|
|
5296
|
-
blockingItems = [
|
|
5297
|
-
...scopeItems
|
|
5298
|
-
.filter((item) => isCriticalScopeBreach(item.file, item.message))
|
|
5299
|
-
.map((item) => ({ file: item.file, message: item.message })),
|
|
5300
|
-
...policyTriageItems
|
|
5301
|
-
.filter((item) => isSecurityOrAuthViolation(item.file, item.policy, item.message))
|
|
5302
|
-
.map((item) => ({ file: item.file, message: item.message })),
|
|
5303
|
-
];
|
|
5304
|
-
expediteItems = [
|
|
5305
|
-
...scopeItems
|
|
5306
|
-
.filter((item) => !isCriticalScopeBreach(item.file, item.message))
|
|
5307
|
-
.map((item) => ({ file: item.file, message: item.message })),
|
|
5308
|
-
...policyTriageItems
|
|
5309
|
-
.filter((item) => !isSecurityOrAuthViolation(item.file, item.policy, item.message))
|
|
5310
|
-
.map((item) => ({ file: item.file, message: item.message })),
|
|
5311
|
-
];
|
|
5312
|
-
advisoryItems = [];
|
|
5313
|
-
}
|
|
5314
|
-
// ── Counts ────────────────────────────────────────────────────────────────
|
|
5315
|
-
console.log(blockingItems.length > 0
|
|
5316
|
-
? chalk.red(`Blocking Issues: ${blockingItems.length}`)
|
|
5317
|
-
: chalk.dim('Blocking Issues: 0'));
|
|
5318
|
-
if (expediteModeUsed) {
|
|
5319
|
-
console.log(chalk.yellow(`Expedite Issues: ${expediteItems.length}`));
|
|
5320
|
-
}
|
|
5321
|
-
else {
|
|
5322
|
-
console.log(advisoryItems.length > 0
|
|
5323
|
-
? chalk.yellow(`Advisory Issues: ${advisoryItems.length}`)
|
|
5324
|
-
: chalk.dim('Advisory Issues: 0'));
|
|
5325
|
-
}
|
|
5326
|
-
console.log(chalk.dim(`Plan adherence: ${result.plannedFilesModified}/${result.totalPlannedFiles} files (${result.adherenceScore}%)`));
|
|
5327
|
-
// ── Top issues ────────────────────────────────────────────────────────────
|
|
5328
|
-
const topIssues = [
|
|
5329
|
-
...blockingItems,
|
|
5330
|
-
...(expediteModeUsed ? expediteItems : advisoryItems),
|
|
5331
|
-
].slice(0, 2);
|
|
5332
|
-
if (topIssues.length > 0) {
|
|
5333
|
-
console.log(chalk.bold('\nTop Issues:'));
|
|
5334
|
-
topIssues.forEach((item, i) => {
|
|
5335
|
-
console.log(` ${i + 1}. ${item.message} → ${chalk.cyan(item.file)}`);
|
|
5336
|
-
});
|
|
5337
|
-
}
|
|
5338
|
-
// ── Detailed lists ────────────────────────────────────────────────────────
|
|
5339
|
-
if (blockingItems.length > 0) {
|
|
5340
|
-
console.log(chalk.red(`\nBLOCKING (${blockingItems.length})`));
|
|
5341
|
-
blockingItems.slice(0, maxBlockingItems).forEach((item) => {
|
|
5342
|
-
console.log(` - ${item.file}: ${item.message}`);
|
|
5343
|
-
});
|
|
5344
|
-
if (blockingItems.length > maxBlockingItems) {
|
|
5345
|
-
console.log(chalk.dim(` - ... ${blockingItems.length - maxBlockingItems} more`));
|
|
5346
|
-
}
|
|
5347
|
-
}
|
|
5348
|
-
if (advisoryItems.length > 0) {
|
|
5349
|
-
console.log(chalk.yellow(`\nADVISORY (${advisoryItems.length})`));
|
|
5350
|
-
advisoryItems.slice(0, maxAdvisoryItems).forEach((item) => {
|
|
5351
|
-
console.log(` - ${item.file}: ${item.message}`);
|
|
5352
|
-
});
|
|
5353
|
-
if (advisoryItems.length > maxAdvisoryItems) {
|
|
5354
|
-
console.log(chalk.dim(` - ... ${advisoryItems.length - maxAdvisoryItems} more (summarized)`));
|
|
5355
|
-
}
|
|
5356
|
-
}
|
|
5357
|
-
if (expediteModeUsed && expediteItems.length > 0) {
|
|
5358
|
-
console.log(chalk.yellow(`\nEXPEDITE (requires follow-up) (${expediteItems.length})`));
|
|
5359
|
-
expediteItems.slice(0, maxExpediteItems).forEach((item) => {
|
|
5360
|
-
console.log(` - ${item.file}: ${item.message}`);
|
|
5361
|
-
});
|
|
5362
|
-
if (expediteItems.length > maxExpediteItems) {
|
|
5363
|
-
console.log(chalk.dim(` - ... ${expediteItems.length - maxExpediteItems} more (summarized)`));
|
|
5364
|
-
}
|
|
5365
|
-
console.log(chalk.dim(' Follow-up checklist:'));
|
|
5366
|
-
EXPEDITE_FOLLOW_UP_CHECKLIST.forEach((checkItem) => {
|
|
5367
|
-
console.log(chalk.dim(` - ${checkItem}`));
|
|
5368
|
-
});
|
|
5369
|
-
console.log(chalk.dim(' Note: Expedite Mode used'));
|
|
5370
|
-
}
|
|
5371
|
-
// ── Intent issues ─────────────────────────────────────────────────────────
|
|
5372
|
-
if (intentIssuesForDisplay.length > 0) {
|
|
5373
|
-
console.log(chalk.magenta(`\nINTENT ISSUES (${intentIssuesForDisplay.length})`));
|
|
5374
|
-
intentIssuesForDisplay.forEach((issue) => {
|
|
5375
|
-
const label = issue.severity === 'high' ? chalk.red('[HIGH]') : chalk.yellow('[MEDIUM]');
|
|
5376
|
-
const typeLabel = issue.type === 'missing' ? 'Missing' : issue.type === 'misplaced' ? 'Misplaced' : 'Partial';
|
|
5377
|
-
console.log(` ${label} ${typeLabel}: ${issue.message}`);
|
|
5378
|
-
});
|
|
5379
|
-
}
|
|
5380
|
-
// ── Flow Validation ───────────────────────────────────────────────────────
|
|
5381
|
-
if (flowIssuesForDisplay.length > 0) {
|
|
5382
|
-
console.log(chalk.bold('\n━━━ FLOW VALIDATION ━━━━━━━━━━━━━━━━━━━━━'));
|
|
5383
|
-
flowIssuesForDisplay.forEach((issue) => {
|
|
5384
|
-
const label = issue.severity === 'high' ? chalk.red('[HIGH]') : chalk.yellow('[MEDIUM]');
|
|
5385
|
-
const typeIcon = issue.type === 'missing-flow' ? '⛓' : issue.type === 'misplaced-flow' ? '⚠' : '⊘';
|
|
5386
|
-
console.log(` ${label} ${typeIcon} ${issue.message}`);
|
|
5387
|
-
if (issue.files && issue.files.length > 0) {
|
|
5388
|
-
const display = issue.files.slice(0, 3);
|
|
5389
|
-
console.log(chalk.dim(` → ${display.join(', ')}${issue.files.length > 3 ? ` +${issue.files.length - 3} more` : ''}`));
|
|
5390
|
-
}
|
|
5391
|
-
});
|
|
5392
|
-
console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
5393
|
-
}
|
|
5394
|
-
// ── Regression Analysis ───────────────────────────────────────────────────
|
|
5395
|
-
if (regressionsForDisplay.length > 0) {
|
|
5396
|
-
console.log(chalk.bold.red('\n━━━ REGRESSION ANALYSIS ━━━━━━━━━━━━━━━━━'));
|
|
5397
|
-
regressionsForDisplay.forEach((reg) => {
|
|
5398
|
-
const icon = reg.type === 'coverage-regression' ? '📉' :
|
|
5399
|
-
reg.type === 'critical-regression' ? '🔴' :
|
|
5400
|
-
reg.type === 'flow-regression' ? '⛓' : '⚠';
|
|
5401
|
-
console.log(` ${chalk.red('[REGRESSION]')} ${icon} ${reg.message}`);
|
|
5402
|
-
});
|
|
5403
|
-
console.log(chalk.bold.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
5404
|
-
}
|
|
5405
|
-
// ── Structural Rule Engine ─────────────────────────────────────────────────
|
|
5406
|
-
// Display detailed structural violations with AST evidence and determinism labels.
|
|
5407
|
-
if (structuralViolationsForDisplay.length > 0) {
|
|
5408
|
-
try {
|
|
5409
|
-
const report = (0, explainability_1.buildViolationReport)(structuralViolationsForDisplay, '');
|
|
5410
|
-
const formatter = new explainability_1.ViolationFormatter();
|
|
5411
|
-
const blocking = report.blocking;
|
|
5412
|
-
const advisory = report.advisory;
|
|
5413
|
-
if (blocking.length > 0 || advisory.length > 0) {
|
|
5414
|
-
console.log(chalk.bold('\n━━━ STRUCTURAL ANALYSIS ━━━━━━━━━━━━━━━━━'));
|
|
5415
|
-
blocking.slice(0, 5).forEach((v) => {
|
|
5416
|
-
const detLabel = v.determinism === 'deterministic-structural'
|
|
5417
|
-
? chalk.cyan('⚙ AST-verified')
|
|
5418
|
-
: chalk.yellow('⚡ heuristic');
|
|
5419
|
-
console.log(chalk.red(`\n ● ${v.ruleId} [BLOCKING] ${detLabel} · confidence ${Math.round(v.confidence * 100)}%`));
|
|
5420
|
-
console.log(chalk.bold(` ${v.filePath}:${v.line}`));
|
|
5421
|
-
console.log(chalk.dim(` Pattern: ${v.evidence.matchReason}`));
|
|
5422
|
-
if (v.evidence.codeSnippet) {
|
|
5423
|
-
console.log(chalk.dim(` Code: ${v.evidence.codeSnippet.slice(0, 100)}`));
|
|
5424
|
-
}
|
|
5425
|
-
console.log(chalk.yellow(` Risk: ${v.operationalRisk}`));
|
|
5426
|
-
console.log(chalk.green(` Fix: ${v.remediation}`));
|
|
5427
|
-
});
|
|
5428
|
-
if (blocking.length > 5) {
|
|
5429
|
-
console.log(chalk.dim(`\n ... ${blocking.length - 5} more blocking structural violations`));
|
|
5430
|
-
}
|
|
5431
|
-
advisory.slice(0, 3).forEach((v) => {
|
|
5432
|
-
console.log(chalk.yellow(`\n ○ ${v.ruleId} [ADVISORY] ⚡ heuristic · confidence ${Math.round(v.confidence * 100)}%`));
|
|
5433
|
-
console.log(chalk.dim(` ${v.filePath}:${v.line} — ${v.operationalRisk}`));
|
|
5434
|
-
});
|
|
5435
|
-
if (advisory.length > 3) {
|
|
5436
|
-
console.log(chalk.dim(` ... ${advisory.length - 3} more advisory structural violations`));
|
|
5437
|
-
}
|
|
5438
|
-
const deterministicCount = report.deterministicCount;
|
|
5439
|
-
const heuristicCount = report.heuristicCount;
|
|
5440
|
-
console.log(chalk.dim(`\n Determinism: ${deterministicCount} AST-verified · ${heuristicCount} heuristic`));
|
|
5441
|
-
console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
5442
|
-
}
|
|
5443
|
-
}
|
|
5444
|
-
catch {
|
|
5445
|
-
// Non-fatal: explainability rendering must never break verification display
|
|
5446
|
-
}
|
|
5447
|
-
}
|
|
5448
|
-
const hasAnyIssue = blockingItems.length > 0 ||
|
|
5449
|
-
advisoryItems.length > 0 ||
|
|
5450
|
-
expediteItems.length > 0 ||
|
|
5451
|
-
intentIssuesForDisplay.length > 0 ||
|
|
5452
|
-
flowIssuesForDisplay.length > 0 ||
|
|
5453
|
-
regressionsForDisplay.length > 0;
|
|
5454
|
-
if (!hasAnyIssue) {
|
|
5455
|
-
console.log(chalk.green('\nNo issues detected.'));
|
|
5456
|
-
}
|
|
5457
|
-
// ── Next step ─────────────────────────────────────────────────────────────
|
|
5458
|
-
if (hasAnyIssue) {
|
|
5459
|
-
console.log(chalk.bold('\nNext step:'));
|
|
5460
|
-
console.log(` ${chalk.cyan('neurcode fix')}`);
|
|
5461
|
-
console.log(chalk.dim(' or: neurcode fix --apply-safe (auto-apply high-confidence patches)'));
|
|
5462
|
-
}
|
|
5463
|
-
console.log(chalk.dim(`\nDetails: ${result.message}\n`));
|
|
5464
|
-
}
|
|
5465
|
-
function printFirstRunAdvisoryMessage(demoMode) {
|
|
5466
|
-
console.log(chalk.cyan('\nNeurcode first-run advisory mode'));
|
|
5467
|
-
console.log(chalk.dim('Neurcode checks if your AI-generated code matches your intended plan.'));
|
|
5468
|
-
console.log(chalk.dim('To get full enforcement:'));
|
|
5469
|
-
console.log(chalk.dim('1. Define a plan'));
|
|
5470
|
-
console.log(chalk.dim('2. Generate a contract'));
|
|
5471
|
-
console.log(chalk.dim('Running in advisory mode for now.\n'));
|
|
5472
|
-
if (demoMode) {
|
|
5473
|
-
console.log(chalk.dim('Demo mode: this run is intentionally non-blocking to make evaluation easy.'));
|
|
5474
|
-
}
|
|
5475
|
-
}
|
|
5476
|
-
function printAdvisorySignals(signals, demoMode) {
|
|
5477
|
-
if (signals.length === 0) {
|
|
5478
|
-
if (demoMode) {
|
|
5479
|
-
console.log(chalk.dim('No high-signal advisory findings detected for this diff.'));
|
|
5480
|
-
}
|
|
5481
|
-
return;
|
|
5482
|
-
}
|
|
5483
|
-
console.log(chalk.yellow('\nAdvisory findings (non-blocking):'));
|
|
5484
|
-
for (const signal of signals) {
|
|
5485
|
-
const severityLabel = signal.severity === 'warn' ? chalk.yellow('[warn]') : chalk.dim('[info]');
|
|
5486
|
-
console.log(`${severityLabel} ${signal.title}`);
|
|
5487
|
-
console.log(chalk.dim(` ${signal.detail}`));
|
|
5488
|
-
console.log(chalk.dim(` Confidence: ${signal.confidence.toUpperCase()} (advisory-only)`));
|
|
5489
|
-
if (signal.evidence.length > 0) {
|
|
5490
|
-
console.log(chalk.dim(` Evidence: ${signal.evidence.join(', ')}`));
|
|
5491
|
-
}
|
|
5492
|
-
console.log(chalk.dim(` Structural gap: ${signal.structuralCoverageGap}`));
|
|
5493
|
-
console.log(chalk.dim(` Uncertainty: ${signal.uncertainty}`));
|
|
5494
|
-
signal.files.forEach((file) => {
|
|
5495
|
-
console.log(chalk.dim(` - ${file}`));
|
|
5496
|
-
});
|
|
5497
|
-
}
|
|
5498
|
-
}
|
|
5499
4696
|
function buildMinimalAdvisoryContractFromDiff(diffFiles, fallbackPlanId) {
|
|
5500
4697
|
const expectedFiles = [...new Set(diffFiles.map((file) => toUnixPath(file.path)).filter(Boolean))];
|
|
5501
4698
|
const planFiles = expectedFiles.map((path) => {
|