@neurcode-ai/cli 0.9.63 → 0.9.65
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/LICENSE +201 -0
- package/dist/commands/brain.d.ts.map +1 -1
- package/dist/commands/brain.js +273 -0
- package/dist/commands/brain.js.map +1 -1
- package/dist/commands/control-plane.js +7 -7
- package/dist/commands/control-plane.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +108 -1
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/patch-apply.d.ts +2 -0
- package/dist/commands/patch-apply.d.ts.map +1 -1
- package/dist/commands/patch-apply.js +331 -19
- package/dist/commands/patch-apply.js.map +1 -1
- package/dist/commands/pilot-report.d.ts +9 -0
- package/dist/commands/pilot-report.d.ts.map +1 -0
- package/dist/commands/pilot-report.js +176 -0
- package/dist/commands/pilot-report.js.map +1 -0
- package/dist/commands/remediate-governance.d.ts +54 -0
- package/dist/commands/remediate-governance.d.ts.map +1 -0
- package/dist/commands/remediate-governance.js +375 -0
- package/dist/commands/remediate-governance.js.map +1 -0
- package/dist/commands/remediate.d.ts.map +1 -1
- package/dist/commands/remediate.js.map +1 -1
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +35 -5
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +336 -25
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/workspace.js +7 -7
- package/dist/commands/workspace.js.map +1 -1
- package/dist/daemon/server.d.ts +2 -2
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +2113 -32
- package/dist/daemon/server.js.map +1 -1
- package/dist/explainability/DeterminismClassifier.d.ts +34 -0
- package/dist/explainability/DeterminismClassifier.d.ts.map +1 -0
- package/dist/explainability/DeterminismClassifier.js +104 -0
- package/dist/explainability/DeterminismClassifier.js.map +1 -0
- package/dist/explainability/ViolationFormatter.d.ts +32 -0
- package/dist/explainability/ViolationFormatter.d.ts.map +1 -0
- package/dist/explainability/ViolationFormatter.js +252 -0
- package/dist/explainability/ViolationFormatter.js.map +1 -0
- package/dist/explainability/index.d.ts +15 -0
- package/dist/explainability/index.d.ts.map +1 -0
- package/dist/explainability/index.js +94 -0
- package/dist/explainability/index.js.map +1 -0
- package/dist/explainability/types.d.ts +37 -0
- package/dist/explainability/types.d.ts.map +1 -0
- package/dist/explainability/types.js +3 -0
- package/dist/explainability/types.js.map +1 -0
- package/dist/governance/canonical-pipeline.d.ts +38 -0
- package/dist/governance/canonical-pipeline.d.ts.map +1 -0
- package/dist/governance/canonical-pipeline.js +448 -0
- package/dist/governance/canonical-pipeline.js.map +1 -0
- package/dist/governance/structural-on-diff.d.ts +13 -0
- package/dist/governance/structural-on-diff.d.ts.map +1 -0
- package/dist/governance/structural-on-diff.js +35 -0
- package/dist/governance/structural-on-diff.js.map +1 -0
- package/dist/governance/structural-policy-merge.d.ts +14 -0
- package/dist/governance/structural-policy-merge.d.ts.map +1 -0
- package/dist/governance/structural-policy-merge.js +25 -0
- package/dist/governance/structural-policy-merge.js.map +1 -0
- package/dist/index.js +86 -4
- package/dist/index.js.map +1 -1
- package/dist/integrations/review-compression/index.d.ts +50 -0
- package/dist/integrations/review-compression/index.d.ts.map +1 -0
- package/dist/integrations/review-compression/index.js +158 -0
- package/dist/integrations/review-compression/index.js.map +1 -0
- package/dist/intent-engine/domain-taxonomy.d.ts +42 -0
- package/dist/intent-engine/domain-taxonomy.d.ts.map +1 -0
- package/dist/intent-engine/domain-taxonomy.js +534 -0
- package/dist/intent-engine/domain-taxonomy.js.map +1 -0
- package/dist/intent-engine/index.d.ts +1 -0
- package/dist/intent-engine/index.d.ts.map +1 -1
- package/dist/intent-engine/index.js +6 -1
- package/dist/intent-engine/index.js.map +1 -1
- package/dist/intent-engine/matcher.d.ts.map +1 -1
- package/dist/intent-engine/matcher.js +2 -0
- package/dist/intent-engine/matcher.js.map +1 -1
- package/dist/intent-engine/parser.d.ts.map +1 -1
- package/dist/intent-engine/parser.js +47 -0
- package/dist/intent-engine/parser.js.map +1 -1
- package/dist/intent-engine/semantic-expander.d.ts +104 -0
- package/dist/intent-engine/semantic-expander.d.ts.map +1 -0
- package/dist/intent-engine/semantic-expander.js +480 -0
- package/dist/intent-engine/semantic-expander.js.map +1 -0
- package/dist/patch-engine/diff.d.ts +1 -1
- package/dist/patch-engine/diff.js +1 -1
- package/dist/patch-engine/generator.d.ts +9 -0
- package/dist/patch-engine/generator.d.ts.map +1 -1
- package/dist/patch-engine/generator.js +375 -17
- package/dist/patch-engine/generator.js.map +1 -1
- package/dist/patch-engine/index.d.ts +25 -25
- package/dist/patch-engine/index.d.ts.map +1 -1
- package/dist/patch-engine/index.js +134 -87
- package/dist/patch-engine/index.js.map +1 -1
- package/dist/patch-engine/patterns.d.ts +1 -1
- package/dist/patch-engine/patterns.d.ts.map +1 -1
- package/dist/patch-engine/patterns.js +282 -41
- package/dist/patch-engine/patterns.js.map +1 -1
- package/dist/patch-engine/rollback.d.ts +31 -0
- package/dist/patch-engine/rollback.d.ts.map +1 -0
- package/dist/patch-engine/rollback.js +275 -0
- package/dist/patch-engine/rollback.js.map +1 -0
- package/dist/patch-engine/safety.d.ts +28 -0
- package/dist/patch-engine/safety.d.ts.map +1 -0
- package/dist/patch-engine/safety.js +122 -0
- package/dist/patch-engine/safety.js.map +1 -0
- package/dist/patch-engine/transaction.d.ts +52 -0
- package/dist/patch-engine/transaction.d.ts.map +1 -0
- package/dist/patch-engine/transaction.js +93 -0
- package/dist/patch-engine/transaction.js.map +1 -0
- package/dist/semantic/index.d.ts +14 -0
- package/dist/semantic/index.d.ts.map +1 -0
- package/dist/semantic/index.js +30 -0
- package/dist/semantic/index.js.map +1 -0
- package/dist/semantic/tfidf-engine.d.ts +81 -0
- package/dist/semantic/tfidf-engine.d.ts.map +1 -0
- package/dist/semantic/tfidf-engine.js +278 -0
- package/dist/semantic/tfidf-engine.js.map +1 -0
- package/dist/semantic/vector-store.d.ts +108 -0
- package/dist/semantic/vector-store.d.ts.map +1 -0
- package/dist/semantic/vector-store.js +321 -0
- package/dist/semantic/vector-store.js.map +1 -0
- package/dist/structural-rules/context-severity.d.ts +46 -0
- package/dist/structural-rules/context-severity.d.ts.map +1 -0
- package/dist/structural-rules/context-severity.js +115 -0
- package/dist/structural-rules/context-severity.js.map +1 -0
- package/dist/structural-rules/distributed/DS001-saga-rollback-absence.d.ts +11 -0
- package/dist/structural-rules/distributed/DS001-saga-rollback-absence.d.ts.map +1 -0
- package/dist/structural-rules/distributed/DS001-saga-rollback-absence.js +212 -0
- package/dist/structural-rules/distributed/DS001-saga-rollback-absence.js.map +1 -0
- package/dist/structural-rules/distributed/DS002-missing-correlation-id.d.ts +11 -0
- package/dist/structural-rules/distributed/DS002-missing-correlation-id.d.ts.map +1 -0
- package/dist/structural-rules/distributed/DS002-missing-correlation-id.js +213 -0
- package/dist/structural-rules/distributed/DS002-missing-correlation-id.js.map +1 -0
- package/dist/structural-rules/distributed/index.d.ts +3 -0
- package/dist/structural-rules/distributed/index.d.ts.map +1 -0
- package/dist/structural-rules/distributed/index.js +8 -0
- package/dist/structural-rules/distributed/index.js.map +1 -0
- package/dist/structural-rules/engine.d.ts +25 -0
- package/dist/structural-rules/engine.d.ts.map +1 -0
- package/dist/structural-rules/engine.js +90 -0
- package/dist/structural-rules/engine.js.map +1 -0
- package/dist/structural-rules/index.d.ts +41 -0
- package/dist/structural-rules/index.d.ts.map +1 -0
- package/dist/structural-rules/index.js +141 -0
- package/dist/structural-rules/index.js.map +1 -0
- package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.d.ts +11 -0
- package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.d.ts.map +1 -0
- package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.js +66 -0
- package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.js.map +1 -0
- package/dist/structural-rules/python/PY002-unbounded-dict-singleton.d.ts +11 -0
- package/dist/structural-rules/python/PY002-unbounded-dict-singleton.d.ts.map +1 -0
- package/dist/structural-rules/python/PY002-unbounded-dict-singleton.js +135 -0
- package/dist/structural-rules/python/PY002-unbounded-dict-singleton.js.map +1 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.d.ts +11 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.d.ts.map +1 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.js +86 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.js.map +1 -0
- package/dist/structural-rules/python/PY004-swallowed-async-exception.d.ts +11 -0
- package/dist/structural-rules/python/PY004-swallowed-async-exception.d.ts.map +1 -0
- package/dist/structural-rules/python/PY004-swallowed-async-exception.js +167 -0
- package/dist/structural-rules/python/PY004-swallowed-async-exception.js.map +1 -0
- package/dist/structural-rules/python/PY005-fastapi-without-pydantic.d.ts +11 -0
- package/dist/structural-rules/python/PY005-fastapi-without-pydantic.d.ts.map +1 -0
- package/dist/structural-rules/python/PY005-fastapi-without-pydantic.js +154 -0
- package/dist/structural-rules/python/PY005-fastapi-without-pydantic.js.map +1 -0
- package/dist/structural-rules/python/PY006-blocking-io-in-async.d.ts +11 -0
- package/dist/structural-rules/python/PY006-blocking-io-in-async.d.ts.map +1 -0
- package/dist/structural-rules/python/PY006-blocking-io-in-async.js +130 -0
- package/dist/structural-rules/python/PY006-blocking-io-in-async.js.map +1 -0
- package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.d.ts +11 -0
- package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.d.ts.map +1 -0
- package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.js +93 -0
- package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.js.map +1 -0
- package/dist/structural-rules/python/PY008-celery-task-without-retry.d.ts +11 -0
- package/dist/structural-rules/python/PY008-celery-task-without-retry.d.ts.map +1 -0
- package/dist/structural-rules/python/PY008-celery-task-without-retry.js +154 -0
- package/dist/structural-rules/python/PY008-celery-task-without-retry.js.map +1 -0
- package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.d.ts +11 -0
- package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.d.ts.map +1 -0
- package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.js +133 -0
- package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.js.map +1 -0
- package/dist/structural-rules/python/PY010-leaked-aiohttp-session.d.ts +11 -0
- package/dist/structural-rules/python/PY010-leaked-aiohttp-session.d.ts.map +1 -0
- package/dist/structural-rules/python/PY010-leaked-aiohttp-session.js +80 -0
- package/dist/structural-rules/python/PY010-leaked-aiohttp-session.js.map +1 -0
- package/dist/structural-rules/rules/SR001-swallowed-async-rejection.d.ts +11 -0
- package/dist/structural-rules/rules/SR001-swallowed-async-rejection.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR001-swallowed-async-rejection.js +145 -0
- package/dist/structural-rules/rules/SR001-swallowed-async-rejection.js.map +1 -0
- package/dist/structural-rules/rules/SR002-unbounded-collection.d.ts +11 -0
- package/dist/structural-rules/rules/SR002-unbounded-collection.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR002-unbounded-collection.js +196 -0
- package/dist/structural-rules/rules/SR002-unbounded-collection.js.map +1 -0
- package/dist/structural-rules/rules/SR003-timer-without-cleanup.d.ts +11 -0
- package/dist/structural-rules/rules/SR003-timer-without-cleanup.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR003-timer-without-cleanup.js +148 -0
- package/dist/structural-rules/rules/SR003-timer-without-cleanup.js.map +1 -0
- package/dist/structural-rules/rules/SR004-request-boundary-no-validation.d.ts +11 -0
- package/dist/structural-rules/rules/SR004-request-boundary-no-validation.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR004-request-boundary-no-validation.js +162 -0
- package/dist/structural-rules/rules/SR004-request-boundary-no-validation.js.map +1 -0
- package/dist/structural-rules/rules/SR005-halfopen-probe-gate.d.ts +11 -0
- package/dist/structural-rules/rules/SR005-halfopen-probe-gate.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR005-halfopen-probe-gate.js +150 -0
- package/dist/structural-rules/rules/SR005-halfopen-probe-gate.js.map +1 -0
- package/dist/structural-rules/rules/SR006-fanout-error-sanitization.d.ts +11 -0
- package/dist/structural-rules/rules/SR006-fanout-error-sanitization.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR006-fanout-error-sanitization.js +161 -0
- package/dist/structural-rules/rules/SR006-fanout-error-sanitization.js.map +1 -0
- package/dist/structural-rules/rules/SR007-cross-request-error.d.ts +11 -0
- package/dist/structural-rules/rules/SR007-cross-request-error.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR007-cross-request-error.js +175 -0
- package/dist/structural-rules/rules/SR007-cross-request-error.js.map +1 -0
- package/dist/structural-rules/rules/SR008-background-task-orphan.d.ts +11 -0
- package/dist/structural-rules/rules/SR008-background-task-orphan.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR008-background-task-orphan.js +176 -0
- package/dist/structural-rules/rules/SR008-background-task-orphan.js.map +1 -0
- package/dist/structural-rules/rules/SR009-missing-retry-backoff.d.ts +11 -0
- package/dist/structural-rules/rules/SR009-missing-retry-backoff.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR009-missing-retry-backoff.js +168 -0
- package/dist/structural-rules/rules/SR009-missing-retry-backoff.js.map +1 -0
- package/dist/structural-rules/rules/SR010-retry-storm.d.ts +11 -0
- package/dist/structural-rules/rules/SR010-retry-storm.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR010-retry-storm.js +181 -0
- package/dist/structural-rules/rules/SR010-retry-storm.js.map +1 -0
- package/dist/structural-rules/rules/SR011-event-listener-leak.d.ts +11 -0
- package/dist/structural-rules/rules/SR011-event-listener-leak.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR011-event-listener-leak.js +208 -0
- package/dist/structural-rules/rules/SR011-event-listener-leak.js.map +1 -0
- package/dist/structural-rules/rules/SR012-promise-race-leak.d.ts +11 -0
- package/dist/structural-rules/rules/SR012-promise-race-leak.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR012-promise-race-leak.js +191 -0
- package/dist/structural-rules/rules/SR012-promise-race-leak.js.map +1 -0
- package/dist/structural-rules/rules/SR013-missing-idempotency-key.d.ts +11 -0
- package/dist/structural-rules/rules/SR013-missing-idempotency-key.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR013-missing-idempotency-key.js +219 -0
- package/dist/structural-rules/rules/SR013-missing-idempotency-key.js.map +1 -0
- package/dist/structural-rules/rules/SR014-mutable-closure-async.d.ts +11 -0
- package/dist/structural-rules/rules/SR014-mutable-closure-async.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR014-mutable-closure-async.js +208 -0
- package/dist/structural-rules/rules/SR014-mutable-closure-async.js.map +1 -0
- package/dist/structural-rules/rules/SR015-dangling-abort-controller.d.ts +11 -0
- package/dist/structural-rules/rules/SR015-dangling-abort-controller.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR015-dangling-abort-controller.js +190 -0
- package/dist/structural-rules/rules/SR015-dangling-abort-controller.js.map +1 -0
- package/dist/structural-rules/rules/SR016-unsafe-json-parse.d.ts +11 -0
- package/dist/structural-rules/rules/SR016-unsafe-json-parse.d.ts.map +1 -0
- package/dist/structural-rules/rules/SR016-unsafe-json-parse.js +187 -0
- package/dist/structural-rules/rules/SR016-unsafe-json-parse.js.map +1 -0
- package/dist/structural-rules/suppressions.d.ts +43 -0
- package/dist/structural-rules/suppressions.d.ts.map +1 -0
- package/dist/structural-rules/suppressions.js +115 -0
- package/dist/structural-rules/suppressions.js.map +1 -0
- package/dist/structural-rules/types.d.ts +43 -0
- package/dist/structural-rules/types.d.ts.map +1 -0
- package/dist/structural-rules/types.js +3 -0
- package/dist/structural-rules/types.js.map +1 -0
- package/dist/utils/advisory-signals.d.ts +5 -0
- package/dist/utils/advisory-signals.d.ts.map +1 -1
- package/dist/utils/advisory-signals.js +50 -12
- package/dist/utils/advisory-signals.js.map +1 -1
- package/dist/utils/ai-debt-budget.d.ts.map +1 -1
- package/dist/utils/ai-debt-budget.js +5 -2
- package/dist/utils/ai-debt-budget.js.map +1 -1
- package/dist/utils/brain-cache.d.ts +100 -0
- package/dist/utils/brain-cache.d.ts.map +1 -0
- package/dist/utils/brain-cache.js +346 -0
- package/dist/utils/brain-cache.js.map +1 -0
- package/dist/utils/cli-json.d.ts.map +1 -1
- package/dist/utils/cli-json.js +80 -12
- package/dist/utils/cli-json.js.map +1 -1
- package/dist/utils/execution-bus.d.ts +10 -0
- package/dist/utils/execution-bus.d.ts.map +1 -1
- package/dist/utils/execution-bus.js +16 -0
- package/dist/utils/execution-bus.js.map +1 -1
- package/dist/utils/governance-provenance.d.ts +95 -0
- package/dist/utils/governance-provenance.d.ts.map +1 -0
- package/dist/utils/governance-provenance.js +187 -0
- package/dist/utils/governance-provenance.js.map +1 -0
- package/dist/utils/pilot-metrics.d.ts +46 -0
- package/dist/utils/pilot-metrics.d.ts.map +1 -0
- package/dist/utils/pilot-metrics.js +240 -0
- package/dist/utils/pilot-metrics.js.map +1 -0
- package/dist/utils/policy-compiler.d.ts +6 -0
- package/dist/utils/policy-compiler.d.ts.map +1 -1
- package/dist/utils/policy-compiler.js +20 -0
- package/dist/utils/policy-compiler.js.map +1 -1
- package/dist/utils/replay-runtime.d.ts +34 -0
- package/dist/utils/replay-runtime.d.ts.map +1 -1
- package/dist/utils/replay-runtime.js +207 -0
- package/dist/utils/replay-runtime.js.map +1 -1
- package/dist/workspace/cross-repo-graph.d.ts +111 -0
- package/dist/workspace/cross-repo-graph.d.ts.map +1 -0
- package/dist/workspace/cross-repo-graph.js +450 -0
- package/dist/workspace/cross-repo-graph.js.map +1 -0
- package/dist/workspace/federated-context.d.ts +144 -0
- package/dist/workspace/federated-context.d.ts.map +1 -0
- package/dist/workspace/federated-context.js +347 -0
- package/dist/workspace/federated-context.js.map +1 -0
- package/dist/workspace/index.d.ts +38 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +48 -0
- package/dist/workspace/index.js.map +1 -0
- package/package.json +10 -10
package/dist/commands/verify.js
CHANGED
|
@@ -67,6 +67,14 @@ 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 structural_rules_1 = require("../structural-rules");
|
|
71
|
+
const canonical_pipeline_1 = require("../governance/canonical-pipeline");
|
|
72
|
+
const structural_on_diff_1 = require("../governance/structural-on-diff");
|
|
73
|
+
const structural_policy_merge_1 = require("../governance/structural-policy-merge");
|
|
74
|
+
const telemetry_1 = require("@neurcode-ai/telemetry");
|
|
75
|
+
const governance_provenance_1 = require("../utils/governance-provenance");
|
|
76
|
+
const pilot_metrics_1 = require("../utils/pilot-metrics");
|
|
77
|
+
const explainability_1 = require("../explainability");
|
|
70
78
|
const runtime_guard_1 = require("../utils/runtime-guard");
|
|
71
79
|
const artifact_signature_1 = require("../utils/artifact-signature");
|
|
72
80
|
const policy_1 = require("@neurcode-ai/policy");
|
|
@@ -1080,10 +1088,17 @@ function toCanonicalVerifyOutput(payload) {
|
|
|
1080
1088
|
'policyDecision',
|
|
1081
1089
|
'policyPack',
|
|
1082
1090
|
'changeContractViolations',
|
|
1091
|
+
'governanceVerification',
|
|
1092
|
+
'governanceFindings',
|
|
1093
|
+
'structuralViolations',
|
|
1094
|
+
'structuralRulesApplied',
|
|
1095
|
+
'structuralSuppressedCount',
|
|
1083
1096
|
];
|
|
1097
|
+
const canonicalMutable = canonical;
|
|
1084
1098
|
for (const key of passthroughKeys) {
|
|
1085
|
-
|
|
1086
|
-
|
|
1099
|
+
const v = payload[key];
|
|
1100
|
+
if (Object.prototype.hasOwnProperty.call(payload, key) && v !== undefined && v !== null) {
|
|
1101
|
+
canonicalMutable[key] = v;
|
|
1087
1102
|
}
|
|
1088
1103
|
}
|
|
1089
1104
|
// Backward-compatibility alias: older integrations and tests expect `rule`
|
|
@@ -1099,9 +1114,31 @@ function toCanonicalVerifyOutput(payload) {
|
|
|
1099
1114
|
return canonical;
|
|
1100
1115
|
}
|
|
1101
1116
|
function emitCanonicalVerifyJson(payload, onEmit) {
|
|
1102
|
-
const canonical = toCanonicalVerifyOutput(payload);
|
|
1117
|
+
const canonical = toCanonicalVerifyOutput((0, canonical_pipeline_1.attachCanonicalGovernance)(payload));
|
|
1103
1118
|
onEmit?.(canonical);
|
|
1104
|
-
|
|
1119
|
+
// Use sync stdout write so immediate process.exit paths do not truncate JSON.
|
|
1120
|
+
const serialized = Buffer.from(`${JSON.stringify(canonical, null, 2)}\n`, 'utf-8');
|
|
1121
|
+
try {
|
|
1122
|
+
let offset = 0;
|
|
1123
|
+
while (offset < serialized.length) {
|
|
1124
|
+
try {
|
|
1125
|
+
const written = (0, fs_1.writeSync)(1, serialized, offset, serialized.length - offset);
|
|
1126
|
+
if (written <= 0)
|
|
1127
|
+
break;
|
|
1128
|
+
offset += written;
|
|
1129
|
+
}
|
|
1130
|
+
catch (error) {
|
|
1131
|
+
const code = error.code;
|
|
1132
|
+
if (code === 'EAGAIN' || code === 'EWOULDBLOCK') {
|
|
1133
|
+
continue;
|
|
1134
|
+
}
|
|
1135
|
+
throw error;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
catch {
|
|
1140
|
+
process.stdout.write(serialized.toString('utf-8'));
|
|
1141
|
+
}
|
|
1105
1142
|
}
|
|
1106
1143
|
function buildDeterministicLayerSummary(payload) {
|
|
1107
1144
|
const verdict = asStringValue(payload.verdict) || 'UNKNOWN';
|
|
@@ -1894,6 +1931,8 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
|
|
|
1894
1931
|
message: `Policy audit chain is invalid: ${auditIntegrityStatus.issues.join('; ') || 'unknown issue'}`,
|
|
1895
1932
|
});
|
|
1896
1933
|
}
|
|
1934
|
+
const policyOnlyStructural = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFilesForPolicy);
|
|
1935
|
+
(0, structural_policy_merge_1.mergeStructuralIntoPolicyViolations)(policyViolations, policyOnlyStructural.violations);
|
|
1897
1936
|
policyDecision = resolvePolicyDecisionFromViolations(policyViolations);
|
|
1898
1937
|
const effectiveVerdict = policyDecision === 'block' ? 'FAIL' : policyDecision === 'warn' ? 'WARN' : 'PASS';
|
|
1899
1938
|
const grade = effectiveVerdict === 'PASS' ? 'A' : effectiveVerdict === 'WARN' ? 'C' : 'F';
|
|
@@ -1962,6 +2001,9 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
|
|
|
1962
2001
|
plannedFilesModified: 0,
|
|
1963
2002
|
totalPlannedFiles: 0,
|
|
1964
2003
|
adherenceScore: score,
|
|
2004
|
+
structuralViolations: policyOnlyStructural.violations,
|
|
2005
|
+
structuralRulesApplied: policyOnlyStructural.rulesApplied,
|
|
2006
|
+
structuralSuppressedCount: policyOnlyStructural.suppressedCount,
|
|
1965
2007
|
mode: 'policy_only',
|
|
1966
2008
|
policyOnly: true,
|
|
1967
2009
|
policyOnlySource: source,
|
|
@@ -2045,6 +2087,8 @@ async function verifyCommand(options) {
|
|
|
2045
2087
|
const evidenceEnabled = options.evidence === true || isEnabledFlag(process.env.NEURCODE_VERIFY_EVIDENCE);
|
|
2046
2088
|
const verifyStartedAtMs = Date.now();
|
|
2047
2089
|
const evidenceCiContext = collectCIContext();
|
|
2090
|
+
/** Set when provenance is written (human path); JSON early-exit may leave null. */
|
|
2091
|
+
let lastProvenanceRunId = null;
|
|
2048
2092
|
let lastCanonicalOutput = null;
|
|
2049
2093
|
let lastEvidenceFallbackOutput = null;
|
|
2050
2094
|
let evidenceFinalizeAttempted = false;
|
|
@@ -2098,6 +2142,12 @@ async function verifyCommand(options) {
|
|
|
2098
2142
|
};
|
|
2099
2143
|
const exitWithEvidence = (exitCode) => {
|
|
2100
2144
|
finalizeEvidence(exitCode);
|
|
2145
|
+
try {
|
|
2146
|
+
(0, telemetry_1.appendVerifyCompletedFromCanonical)(projectRoot, lastCanonicalOutput, lastProvenanceRunId);
|
|
2147
|
+
}
|
|
2148
|
+
catch {
|
|
2149
|
+
// calibration must never affect exit
|
|
2150
|
+
}
|
|
2101
2151
|
process.exit(exitCode);
|
|
2102
2152
|
};
|
|
2103
2153
|
exitWithEvidenceFromTry = exitWithEvidence;
|
|
@@ -2108,6 +2158,10 @@ async function verifyCommand(options) {
|
|
|
2108
2158
|
let intentEngineSummary = null;
|
|
2109
2159
|
let intentEngineFlowIssues = [];
|
|
2110
2160
|
let intentEngineRegressions = [];
|
|
2161
|
+
// Structural rule engine results — AST-level deterministic violations
|
|
2162
|
+
let structuralViolations = [];
|
|
2163
|
+
let structuralRulesApplied = [];
|
|
2164
|
+
let structuralSuppressedCount = 0;
|
|
2111
2165
|
const emitVerifyJson = (payload) => {
|
|
2112
2166
|
const enrichedPayload = {
|
|
2113
2167
|
...payload,
|
|
@@ -2121,6 +2175,9 @@ async function verifyCommand(options) {
|
|
|
2121
2175
|
flowIssues: payload.flowIssues ?? intentEngineFlowIssues,
|
|
2122
2176
|
// V6: regressions always injected
|
|
2123
2177
|
regressions: payload.regressions ?? intentEngineRegressions,
|
|
2178
|
+
structuralViolations: payload.structuralViolations ?? structuralViolations,
|
|
2179
|
+
structuralRulesApplied: payload.structuralRulesApplied ?? structuralRulesApplied,
|
|
2180
|
+
structuralSuppressedCount: payload.structuralSuppressedCount ?? structuralSuppressedCount,
|
|
2124
2181
|
};
|
|
2125
2182
|
lastEvidenceFallbackOutput = enrichedPayload;
|
|
2126
2183
|
emitCanonicalVerifyJson(enrichedPayload, (canonical) => {
|
|
@@ -2439,10 +2496,14 @@ async function verifyCommand(options) {
|
|
|
2439
2496
|
console.log(chalk.dim(' CI mode: deterministic local verification enabled (policy-only, non-interactive).'));
|
|
2440
2497
|
}
|
|
2441
2498
|
}
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
||
|
|
2445
|
-
|
|
2499
|
+
// NEURCODE_VERIFY_LOCAL_ONLY=1 or --local-only: skip API entirely, run structural-only
|
|
2500
|
+
const localOnlyMode = isEnabledFlag(process.env.NEURCODE_VERIFY_LOCAL_ONLY)
|
|
2501
|
+
|| options.localOnly === true;
|
|
2502
|
+
const enforceCompatibilityHandshake = !localOnlyMode
|
|
2503
|
+
&& (isEnabledFlag(process.env.NEURCODE_VERIFY_ENFORCE_COMPAT_HANDSHAKE)
|
|
2504
|
+
|| strictArtifactMode
|
|
2505
|
+
|| (process.env.CI === 'true' && Boolean(config.apiKey)));
|
|
2506
|
+
if (!localOnlyMode && config.apiKey && config.apiUrl) {
|
|
2446
2507
|
const compatibilityProbe = await probeApiRuntimeCompatibility(config.apiUrl);
|
|
2447
2508
|
if (compatibilityProbe.status !== 'ok' && enforceCompatibilityHandshake) {
|
|
2448
2509
|
const failureMessages = compatibilityProbe.messages.length > 0
|
|
@@ -2471,6 +2532,7 @@ async function verifyCommand(options) {
|
|
|
2471
2532
|
mode: 'runtime_compatibility_failed',
|
|
2472
2533
|
policyOnly: options.policyOnly === true,
|
|
2473
2534
|
changeContract: changeContractSummary,
|
|
2535
|
+
offlineFallbackHint: 'Run with NEURCODE_VERIFY_LOCAL_ONLY=1 or --local-only for offline structural verification.',
|
|
2474
2536
|
...(compiledPolicyMetadata ? { policyCompilation: compiledPolicyMetadata } : {}),
|
|
2475
2537
|
});
|
|
2476
2538
|
}
|
|
@@ -2485,6 +2547,7 @@ async function verifyCommand(options) {
|
|
|
2485
2547
|
}
|
|
2486
2548
|
console.log(chalk.dim(` CLI version: ${CLI_COMPONENT_VERSION}`));
|
|
2487
2549
|
console.log(chalk.dim(' Upgrade/downgrade CLI, Action, or API to satisfy the runtime compatibility contract before running verify.\n'));
|
|
2550
|
+
console.log(chalk.dim(' Tip: Use --local-only to run offline deterministic structural verification without the API.\n'));
|
|
2488
2551
|
}
|
|
2489
2552
|
exitWithEvidence(2);
|
|
2490
2553
|
}
|
|
@@ -2704,6 +2767,62 @@ async function verifyCommand(options) {
|
|
|
2704
2767
|
const excludeOldPath = file.oldPath ? isExcludedFile(file.oldPath) : false;
|
|
2705
2768
|
return !excludePath && !excludeOldPath;
|
|
2706
2769
|
});
|
|
2770
|
+
// ── Local-only mode (Part 8): run structural analysis and exit, no API calls ──
|
|
2771
|
+
// Triggered by NEURCODE_VERIFY_LOCAL_ONLY=1 or --local-only.
|
|
2772
|
+
// Deterministic structural governance MUST work offline, with zero API dependency.
|
|
2773
|
+
if (localOnlyMode) {
|
|
2774
|
+
if (!options.json) {
|
|
2775
|
+
console.log(chalk.cyan('\n🔍 Local-only mode: deterministic structural verification (no API required)...'));
|
|
2776
|
+
}
|
|
2777
|
+
const localStructural = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFiles);
|
|
2778
|
+
const blockingViolations = localStructural.violations.filter((v) => v.severity === 'BLOCKING');
|
|
2779
|
+
const localVerdict = blockingViolations.length > 0 ? 'FAIL' : 'PASS';
|
|
2780
|
+
const localGrade = blockingViolations.length > 0 ? 'F' : 'B';
|
|
2781
|
+
const localScore = blockingViolations.length > 0 ? 0 : 70;
|
|
2782
|
+
if (options.json) {
|
|
2783
|
+
emitVerifyJson({
|
|
2784
|
+
grade: localGrade,
|
|
2785
|
+
score: localScore,
|
|
2786
|
+
verdict: localVerdict,
|
|
2787
|
+
violations: localStructural.violations.map((v) => ({
|
|
2788
|
+
file: v.filePath,
|
|
2789
|
+
rule: v.ruleId,
|
|
2790
|
+
severity: v.severity === 'BLOCKING' ? 'block' : 'warn',
|
|
2791
|
+
message: `${v.ruleName}: ${v.evidence.slice(0, 120)}`,
|
|
2792
|
+
})),
|
|
2793
|
+
adherenceScore: localScore,
|
|
2794
|
+
bloatCount: 0,
|
|
2795
|
+
bloatFiles: [],
|
|
2796
|
+
plannedFilesModified: 0,
|
|
2797
|
+
totalPlannedFiles: 0,
|
|
2798
|
+
message: `Local-only structural verification: ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking.`,
|
|
2799
|
+
scopeGuardPassed: true,
|
|
2800
|
+
mode: 'local_only_structural',
|
|
2801
|
+
policyOnly: true,
|
|
2802
|
+
structuralViolations: localStructural.violations,
|
|
2803
|
+
structuralBlockingCount: blockingViolations.length,
|
|
2804
|
+
structuralRulesApplied: localStructural.rulesApplied,
|
|
2805
|
+
changeContract: changeContractSummary,
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
else {
|
|
2809
|
+
if (localStructural.violations.length === 0) {
|
|
2810
|
+
console.log(chalk.green('\n✅ No structural violations found (local-only mode).'));
|
|
2811
|
+
}
|
|
2812
|
+
else {
|
|
2813
|
+
localStructural.violations.forEach((v) => {
|
|
2814
|
+
const prefix = v.severity === 'BLOCKING' ? chalk.red(' ⛔ BLOCKING') : chalk.yellow(' ⚠ ADVISORY');
|
|
2815
|
+
console.log(`${prefix} ${v.ruleId} — ${v.filePath}:${v.line}`);
|
|
2816
|
+
console.log(chalk.dim(` ${v.ruleName}`));
|
|
2817
|
+
console.log(chalk.dim(` ${v.evidence.slice(0, 100)}`));
|
|
2818
|
+
});
|
|
2819
|
+
}
|
|
2820
|
+
console.log(chalk.dim(`\n[Local-only] ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking. ` +
|
|
2821
|
+
`Remove --local-only for full governance verification.\n`));
|
|
2822
|
+
}
|
|
2823
|
+
recordVerifyEvent(localVerdict, `local_only;structural=${localStructural.violations.length}`, diffFiles.map((f) => f.path));
|
|
2824
|
+
exitWithEvidence(blockingViolations.length > 0 ? 2 : 0);
|
|
2825
|
+
}
|
|
2707
2826
|
const summary = (0, diff_parser_1.getDiffSummary)(diffFiles);
|
|
2708
2827
|
if (diffFiles.length === 0) {
|
|
2709
2828
|
if (!options.json) {
|
|
@@ -3102,15 +3221,50 @@ async function verifyCommand(options) {
|
|
|
3102
3221
|
summary,
|
|
3103
3222
|
});
|
|
3104
3223
|
const advisoryWarnCount = advisorySignals.filter((item) => item.severity === 'warn').length;
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3224
|
+
// ── Advisory-first: always run structural rules, downgrade scope issues to advisory ──
|
|
3225
|
+
// Structural rules are deterministic and local — they MUST always run regardless of plan.
|
|
3226
|
+
let advisoryStructuralViolations = [];
|
|
3227
|
+
let advisoryStructuralBlockingCount = 0;
|
|
3228
|
+
try {
|
|
3229
|
+
if (!options.json) {
|
|
3230
|
+
console.log(chalk.cyan('🔍 Running deterministic structural analysis (advisory mode — no plan)...'));
|
|
3231
|
+
}
|
|
3232
|
+
const structuralResult = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFiles);
|
|
3233
|
+
advisoryStructuralViolations = structuralResult.violations;
|
|
3234
|
+
// In advisory mode (no plan), BLOCKING structural violations are downgraded to advisory warnings.
|
|
3235
|
+
// They are still surfaced — engineers must review them — but they do not block the verify exit.
|
|
3236
|
+
advisoryStructuralBlockingCount = structuralResult.violations.filter((v) => v.severity === 'BLOCKING').length;
|
|
3237
|
+
if (!options.json && advisoryStructuralViolations.length > 0) {
|
|
3238
|
+
console.log(chalk.yellow(`\n⚠ Structural findings (advisory — link a plan to enable enforcement):`));
|
|
3239
|
+
advisoryStructuralViolations.forEach((v) => {
|
|
3240
|
+
const prefix = v.severity === 'BLOCKING' ? chalk.yellow(' ⚠ BLOCKING (advisory)') : chalk.dim(' ℹ ADVISORY');
|
|
3241
|
+
console.log(`${prefix} ${v.ruleId} — ${v.filePath}:${v.line}`);
|
|
3242
|
+
console.log(chalk.dim(` ${v.ruleName}`));
|
|
3243
|
+
console.log(chalk.dim(` ${v.evidence.slice(0, 100)}`));
|
|
3244
|
+
});
|
|
3245
|
+
console.log(chalk.dim(`\n To enforce these findings: run \`neurcode plan "<intent>"\` to link a plan.\n`));
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
catch {
|
|
3249
|
+
// Structural engine failure must never block advisory verify
|
|
3250
|
+
}
|
|
3251
|
+
const advisoryVerdict = advisoryWarnCount > 0 || advisoryStructuralBlockingCount > 0 ? 'WARN' : 'PASS';
|
|
3252
|
+
const advisoryGrade = advisoryWarnCount > 0 || advisoryStructuralBlockingCount > 0 ? 'C' : 'B';
|
|
3253
|
+
const advisoryScore = advisoryWarnCount > 0 || advisoryStructuralBlockingCount > 0 ? 60 : 70;
|
|
3254
|
+
const advisoryViolations = [
|
|
3255
|
+
...advisorySignals.map((item) => ({
|
|
3256
|
+
file: item.files[0] || '.',
|
|
3257
|
+
rule: `advisory:${item.code.toLowerCase()}`,
|
|
3258
|
+
severity: item.severity === 'warn' ? 'warn' : 'allow',
|
|
3259
|
+
message: `${item.title}: ${item.detail}`,
|
|
3260
|
+
})),
|
|
3261
|
+
...advisoryStructuralViolations.map((v) => ({
|
|
3262
|
+
file: v.filePath,
|
|
3263
|
+
rule: `structural-advisory:${v.ruleId.toLowerCase()}`,
|
|
3264
|
+
severity: 'warn',
|
|
3265
|
+
message: `${v.ruleId} ${v.ruleName}: ${v.evidence.slice(0, 100)} (advisory — link plan to enforce)`,
|
|
3266
|
+
})),
|
|
3267
|
+
];
|
|
3114
3268
|
recordVerifyEvent(advisoryVerdict, `advisory_missing_plan;signals=${advisorySignals.length};warn=${advisoryWarnCount}`, diffFiles.map((f) => f.path));
|
|
3115
3269
|
if (options.json) {
|
|
3116
3270
|
emitVerifyJson({
|
|
@@ -3128,6 +3282,11 @@ async function verifyCommand(options) {
|
|
|
3128
3282
|
mode: 'advisory_missing_plan',
|
|
3129
3283
|
advisoryMode: true,
|
|
3130
3284
|
advisorySignals,
|
|
3285
|
+
structuralViolations: advisoryStructuralViolations,
|
|
3286
|
+
structuralBlockingCount: advisoryStructuralBlockingCount,
|
|
3287
|
+
structuralNote: advisoryStructuralBlockingCount > 0
|
|
3288
|
+
? `${advisoryStructuralBlockingCount} structural finding(s) surfaced in advisory mode. Link a plan to enforce.`
|
|
3289
|
+
: undefined,
|
|
3131
3290
|
policyOnly: true,
|
|
3132
3291
|
policyOnlySource: 'fallback_missing_plan',
|
|
3133
3292
|
...(autoContractPath
|
|
@@ -3233,6 +3392,36 @@ async function verifyCommand(options) {
|
|
|
3233
3392
|
// Non-fatal: intent engine errors must never break verification
|
|
3234
3393
|
}
|
|
3235
3394
|
}
|
|
3395
|
+
// ── Structural Rule Engine ──────────────────────────────────────────────
|
|
3396
|
+
// AST-level deterministic analysis against changed files.
|
|
3397
|
+
// Reads file contents from disk; never throws — errors are isolated per file.
|
|
3398
|
+
if (diffFiles.length > 0) {
|
|
3399
|
+
try {
|
|
3400
|
+
const structuralEngine = (0, structural_rules_1.createDefaultStructuralRuleEngine)();
|
|
3401
|
+
const filesToAnalyze = [];
|
|
3402
|
+
for (const df of diffFiles) {
|
|
3403
|
+
const absPath = (0, path_1.join)(projectRoot, df.path);
|
|
3404
|
+
if ((0, fs_1.existsSync)(absPath)) {
|
|
3405
|
+
try {
|
|
3406
|
+
const sourceText = (0, fs_1.readFileSync)(absPath, 'utf-8');
|
|
3407
|
+
filesToAnalyze.push({ filePath: df.path, sourceText });
|
|
3408
|
+
}
|
|
3409
|
+
catch {
|
|
3410
|
+
// Skip unreadable files
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
if (filesToAnalyze.length > 0) {
|
|
3415
|
+
const structuralResult = structuralEngine.analyze(filesToAnalyze);
|
|
3416
|
+
structuralViolations = structuralResult.violations;
|
|
3417
|
+
structuralRulesApplied = structuralResult.rulesApplied;
|
|
3418
|
+
structuralSuppressedCount = structuralResult.suppressedCount;
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
catch {
|
|
3422
|
+
// Non-fatal: structural engine errors must never break verification
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3236
3425
|
governanceResult = (0, governance_1.evaluateGovernance)({
|
|
3237
3426
|
projectRoot,
|
|
3238
3427
|
task: governanceTask,
|
|
@@ -3782,6 +3971,7 @@ async function verifyCommand(options) {
|
|
|
3782
3971
|
message: `Policy audit chain is invalid: ${auditIntegrityStatus.issues.join('; ') || 'unknown issue'}`,
|
|
3783
3972
|
});
|
|
3784
3973
|
}
|
|
3974
|
+
(0, structural_policy_merge_1.mergeStructuralIntoPolicyViolations)(policyViolations, structuralViolations);
|
|
3785
3975
|
policyDecision = resolvePolicyDecisionFromViolations(policyViolations);
|
|
3786
3976
|
const policyExceptionsSummary = {
|
|
3787
3977
|
sourceMode: policyExceptionResolution.mode,
|
|
@@ -4229,6 +4419,9 @@ async function verifyCommand(options) {
|
|
|
4229
4419
|
plannedFilesModified: verifyResult.plannedFilesModified,
|
|
4230
4420
|
totalPlannedFiles: verifyResult.totalPlannedFiles,
|
|
4231
4421
|
verificationSource: verifySource,
|
|
4422
|
+
structuralViolations,
|
|
4423
|
+
structuralRulesApplied,
|
|
4424
|
+
structuralSuppressedCount,
|
|
4232
4425
|
mode: 'plan_enforced',
|
|
4233
4426
|
policyOnly: false,
|
|
4234
4427
|
aiDebt: aiDebtSummary,
|
|
@@ -4300,7 +4493,7 @@ async function verifyCommand(options) {
|
|
|
4300
4493
|
message: effectiveMessage,
|
|
4301
4494
|
bloatFiles: displayBloatFiles,
|
|
4302
4495
|
bloatCount: displayBloatFiles.length,
|
|
4303
|
-
}, policyViolations, expediteModeEnabled, intentEngineIssues, intentEngineSummary, intentEngineFlowIssues, intentEngineRegressions);
|
|
4496
|
+
}, policyViolations, expediteModeEnabled, intentEngineIssues, intentEngineSummary, intentEngineFlowIssues, intentEngineRegressions, structuralViolations);
|
|
4304
4497
|
if (governanceResult) {
|
|
4305
4498
|
displayGovernanceInsights(governanceResult, { explain: options.explain });
|
|
4306
4499
|
}
|
|
@@ -4364,6 +4557,58 @@ async function verifyCommand(options) {
|
|
|
4364
4557
|
}
|
|
4365
4558
|
}
|
|
4366
4559
|
}
|
|
4560
|
+
// ── Governance Provenance Chain + Pilot Metrics ───────────────────────
|
|
4561
|
+
// Best-effort: never throws, never changes the verification outcome.
|
|
4562
|
+
try {
|
|
4563
|
+
const structuralBlocking = structuralViolations.filter(v => v.severity === 'BLOCKING').length;
|
|
4564
|
+
const structuralAdvisory = structuralViolations.filter(v => v.severity === 'ADVISORY').length;
|
|
4565
|
+
const deterministicSigs = structuralViolations.filter(v => v.determinism === 'deterministic-structural').length;
|
|
4566
|
+
const heuristicSigs = structuralViolations.filter(v => v.determinism === 'heuristic-advisory').length;
|
|
4567
|
+
const trustScore = structuralViolations.length > 0
|
|
4568
|
+
? Math.round((deterministicSigs / structuralViolations.length) * 100)
|
|
4569
|
+
: 100;
|
|
4570
|
+
const prov = (0, governance_provenance_1.buildProvenanceRecord)({
|
|
4571
|
+
repoRoot: projectRoot,
|
|
4572
|
+
filesAnalyzed: diffFiles.length,
|
|
4573
|
+
diffContext: `${options.base || 'HEAD'} vs working tree`,
|
|
4574
|
+
planId: finalPlanId || null,
|
|
4575
|
+
intentHash: null,
|
|
4576
|
+
policyHash: null,
|
|
4577
|
+
ruleIds: structuralRulesApplied,
|
|
4578
|
+
blockingCount: policyViolations.filter((v) => v.severity === 'block').length + structuralBlocking,
|
|
4579
|
+
advisoryCount: policyViolations.filter((v) => v.severity !== 'block').length + structuralAdvisory,
|
|
4580
|
+
suppressedCount: structuralSuppressedCount,
|
|
4581
|
+
structuralBlockingCount: structuralBlocking,
|
|
4582
|
+
structuralAdvisoryCount: structuralAdvisory,
|
|
4583
|
+
deterministicSignals: deterministicSigs,
|
|
4584
|
+
heuristicSignals: heuristicSigs,
|
|
4585
|
+
overallTrustScore: trustScore,
|
|
4586
|
+
verdict: effectiveVerdict,
|
|
4587
|
+
governanceDecision: governanceResult?.governanceDecision?.summary || 'automatic',
|
|
4588
|
+
});
|
|
4589
|
+
(0, governance_provenance_1.saveProvenanceRecord)(projectRoot, prov);
|
|
4590
|
+
lastProvenanceRunId = prov.runId;
|
|
4591
|
+
// Tally per-rule counts for pilot metrics
|
|
4592
|
+
const ruleCounts = {};
|
|
4593
|
+
for (const v of structuralViolations) {
|
|
4594
|
+
ruleCounts[v.ruleId] = (ruleCounts[v.ruleId] ?? 0) + 1;
|
|
4595
|
+
}
|
|
4596
|
+
(0, pilot_metrics_1.recordVerifyRun)(projectRoot, {
|
|
4597
|
+
planCount: 0,
|
|
4598
|
+
verifyCount: 1,
|
|
4599
|
+
passCount: effectiveVerdict === 'PASS' ? 1 : 0,
|
|
4600
|
+
failCount: effectiveVerdict === 'FAIL' ? 1 : 0,
|
|
4601
|
+
blockingCaught: prov.blockingCount,
|
|
4602
|
+
advisoryCaught: prov.advisoryCount,
|
|
4603
|
+
suppressions: structuralSuppressedCount,
|
|
4604
|
+
structuralCaught: structuralViolations.length,
|
|
4605
|
+
aiDebtDelta: aiDebtSummary?.score ?? 0,
|
|
4606
|
+
ruleCounts,
|
|
4607
|
+
});
|
|
4608
|
+
}
|
|
4609
|
+
catch {
|
|
4610
|
+
// Never break verification
|
|
4611
|
+
}
|
|
4367
4612
|
// Report to Neurcode Cloud if --record flag is set
|
|
4368
4613
|
const filteredBloatForReport = (verifyResult.bloatFiles || []).filter((f) => !shouldIgnore(f));
|
|
4369
4614
|
const reportViolations = [
|
|
@@ -4833,7 +5078,7 @@ function displayChangeContractDrift(summary, options = { advisory: false }) {
|
|
|
4833
5078
|
/**
|
|
4834
5079
|
* Display verification results in a formatted report card
|
|
4835
5080
|
*/
|
|
4836
|
-
function displayVerifyResults(result, policyViolations, expediteModeUsed = false, intentIssuesForDisplay = [], intentSummaryForDisplay = null, flowIssuesForDisplay = [], regressionsForDisplay = []) {
|
|
5081
|
+
function displayVerifyResults(result, policyViolations, expediteModeUsed = false, intentIssuesForDisplay = [], intentSummaryForDisplay = null, flowIssuesForDisplay = [], regressionsForDisplay = [], structuralViolationsForDisplay = []) {
|
|
4837
5082
|
// ── Header ────────────────────────────────────────────────────────────────
|
|
4838
5083
|
const headerLabel = result.verdict === 'PASS'
|
|
4839
5084
|
? chalk.bold.green('\n✅ VERIFICATION PASSED')
|
|
@@ -4915,6 +5160,19 @@ function displayVerifyResults(result, policyViolations, expediteModeUsed = false
|
|
|
4915
5160
|
policy: item.rule || 'policy_violation',
|
|
4916
5161
|
severity: item.severity,
|
|
4917
5162
|
}));
|
|
5163
|
+
// Structural rule violations — split by severity
|
|
5164
|
+
const structuralBlocking = structuralViolationsForDisplay
|
|
5165
|
+
.filter((v) => v.severity === 'BLOCKING')
|
|
5166
|
+
.map((v) => ({
|
|
5167
|
+
file: v.filePath,
|
|
5168
|
+
message: `${v.ruleId} · ${v.ruleName} (line ${v.line}) — ${v.operationalRisk}`,
|
|
5169
|
+
}));
|
|
5170
|
+
const structuralAdvisory = structuralViolationsForDisplay
|
|
5171
|
+
.filter((v) => v.severity === 'ADVISORY')
|
|
5172
|
+
.map((v) => ({
|
|
5173
|
+
file: v.filePath,
|
|
5174
|
+
message: `${v.ruleId} · ${v.ruleName} (line ${v.line}) — ${v.operationalRisk}`,
|
|
5175
|
+
}));
|
|
4918
5176
|
let blockingItems = [
|
|
4919
5177
|
...scopeItems.map((item) => ({
|
|
4920
5178
|
file: item.file,
|
|
@@ -4926,13 +5184,17 @@ function displayVerifyResults(result, policyViolations, expediteModeUsed = false
|
|
|
4926
5184
|
file: item.file,
|
|
4927
5185
|
message: item.message,
|
|
4928
5186
|
})),
|
|
5187
|
+
...structuralBlocking,
|
|
5188
|
+
];
|
|
5189
|
+
let advisoryItems = [
|
|
5190
|
+
...policyTriageItems
|
|
5191
|
+
.filter((item) => !isBlockingSeverity(item.severity))
|
|
5192
|
+
.map((item) => ({
|
|
5193
|
+
file: item.file,
|
|
5194
|
+
message: item.message,
|
|
5195
|
+
})),
|
|
5196
|
+
...structuralAdvisory,
|
|
4929
5197
|
];
|
|
4930
|
-
let advisoryItems = policyTriageItems
|
|
4931
|
-
.filter((item) => !isBlockingSeverity(item.severity))
|
|
4932
|
-
.map((item) => ({
|
|
4933
|
-
file: item.file,
|
|
4934
|
-
message: item.message,
|
|
4935
|
-
}));
|
|
4936
5198
|
let expediteItems = [];
|
|
4937
5199
|
if (expediteModeUsed) {
|
|
4938
5200
|
blockingItems = [
|
|
@@ -5044,6 +5306,49 @@ function displayVerifyResults(result, policyViolations, expediteModeUsed = false
|
|
|
5044
5306
|
});
|
|
5045
5307
|
console.log(chalk.bold.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
5046
5308
|
}
|
|
5309
|
+
// ── Structural Rule Engine ─────────────────────────────────────────────────
|
|
5310
|
+
// Display detailed structural violations with AST evidence and determinism labels.
|
|
5311
|
+
if (structuralViolationsForDisplay.length > 0) {
|
|
5312
|
+
try {
|
|
5313
|
+
const report = (0, explainability_1.buildViolationReport)(structuralViolationsForDisplay, '');
|
|
5314
|
+
const formatter = new explainability_1.ViolationFormatter();
|
|
5315
|
+
const blocking = report.blocking;
|
|
5316
|
+
const advisory = report.advisory;
|
|
5317
|
+
if (blocking.length > 0 || advisory.length > 0) {
|
|
5318
|
+
console.log(chalk.bold('\n━━━ STRUCTURAL ANALYSIS ━━━━━━━━━━━━━━━━━'));
|
|
5319
|
+
blocking.slice(0, 5).forEach((v) => {
|
|
5320
|
+
const detLabel = v.determinism === 'deterministic-structural'
|
|
5321
|
+
? chalk.cyan('⚙ AST-verified')
|
|
5322
|
+
: chalk.yellow('⚡ heuristic');
|
|
5323
|
+
console.log(chalk.red(`\n ● ${v.ruleId} [BLOCKING] ${detLabel} · confidence ${Math.round(v.confidence * 100)}%`));
|
|
5324
|
+
console.log(chalk.bold(` ${v.filePath}:${v.line}`));
|
|
5325
|
+
console.log(chalk.dim(` Pattern: ${v.evidence.matchReason}`));
|
|
5326
|
+
if (v.evidence.codeSnippet) {
|
|
5327
|
+
console.log(chalk.dim(` Code: ${v.evidence.codeSnippet.slice(0, 100)}`));
|
|
5328
|
+
}
|
|
5329
|
+
console.log(chalk.yellow(` Risk: ${v.operationalRisk}`));
|
|
5330
|
+
console.log(chalk.green(` Fix: ${v.remediation}`));
|
|
5331
|
+
});
|
|
5332
|
+
if (blocking.length > 5) {
|
|
5333
|
+
console.log(chalk.dim(`\n ... ${blocking.length - 5} more blocking structural violations`));
|
|
5334
|
+
}
|
|
5335
|
+
advisory.slice(0, 3).forEach((v) => {
|
|
5336
|
+
console.log(chalk.yellow(`\n ○ ${v.ruleId} [ADVISORY] ⚡ heuristic · confidence ${Math.round(v.confidence * 100)}%`));
|
|
5337
|
+
console.log(chalk.dim(` ${v.filePath}:${v.line} — ${v.operationalRisk}`));
|
|
5338
|
+
});
|
|
5339
|
+
if (advisory.length > 3) {
|
|
5340
|
+
console.log(chalk.dim(` ... ${advisory.length - 3} more advisory structural violations`));
|
|
5341
|
+
}
|
|
5342
|
+
const deterministicCount = report.deterministicCount;
|
|
5343
|
+
const heuristicCount = report.heuristicCount;
|
|
5344
|
+
console.log(chalk.dim(`\n Determinism: ${deterministicCount} AST-verified · ${heuristicCount} heuristic`));
|
|
5345
|
+
console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
catch {
|
|
5349
|
+
// Non-fatal: explainability rendering must never break verification display
|
|
5350
|
+
}
|
|
5351
|
+
}
|
|
5047
5352
|
const hasAnyIssue = blockingItems.length > 0 ||
|
|
5048
5353
|
advisoryItems.length > 0 ||
|
|
5049
5354
|
expediteItems.length > 0 ||
|
|
@@ -5084,6 +5389,12 @@ function printAdvisorySignals(signals, demoMode) {
|
|
|
5084
5389
|
const severityLabel = signal.severity === 'warn' ? chalk.yellow('[warn]') : chalk.dim('[info]');
|
|
5085
5390
|
console.log(`${severityLabel} ${signal.title}`);
|
|
5086
5391
|
console.log(chalk.dim(` ${signal.detail}`));
|
|
5392
|
+
console.log(chalk.dim(` Confidence: ${signal.confidence.toUpperCase()} (advisory-only)`));
|
|
5393
|
+
if (signal.evidence.length > 0) {
|
|
5394
|
+
console.log(chalk.dim(` Evidence: ${signal.evidence.join(', ')}`));
|
|
5395
|
+
}
|
|
5396
|
+
console.log(chalk.dim(` Structural gap: ${signal.structuralCoverageGap}`));
|
|
5397
|
+
console.log(chalk.dim(` Uncertainty: ${signal.uncertainty}`));
|
|
5087
5398
|
signal.files.forEach((file) => {
|
|
5088
5399
|
console.log(chalk.dim(` - ${file}`));
|
|
5089
5400
|
});
|