@neurcode-ai/cli 0.10.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.telemetry-bundle/dist/contracts.d.ts +1 -1
- package/README.md +74 -25
- package/dist/commands/governance.d.ts.map +1 -1
- package/dist/commands/governance.js +12 -0
- package/dist/commands/governance.js.map +1 -1
- package/dist/commands/home.d.ts +21 -0
- package/dist/commands/home.d.ts.map +1 -0
- package/dist/commands/home.js +253 -0
- package/dist/commands/home.js.map +1 -0
- package/dist/commands/login.js +1 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/quickstart.d.ts.map +1 -1
- package/dist/commands/quickstart.js +13 -11
- package/dist/commands/quickstart.js.map +1 -1
- package/dist/commands/remediate-export.d.ts.map +1 -1
- package/dist/commands/remediate-export.js +17 -2
- package/dist/commands/remediate-export.js.map +1 -1
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +36 -0
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/verify-output.d.ts.map +1 -1
- package/dist/commands/verify-output.js +88 -4
- package/dist/commands/verify-output.js.map +1 -1
- package/dist/commands/verify.d.ts +22 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +467 -37
- package/dist/commands/verify.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +4 -0
- package/dist/daemon/server.js.map +1 -1
- package/dist/governance/canonical-pipeline.d.ts.map +1 -1
- package/dist/governance/canonical-pipeline.js +29 -3
- package/dist/governance/canonical-pipeline.js.map +1 -1
- package/dist/governance/intent/drift-detector.d.ts +100 -0
- package/dist/governance/intent/drift-detector.d.ts.map +1 -0
- package/dist/governance/intent/drift-detector.js +275 -0
- package/dist/governance/intent/drift-detector.js.map +1 -0
- package/dist/governance/intent/glob-match.d.ts +43 -0
- package/dist/governance/intent/glob-match.d.ts.map +1 -0
- package/dist/governance/intent/glob-match.js +108 -0
- package/dist/governance/intent/glob-match.js.map +1 -0
- package/dist/governance/intent/import-graph.d.ts +56 -0
- package/dist/governance/intent/import-graph.d.ts.map +1 -0
- package/dist/governance/intent/import-graph.js +133 -0
- package/dist/governance/intent/import-graph.js.map +1 -0
- package/dist/governance/intent/index.d.ts +23 -0
- package/dist/governance/intent/index.d.ts.map +1 -0
- package/dist/governance/intent/index.js +48 -0
- package/dist/governance/intent/index.js.map +1 -0
- package/dist/governance/intent/intelligence-boundaries.d.ts +69 -0
- package/dist/governance/intent/intelligence-boundaries.d.ts.map +1 -0
- package/dist/governance/intent/intelligence-boundaries.js +163 -0
- package/dist/governance/intent/intelligence-boundaries.js.map +1 -0
- package/dist/governance/intent/intent-contract.d.ts +76 -0
- package/dist/governance/intent/intent-contract.d.ts.map +1 -0
- package/dist/governance/intent/intent-contract.js +397 -0
- package/dist/governance/intent/intent-contract.js.map +1 -0
- package/dist/governance/intent/intent-graph.d.ts +135 -0
- package/dist/governance/intent/intent-graph.d.ts.map +1 -0
- package/dist/governance/intent/intent-graph.js +67 -0
- package/dist/governance/intent/intent-graph.js.map +1 -0
- package/dist/governance/pipeline/computation-trace.d.ts +52 -0
- package/dist/governance/pipeline/computation-trace.d.ts.map +1 -0
- package/dist/governance/pipeline/computation-trace.js +79 -0
- package/dist/governance/pipeline/computation-trace.js.map +1 -0
- package/dist/governance/pipeline/envelope-assembly.d.ts +132 -0
- package/dist/governance/pipeline/envelope-assembly.d.ts.map +1 -0
- package/dist/governance/pipeline/envelope-assembly.js +140 -0
- package/dist/governance/pipeline/envelope-assembly.js.map +1 -0
- package/dist/governance/pipeline/fingerprint.d.ts +34 -0
- package/dist/governance/pipeline/fingerprint.d.ts.map +1 -0
- package/dist/governance/pipeline/fingerprint.js +78 -0
- package/dist/governance/pipeline/fingerprint.js.map +1 -0
- package/dist/governance/pipeline/helpers.d.ts +74 -0
- package/dist/governance/pipeline/helpers.d.ts.map +1 -0
- package/dist/governance/pipeline/helpers.js +112 -0
- package/dist/governance/pipeline/helpers.js.map +1 -0
- package/dist/governance/pipeline/index.d.ts +27 -0
- package/dist/governance/pipeline/index.d.ts.map +1 -0
- package/dist/governance/pipeline/index.js +63 -0
- package/dist/governance/pipeline/index.js.map +1 -0
- package/dist/governance/pipeline/lineage.d.ts +26 -0
- package/dist/governance/pipeline/lineage.d.ts.map +1 -0
- package/dist/governance/pipeline/lineage.js +51 -0
- package/dist/governance/pipeline/lineage.js.map +1 -0
- package/dist/governance/pipeline/orchestration/advisory-mode-contract.d.ts +15 -0
- package/dist/governance/pipeline/orchestration/advisory-mode-contract.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/advisory-mode-contract.js +44 -0
- package/dist/governance/pipeline/orchestration/advisory-mode-contract.js.map +1 -0
- package/dist/governance/pipeline/orchestration/advisory-mode.d.ts +102 -0
- package/dist/governance/pipeline/orchestration/advisory-mode.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/advisory-mode.js +170 -0
- package/dist/governance/pipeline/orchestration/advisory-mode.js.map +1 -0
- package/dist/governance/pipeline/orchestration/evidence-lifecycle.d.ts +133 -0
- package/dist/governance/pipeline/orchestration/evidence-lifecycle.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/evidence-lifecycle.js +125 -0
- package/dist/governance/pipeline/orchestration/evidence-lifecycle.js.map +1 -0
- package/dist/governance/pipeline/orchestration/index.d.ts +16 -0
- package/dist/governance/pipeline/orchestration/index.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/index.js +30 -0
- package/dist/governance/pipeline/orchestration/index.js.map +1 -0
- package/dist/governance/pipeline/orchestration/intent-drift-orchestration.d.ts +65 -0
- package/dist/governance/pipeline/orchestration/intent-drift-orchestration.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/intent-drift-orchestration.js +102 -0
- package/dist/governance/pipeline/orchestration/intent-drift-orchestration.js.map +1 -0
- package/dist/governance/pipeline/orchestration/plan-structural-analysis.d.ts +41 -0
- package/dist/governance/pipeline/orchestration/plan-structural-analysis.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/plan-structural-analysis.js +74 -0
- package/dist/governance/pipeline/orchestration/plan-structural-analysis.js.map +1 -0
- package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.d.ts +165 -0
- package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.js +160 -0
- package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.js.map +1 -0
- package/dist/governance/pipeline/orchestration/scope-guard-orchestration.d.ts +152 -0
- package/dist/governance/pipeline/orchestration/scope-guard-orchestration.d.ts.map +1 -0
- package/dist/governance/pipeline/orchestration/scope-guard-orchestration.js +188 -0
- package/dist/governance/pipeline/orchestration/scope-guard-orchestration.js.map +1 -0
- package/dist/governance/pipeline/runtime.d.ts +70 -0
- package/dist/governance/pipeline/runtime.d.ts.map +1 -0
- package/dist/governance/pipeline/runtime.js +223 -0
- package/dist/governance/pipeline/runtime.js.map +1 -0
- package/dist/governance/pipeline/shared-types.d.ts +7 -0
- package/dist/governance/pipeline/shared-types.d.ts.map +1 -0
- package/dist/governance/pipeline/shared-types.js +7 -0
- package/dist/governance/pipeline/shared-types.js.map +1 -0
- package/dist/governance/pipeline/stages/compiled-policy-stage.d.ts +28 -0
- package/dist/governance/pipeline/stages/compiled-policy-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/compiled-policy-stage.js +53 -0
- package/dist/governance/pipeline/stages/compiled-policy-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/diff-normalization-stage.d.ts +63 -0
- package/dist/governance/pipeline/stages/diff-normalization-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/diff-normalization-stage.js +140 -0
- package/dist/governance/pipeline/stages/diff-normalization-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/governance-synthesis-stage.d.ts +53 -0
- package/dist/governance/pipeline/stages/governance-synthesis-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/governance-synthesis-stage.js +129 -0
- package/dist/governance/pipeline/stages/governance-synthesis-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/index.d.ts +29 -0
- package/dist/governance/pipeline/stages/index.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/index.js +40 -0
- package/dist/governance/pipeline/stages/index.js.map +1 -0
- package/dist/governance/pipeline/stages/policy-lock-stage.d.ts +31 -0
- package/dist/governance/pipeline/stages/policy-lock-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/policy-lock-stage.js +71 -0
- package/dist/governance/pipeline/stages/policy-lock-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/runtime-guard-stage.d.ts +29 -0
- package/dist/governance/pipeline/stages/runtime-guard-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/runtime-guard-stage.js +65 -0
- package/dist/governance/pipeline/stages/runtime-guard-stage.js.map +1 -0
- package/dist/governance/pipeline/stages/structural-analysis-stage.d.ts +24 -0
- package/dist/governance/pipeline/stages/structural-analysis-stage.d.ts.map +1 -0
- package/dist/governance/pipeline/stages/structural-analysis-stage.js +58 -0
- package/dist/governance/pipeline/stages/structural-analysis-stage.js.map +1 -0
- package/dist/governance/pipeline/summary.d.ts +14 -0
- package/dist/governance/pipeline/summary.d.ts.map +1 -0
- package/dist/governance/pipeline/summary.js +50 -0
- package/dist/governance/pipeline/summary.js.map +1 -0
- package/dist/governance/pipeline/types.d.ts +69 -0
- package/dist/governance/pipeline/types.d.ts.map +1 -0
- package/dist/governance/pipeline/types.js +30 -0
- package/dist/governance/pipeline/types.js.map +1 -0
- package/dist/index.js +44 -3
- package/dist/index.js.map +1 -1
- package/dist/utils/active-engineering-context.d.ts +16 -0
- package/dist/utils/active-engineering-context.d.ts.map +1 -1
- package/dist/utils/active-engineering-context.js +302 -0
- package/dist/utils/active-engineering-context.js.map +1 -1
- package/dist/utils/import-edge-classifier.d.ts +76 -0
- package/dist/utils/import-edge-classifier.d.ts.map +1 -0
- package/dist/utils/import-edge-classifier.js +308 -0
- package/dist/utils/import-edge-classifier.js.map +1 -0
- package/dist/utils/import-edge-extractor.d.ts +52 -0
- package/dist/utils/import-edge-extractor.d.ts.map +1 -0
- package/dist/utils/import-edge-extractor.js +223 -0
- package/dist/utils/import-edge-extractor.js.map +1 -0
- package/dist/utils/import-edge-governance.d.ts +37 -0
- package/dist/utils/import-edge-governance.d.ts.map +1 -0
- package/dist/utils/import-edge-governance.js +56 -0
- package/dist/utils/import-edge-governance.js.map +1 -0
- package/dist/utils/messages.d.ts.map +1 -1
- package/dist/utils/messages.js +19 -10
- package/dist/utils/messages.js.map +1 -1
- package/dist/utils/path-boundary-classifier.d.ts +42 -0
- package/dist/utils/path-boundary-classifier.d.ts.map +1 -0
- package/dist/utils/path-boundary-classifier.js +143 -0
- package/dist/utils/path-boundary-classifier.js.map +1 -0
- package/dist/utils/replay-html-report.d.ts +29 -0
- package/dist/utils/replay-html-report.d.ts.map +1 -0
- package/dist/utils/replay-html-report.js +309 -0
- package/dist/utils/replay-html-report.js.map +1 -0
- package/dist/utils/runtime-state.d.ts +44 -0
- package/dist/utils/runtime-state.d.ts.map +1 -0
- package/dist/utils/runtime-state.js +151 -0
- package/dist/utils/runtime-state.js.map +1 -0
- package/package.json +3 -3
- package/dist/utils/box.d.ts +0 -16
- package/dist/utils/box.d.ts.map +0 -1
- package/dist/utils/box.js +0 -85
- package/dist/utils/box.js.map +0 -1
package/dist/commands/verify.js
CHANGED
|
@@ -2,7 +2,20 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Verify Command
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Runs deterministic operational governance against the current diff:
|
|
6
|
+
* - Intent contract enforcement (approved scope + forbidden boundaries)
|
|
7
|
+
* - Structural rules (PY/SR/DS catalogues)
|
|
8
|
+
* - Drift narrative synthesis + governance posture rollup
|
|
9
|
+
* - Generated-code spillover + boundary classification
|
|
10
|
+
* - Replay continuity (canonical replay checksum, byte-stable per inputs)
|
|
11
|
+
*
|
|
12
|
+
* Emits a single canonical envelope plus a `runtimeCapabilities` declaration so
|
|
13
|
+
* enterprise CI gates can assert what actually executed instead of inferring
|
|
14
|
+
* from absent fields. The command is the verification step in the canonical
|
|
15
|
+
* governance lifecycle; remediation is performed by an external AI assistant,
|
|
16
|
+
* never by this command.
|
|
17
|
+
*
|
|
18
|
+
* See `docs/governance-vocabulary.md` for canonical terminology.
|
|
6
19
|
*/
|
|
7
20
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
21
|
if (k2 === undefined) k2 = k;
|
|
@@ -52,6 +65,7 @@ const fs_1 = require("fs");
|
|
|
52
65
|
const state_1 = require("../utils/state");
|
|
53
66
|
const ROILogger_1 = require("../utils/ROILogger");
|
|
54
67
|
const ignore_1 = require("../utils/ignore");
|
|
68
|
+
const runtime_state_1 = require("../utils/runtime-state");
|
|
55
69
|
const project_root_1 = require("../utils/project-root");
|
|
56
70
|
const brain_context_1 = require("../utils/brain-context");
|
|
57
71
|
const scope_telemetry_1 = require("../utils/scope-telemetry");
|
|
@@ -85,6 +99,9 @@ const runtime_guard_1 = require("../utils/runtime-guard");
|
|
|
85
99
|
const artifact_signature_1 = require("../utils/artifact-signature");
|
|
86
100
|
const policy_1 = require("@neurcode-ai/policy");
|
|
87
101
|
const active_engineering_context_1 = require("../utils/active-engineering-context");
|
|
102
|
+
const core_1 = require("@neurcode-ai/core");
|
|
103
|
+
const path_boundary_classifier_1 = require("../utils/path-boundary-classifier");
|
|
104
|
+
const import_edge_governance_1 = require("../utils/import-edge-governance");
|
|
88
105
|
const ai_debt_budget_1 = require("../utils/ai-debt-budget");
|
|
89
106
|
const verification_evidence_1 = require("../utils/verification-evidence");
|
|
90
107
|
const verify_runtime_stability_1 = require("../utils/verify-runtime-stability");
|
|
@@ -1715,6 +1732,20 @@ async function verifyCommand(options) {
|
|
|
1715
1732
|
console.log(chalk.yellow(`\n⚠️ Failed to write verification evidence artifact: ${message}`));
|
|
1716
1733
|
}
|
|
1717
1734
|
}
|
|
1735
|
+
// Mirror the canonical envelope into `.neurcode/last-verify-output.json`
|
|
1736
|
+
// so downstream commands (`remediate-export`, `replay --html`) can pick
|
|
1737
|
+
// up the latest run without the user threading paths through stdout
|
|
1738
|
+
// redirection. Closes deep-OSS validation §5.8.
|
|
1739
|
+
try {
|
|
1740
|
+
if (lastCanonicalOutput) {
|
|
1741
|
+
const verifyOutputPath = require('path').resolve(projectRoot, '.neurcode/last-verify-output.json');
|
|
1742
|
+
require('fs').mkdirSync(require('path').dirname(verifyOutputPath), { recursive: true });
|
|
1743
|
+
require('fs').writeFileSync(verifyOutputPath, `${JSON.stringify(lastCanonicalOutput, null, 2)}\n`, 'utf-8');
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
catch {
|
|
1747
|
+
// Persisting the canonical output is best-effort; never block exit.
|
|
1748
|
+
}
|
|
1718
1749
|
};
|
|
1719
1750
|
const exitWithEvidence = (exitCode) => {
|
|
1720
1751
|
finalizeEvidence(exitCode);
|
|
@@ -2286,6 +2317,17 @@ async function verifyCommand(options) {
|
|
|
2286
2317
|
// Determine which diff to capture.
|
|
2287
2318
|
let diffText;
|
|
2288
2319
|
let diffContextLabel = '';
|
|
2320
|
+
// Operational lifecycle guardrail: when the diff context requires a
|
|
2321
|
+
// HEAD reference but the repo has no initial commit yet, surface
|
|
2322
|
+
// structured guidance instead of leaking raw git stderr. (See
|
|
2323
|
+
// docs/ux/lifecycle-state-audit.md §"no-head-commit".)
|
|
2324
|
+
if (options.head || options.staged || !options.base) {
|
|
2325
|
+
const lifecycleState = (0, runtime_state_1.detectRuntimeState)(projectRoot);
|
|
2326
|
+
if (lifecycleState.isGitRepo && !lifecycleState.hasHeadCommit) {
|
|
2327
|
+
const exitCode = (0, runtime_state_1.renderRuntimeStateGuidance)('no-head-commit', lifecycleState, { commandLabel: 'neurcode verify' });
|
|
2328
|
+
process.exit(exitCode);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2289
2331
|
if (options.staged) {
|
|
2290
2332
|
diffText = (0, child_process_1.execSync)('git diff --cached', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
|
|
2291
2333
|
diffContextLabel = 'staged changes';
|
|
@@ -2323,6 +2365,11 @@ async function verifyCommand(options) {
|
|
|
2323
2365
|
console.log(chalk.dim(' Tip: Ensure changes are staged or run against a base branch.'));
|
|
2324
2366
|
}
|
|
2325
2367
|
else {
|
|
2368
|
+
// Surface runtime capabilities even on the empty-diff path so
|
|
2369
|
+
// CI gates that assert `runtimeCapabilities.intentRuntime` etc.
|
|
2370
|
+
// never receive a payload that omits the envelope. The intent
|
|
2371
|
+
// runtime is reported as `inactive` here regardless of whether
|
|
2372
|
+
// an intent-pack exists — there are no findings to govern.
|
|
2326
2373
|
emitVerifyJson({
|
|
2327
2374
|
grade: 'F',
|
|
2328
2375
|
score: 0,
|
|
@@ -2335,6 +2382,24 @@ async function verifyCommand(options) {
|
|
|
2335
2382
|
totalPlannedFiles: 0,
|
|
2336
2383
|
message: 'No changes detected in current diff context.',
|
|
2337
2384
|
scopeGuardPassed: false,
|
|
2385
|
+
runtimeCapabilities: {
|
|
2386
|
+
schemaVersion: 'neurcode.runtime-capabilities.v1',
|
|
2387
|
+
executionPath: localOnlyMode ? 'local-only' : 'unresolved',
|
|
2388
|
+
intentRuntime: 'inactive',
|
|
2389
|
+
intentContractSource: 'none',
|
|
2390
|
+
intentRuntimeRequired: options.requireIntentRuntime === true || isEnabledFlag(process.env.NEURCODE_REQUIRE_INTENT_RUNTIME),
|
|
2391
|
+
intentRuntimeRequirementSatisfied: true,
|
|
2392
|
+
driftIntelligence: 'inactive',
|
|
2393
|
+
scopeGuard: 'unenforced',
|
|
2394
|
+
forbiddenBoundaryEnforcement: 'unenforced',
|
|
2395
|
+
generatedCodeGovernance: 'pattern-deterministic',
|
|
2396
|
+
structuralRules: 'inactive',
|
|
2397
|
+
replayDeterminism: 'enforced',
|
|
2398
|
+
apiContractStatus: localOnlyMode ? 'offline' : 'unresolved',
|
|
2399
|
+
observedScopeCategories: [],
|
|
2400
|
+
observedBoundaryTypes: [],
|
|
2401
|
+
noChangesDetected: true,
|
|
2402
|
+
},
|
|
2338
2403
|
});
|
|
2339
2404
|
}
|
|
2340
2405
|
recordVerifyEvent('NO_CHANGES', 'diff=empty');
|
|
@@ -2353,11 +2418,17 @@ async function verifyCommand(options) {
|
|
|
2353
2418
|
}
|
|
2354
2419
|
}
|
|
2355
2420
|
// Filter out internal/system files before analysis
|
|
2356
|
-
// This prevents self-interference where the tool flags its own files as bloat
|
|
2421
|
+
// This prevents self-interference where the tool flags its own files as bloat.
|
|
2422
|
+
// Two layers:
|
|
2423
|
+
// 1. `isExcludedFile` — built-in policy/governance artifact patterns
|
|
2424
|
+
// 2. `.neurcodeignore` — per-repo user patterns (closes dogfooding gap
|
|
2425
|
+
// where OSS-clone working trees and scratch dirs were showing up as
|
|
2426
|
+
// out-of-scope noise in self-governance runs)
|
|
2427
|
+
const ignoreFilterAllPaths = (0, ignore_1.loadIgnore)(projectRoot);
|
|
2357
2428
|
const diffFiles = allDiffFiles.filter(file => {
|
|
2358
2429
|
// Check both path and oldPath (for renames) against exclusion list
|
|
2359
|
-
const excludePath = isExcludedFile(file.path);
|
|
2360
|
-
const excludeOldPath = file.oldPath ? isExcludedFile(file.oldPath) : false;
|
|
2430
|
+
const excludePath = isExcludedFile(file.path) || ignoreFilterAllPaths(file.path);
|
|
2431
|
+
const excludeOldPath = file.oldPath ? (isExcludedFile(file.oldPath) || ignoreFilterAllPaths(file.oldPath)) : false;
|
|
2361
2432
|
return !excludePath && !excludeOldPath;
|
|
2362
2433
|
});
|
|
2363
2434
|
// ── Local-only mode (Part 8): run structural analysis and exit, no API calls ──
|
|
@@ -2365,54 +2436,381 @@ async function verifyCommand(options) {
|
|
|
2365
2436
|
// Deterministic structural governance MUST work offline, with zero API dependency.
|
|
2366
2437
|
if (localOnlyMode) {
|
|
2367
2438
|
if (!options.json) {
|
|
2368
|
-
console.log(chalk.cyan('\n🔍 Local-only mode: deterministic
|
|
2439
|
+
console.log(chalk.cyan('\n🔍 Local-only mode: deterministic intent-runtime verification (no API required)...'));
|
|
2369
2440
|
}
|
|
2370
2441
|
const localStructural = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFiles);
|
|
2371
2442
|
const localStructuralFindings = localStructural.violations.map(canonical_pipeline_1.findingFromStructural);
|
|
2372
|
-
const localReplayChecksum = (0, canonical_invariants_1.computeCanonicalFindingChecksum)(localStructuralFindings);
|
|
2373
2443
|
const blockingViolations = localStructural.violations.filter((v) => v.severity === 'BLOCKING');
|
|
2374
2444
|
const advisoryViolations = localStructural.violations.filter((v) => v.severity !== 'BLOCKING');
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2445
|
+
// ─── Intent-runtime activation (deterministic, offline) ──────────────────
|
|
2446
|
+
// When an intent-pack is present in `.neurcode/intent-pack.json` the local
|
|
2447
|
+
// verify path now activates the full governance runtime: scope checks,
|
|
2448
|
+
// forbidden-boundary enforcement, drift narratives and posture synthesis.
|
|
2449
|
+
// Companion artefacts (context-pack, repository-graph, session-runtime)
|
|
2450
|
+
// are deterministically synthesised when they are absent so the runtime
|
|
2451
|
+
// does NOT silently collapse into structural-only mode.
|
|
2452
|
+
let localActiveContext = null;
|
|
2453
|
+
let localGovernanceResult = null;
|
|
2454
|
+
const localScopeIssues = [];
|
|
2455
|
+
let localImportEdgeResult = null;
|
|
2456
|
+
try {
|
|
2457
|
+
localActiveContext = (0, active_engineering_context_1.loadOrSynthesizeEngineeringContext)(projectRoot);
|
|
2458
|
+
}
|
|
2459
|
+
catch (err) {
|
|
2460
|
+
if (!options.json && (process.env.DEBUG || process.env.VERBOSE)) {
|
|
2461
|
+
console.log(chalk.dim(` [intent-runtime] context load skipped: ${err.message}`));
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
if (localActiveContext) {
|
|
2465
|
+
try {
|
|
2466
|
+
localGovernanceResult = (0, governance_1.evaluateGovernance)({
|
|
2467
|
+
projectRoot,
|
|
2468
|
+
task: localActiveContext.intentPack.intent.normalized,
|
|
2469
|
+
expectedFiles: localActiveContext.intentPack.approvedScope.files,
|
|
2470
|
+
expectedDependencies: localActiveContext.intentPack.expectedDependencies,
|
|
2471
|
+
diffFiles,
|
|
2472
|
+
contextCandidates: localActiveContext.contextPack.selectedFiles.map((f) => f.path),
|
|
2473
|
+
activeEngineeringContext: localActiveContext,
|
|
2474
|
+
});
|
|
2475
|
+
// Deterministic scope-guard intersection against intent-pack approvedScope
|
|
2476
|
+
// PLUS explicit forbiddenBoundaries. Drift intelligence already flags
|
|
2477
|
+
// narrative-level drift; this surfaces direct path violations as
|
|
2478
|
+
// first-class scope issues regardless of drift heuristics.
|
|
2479
|
+
const intent = localActiveContext.intentPack;
|
|
2480
|
+
const approvedFileSet = new Set(intent.approvedScope.files.map(core_1.normalizeRepoPath));
|
|
2481
|
+
const approvedModulePaths = intent.approvedScope.modules.map(core_1.normalizeRepoPath);
|
|
2482
|
+
const approvedServicePaths = intent.approvedScope.services.map(core_1.normalizeRepoPath);
|
|
2483
|
+
const matchesPrefix = (file, prefixes) => prefixes.some((p) => p && (file === p || file.startsWith(`${p}/`)));
|
|
2484
|
+
const changedNormalized = diffFiles
|
|
2485
|
+
.map((f) => (0, core_1.normalizeRepoPath)(f.path))
|
|
2486
|
+
.filter((p) => Boolean(p));
|
|
2487
|
+
const isAllowedBoundaryType = (value) => value === 'sensitive' || value === 'infra' || value === 'ci' ||
|
|
2488
|
+
value === 'dependency-manifest' || value === 'service' || value === 'module' ||
|
|
2489
|
+
value === 'generated-code' || value === 'unspecified';
|
|
2490
|
+
// First pass: explicit forbidden boundaries always surface (even if
|
|
2491
|
+
// they also happen to be inside an approved module).
|
|
2492
|
+
for (const boundary of intent.forbiddenBoundaries) {
|
|
2493
|
+
const boundaryPath = (0, core_1.normalizeRepoPath)(boundary.path);
|
|
2494
|
+
if (!boundaryPath)
|
|
2495
|
+
continue;
|
|
2496
|
+
for (const file of changedNormalized) {
|
|
2497
|
+
if (file === boundaryPath || file.startsWith(`${boundaryPath}/`)) {
|
|
2498
|
+
if (boundary.policy === 'allowed')
|
|
2499
|
+
continue;
|
|
2500
|
+
const alreadyFlagged = localScopeIssues.some((s) => s.file === file && s.boundaryType === boundary.type);
|
|
2501
|
+
if (alreadyFlagged)
|
|
2502
|
+
continue;
|
|
2503
|
+
const boundaryType = isAllowedBoundaryType(boundary.type) ? boundary.type : 'unspecified';
|
|
2504
|
+
localScopeIssues.push({
|
|
2505
|
+
file,
|
|
2506
|
+
message: `Forbidden boundary touched (${boundary.type}, policy=${boundary.policy}): ${boundary.reason}`,
|
|
2507
|
+
policy: boundary.policy === 'forbidden' ? 'forbidden' : 'review-required',
|
|
2508
|
+
boundaryType,
|
|
2509
|
+
});
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
// Second pass: out-of-scope files (not in approved file/module/service set).
|
|
2514
|
+
// Only run if any approvedScope dimension is non-empty — empty scope means
|
|
2515
|
+
// intent-pack is in observation mode and we should not synthesise FPs.
|
|
2516
|
+
// When a file falls outside scope, we additionally classify it against
|
|
2517
|
+
// well-known path patterns (generated-code, infra, CI, dependency-manifest)
|
|
2518
|
+
// so reviewers see WHY the boundary matters, not just THAT it was breached.
|
|
2519
|
+
const hasApprovedScope = approvedFileSet.size > 0 || approvedModulePaths.length > 0 || approvedServicePaths.length > 0;
|
|
2520
|
+
if (hasApprovedScope) {
|
|
2521
|
+
for (const file of changedNormalized) {
|
|
2522
|
+
if (approvedFileSet.has(file))
|
|
2523
|
+
continue;
|
|
2524
|
+
if (matchesPrefix(file, approvedModulePaths))
|
|
2525
|
+
continue;
|
|
2526
|
+
if (matchesPrefix(file, approvedServicePaths))
|
|
2527
|
+
continue;
|
|
2528
|
+
if (localScopeIssues.some((s) => s.file === file))
|
|
2529
|
+
continue;
|
|
2530
|
+
const classification = (0, path_boundary_classifier_1.classifyPathBoundary)(file);
|
|
2531
|
+
if (classification) {
|
|
2532
|
+
// generated-code is a stronger signal than plain out-of-scope:
|
|
2533
|
+
// generated files should not be hand-edited regardless of
|
|
2534
|
+
// approval status.
|
|
2535
|
+
if (classification.category === 'generated-code') {
|
|
2536
|
+
localScopeIssues.push({
|
|
2537
|
+
file,
|
|
2538
|
+
message: `Generated-code edit outside approved scope (${classification.reason}). Regenerate from source or update the intent-pack to declare this surface.`,
|
|
2539
|
+
policy: 'generated-code',
|
|
2540
|
+
boundaryType: 'generated-code',
|
|
2541
|
+
});
|
|
2542
|
+
continue;
|
|
2543
|
+
}
|
|
2544
|
+
const boundaryType = isAllowedBoundaryType(classification.category) ? classification.category : 'unspecified';
|
|
2545
|
+
localScopeIssues.push({
|
|
2546
|
+
file,
|
|
2547
|
+
message: `File modified outside the declared intent scope (${classification.category}: ${classification.reason}).`,
|
|
2548
|
+
policy: 'out-of-scope',
|
|
2549
|
+
boundaryType,
|
|
2550
|
+
});
|
|
2551
|
+
continue;
|
|
2552
|
+
}
|
|
2553
|
+
localScopeIssues.push({
|
|
2554
|
+
file,
|
|
2555
|
+
message: 'File modified outside the declared intent scope.',
|
|
2556
|
+
policy: 'out-of-scope',
|
|
2557
|
+
});
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
else {
|
|
2561
|
+
// Observation mode (no approved scope): only surface generated-code
|
|
2562
|
+
// edits, because those are usually wrong regardless of intent.
|
|
2563
|
+
for (const file of changedNormalized) {
|
|
2564
|
+
if (localScopeIssues.some((s) => s.file === file))
|
|
2565
|
+
continue;
|
|
2566
|
+
const classification = (0, path_boundary_classifier_1.classifyPathBoundary)(file);
|
|
2567
|
+
if (classification?.category === 'generated-code') {
|
|
2568
|
+
localScopeIssues.push({
|
|
2569
|
+
file,
|
|
2570
|
+
message: `Generated-code edit detected (${classification.reason}). Regenerate from source.`,
|
|
2571
|
+
policy: 'generated-code',
|
|
2572
|
+
boundaryType: 'generated-code',
|
|
2573
|
+
});
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
// ─── Import-edge governance ──────────────────────────────────────
|
|
2578
|
+
// Deterministic import-edge classifier: even when every touched
|
|
2579
|
+
// path is in-scope, an `import` statement that crosses a
|
|
2580
|
+
// forbidden boundary surfaces as a scope issue. Closes the
|
|
2581
|
+
// semantic blind spot documented in
|
|
2582
|
+
// docs/validation/2026-05-17-deep-oss/.
|
|
2583
|
+
try {
|
|
2584
|
+
localImportEdgeResult = (0, import_edge_governance_1.evaluateImportEdgeGovernance)({
|
|
2585
|
+
diffFiles,
|
|
2586
|
+
projectRoot,
|
|
2587
|
+
intent: {
|
|
2588
|
+
approvedScope: {
|
|
2589
|
+
files: intent.approvedScope.files,
|
|
2590
|
+
modules: intent.approvedScope.modules,
|
|
2591
|
+
services: intent.approvedScope.services,
|
|
2592
|
+
},
|
|
2593
|
+
forbiddenBoundaries: intent.forbiddenBoundaries.map((b) => ({
|
|
2594
|
+
type: b.type,
|
|
2595
|
+
path: b.path,
|
|
2596
|
+
policy: b.policy,
|
|
2597
|
+
reason: b.reason,
|
|
2598
|
+
})),
|
|
2599
|
+
},
|
|
2600
|
+
});
|
|
2601
|
+
for (const finding of localImportEdgeResult.findings) {
|
|
2602
|
+
// Avoid double-flagging when the same source file already has
|
|
2603
|
+
// a path-touch issue for the same boundary; import-edge is
|
|
2604
|
+
// additive metadata in that case.
|
|
2605
|
+
const dupe = localScopeIssues.some((s) => s.file === finding.sourceFile
|
|
2606
|
+
&& s.importEdge
|
|
2607
|
+
&& s.importEdge.importTarget === finding.importTarget
|
|
2608
|
+
&& s.importEdge.resolvedBoundary === finding.resolvedBoundary);
|
|
2609
|
+
if (dupe)
|
|
2610
|
+
continue;
|
|
2611
|
+
localScopeIssues.push({
|
|
2612
|
+
file: finding.sourceFile,
|
|
2613
|
+
message: `Import-edge crosses ${finding.boundaryType} boundary (policy=${finding.policy}): \`${finding.importTarget}\` resolves to \`${finding.resolvedTargetPath}\` inside \`${finding.resolvedBoundary}\`. ${finding.reason}`,
|
|
2614
|
+
policy: finding.policy,
|
|
2615
|
+
boundaryType: finding.boundaryType,
|
|
2616
|
+
importEdge: {
|
|
2617
|
+
sourceFile: finding.sourceFile,
|
|
2618
|
+
sourceLine: finding.sourceLine,
|
|
2619
|
+
importTarget: finding.importTarget,
|
|
2620
|
+
resolvedTargetPath: finding.resolvedTargetPath,
|
|
2621
|
+
resolvedBoundary: finding.resolvedBoundary,
|
|
2622
|
+
edgeKind: finding.edgeKind,
|
|
2623
|
+
language: finding.language,
|
|
2624
|
+
deterministic: true,
|
|
2625
|
+
replayStable: true,
|
|
2626
|
+
},
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
catch (importErr) {
|
|
2631
|
+
if (!options.json && (process.env.DEBUG || process.env.VERBOSE)) {
|
|
2632
|
+
console.log(chalk.dim(` [intent-runtime] import-edge governance skipped: ${importErr.message}`));
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
catch (err) {
|
|
2637
|
+
if (!options.json && (process.env.DEBUG || process.env.VERBOSE)) {
|
|
2638
|
+
console.log(chalk.dim(` [intent-runtime] governance evaluation skipped: ${err.message}`));
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
const blockingScopeCount = localScopeIssues.filter((s) => s.policy === 'forbidden' || s.policy === 'out-of-scope' || s.policy === 'generated-code').length;
|
|
2643
|
+
const advisoryScopeCount = localScopeIssues.filter((s) => s.policy === 'review-required').length;
|
|
2644
|
+
const intentRuntimeActive = Boolean(localGovernanceResult);
|
|
2645
|
+
const localScopeGuardPassed = blockingScopeCount === 0;
|
|
2646
|
+
// `--require-intent-runtime` (or NEURCODE_REQUIRE_INTENT_RUNTIME=1) makes
|
|
2647
|
+
// silent downgrade into a hard failure. Without this flag the runtime
|
|
2648
|
+
// gracefully degrades to structural-only when no intent contract exists;
|
|
2649
|
+
// with it, enterprise CI gates can assert intent governance was applied.
|
|
2650
|
+
const requireIntentRuntimeFlag = options.requireIntentRuntime === true || isEnabledFlag(process.env.NEURCODE_REQUIRE_INTENT_RUNTIME);
|
|
2651
|
+
const intentRuntimeRequirementFailed = requireIntentRuntimeFlag && !intentRuntimeActive;
|
|
2652
|
+
const localVerdict = blockingViolations.length > 0 || blockingScopeCount > 0 || intentRuntimeRequirementFailed ? 'FAIL' : 'PASS';
|
|
2653
|
+
const localGrade = localVerdict === 'FAIL' ? 'F' : 'B';
|
|
2654
|
+
const localScore = localVerdict === 'FAIL' ? 0 : 70;
|
|
2655
|
+
const scopeViolationRows = localScopeIssues
|
|
2656
|
+
.filter((s) => s.policy === 'forbidden' || s.policy === 'out-of-scope' || s.policy === 'generated-code')
|
|
2657
|
+
.map((s) => ({
|
|
2658
|
+
file: s.file,
|
|
2659
|
+
rule: 'scope_guard',
|
|
2660
|
+
severity: 'block',
|
|
2661
|
+
message: s.message,
|
|
2662
|
+
}));
|
|
2663
|
+
const scopeWarningRows = localScopeIssues
|
|
2664
|
+
.filter((s) => s.policy === 'review-required')
|
|
2665
|
+
.map((s) => ({
|
|
2666
|
+
file: s.file,
|
|
2667
|
+
rule: 'scope_guard',
|
|
2668
|
+
severity: 'warn',
|
|
2669
|
+
message: s.message,
|
|
2670
|
+
}));
|
|
2671
|
+
// Surface the intent-runtime requirement failure as a first-class
|
|
2672
|
+
// governance row so CI logs, dashboards, and PR comments all see the
|
|
2673
|
+
// same explanation. The row sits next to scope_guard rows so it shares
|
|
2674
|
+
// their treatment (block, blocking-count, exit code).
|
|
2675
|
+
const intentRuntimeRequirementRows = intentRuntimeRequirementFailed
|
|
2676
|
+
? [{
|
|
2677
|
+
file: '.neurcode/intent-pack.json',
|
|
2678
|
+
rule: 'intent_runtime_required',
|
|
2679
|
+
severity: 'block',
|
|
2680
|
+
message: 'Intent-governed runtime required (--require-intent-runtime / NEURCODE_REQUIRE_INTENT_RUNTIME=1) but no `.neurcode/intent-pack.json` was found or it could not be synthesised. Either author an intent pack (`neurcode start`) or drop the requirement to allow structural-only verification.',
|
|
2681
|
+
}]
|
|
2682
|
+
: [];
|
|
2378
2683
|
const localPayload = {
|
|
2379
2684
|
grade: localGrade,
|
|
2380
2685
|
score: localScore,
|
|
2381
2686
|
verdict: localVerdict,
|
|
2382
|
-
violations:
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2687
|
+
violations: [
|
|
2688
|
+
...localStructural.violations.map((v) => ({
|
|
2689
|
+
file: v.filePath,
|
|
2690
|
+
rule: v.ruleId,
|
|
2691
|
+
severity: v.severity === 'BLOCKING' ? 'block' : 'warn',
|
|
2692
|
+
message: `${v.ruleName}: ${v.evidence.slice(0, 120)}`,
|
|
2693
|
+
})),
|
|
2694
|
+
...scopeViolationRows,
|
|
2695
|
+
...scopeWarningRows,
|
|
2696
|
+
...intentRuntimeRequirementRows,
|
|
2697
|
+
],
|
|
2388
2698
|
adherenceScore: localScore,
|
|
2389
|
-
bloatCount:
|
|
2390
|
-
bloatFiles:
|
|
2699
|
+
bloatCount: blockingScopeCount,
|
|
2700
|
+
bloatFiles: scopeViolationRows.map((r) => r.file),
|
|
2391
2701
|
plannedFilesModified: 0,
|
|
2392
2702
|
totalPlannedFiles: 0,
|
|
2393
|
-
message:
|
|
2394
|
-
|
|
2395
|
-
|
|
2703
|
+
message: intentRuntimeRequirementFailed
|
|
2704
|
+
? 'Intent-runtime requirement failed: no `.neurcode/intent-pack.json` available to activate scope + forbidden-boundary enforcement.'
|
|
2705
|
+
: (intentRuntimeActive
|
|
2706
|
+
? `Local intent-runtime verification: ${localStructural.violations.length} structural finding(s), ${blockingViolations.length} blocking; ${blockingScopeCount} scope violation(s), ${advisoryScopeCount} advisory boundary issue(s).`
|
|
2707
|
+
: `Local-only structural verification: ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking.`),
|
|
2708
|
+
scopeGuardPassed: localScopeGuardPassed,
|
|
2709
|
+
scopeIssues: localScopeIssues.map((s) => ({
|
|
2710
|
+
file: s.file,
|
|
2711
|
+
message: s.message,
|
|
2712
|
+
policy: s.policy,
|
|
2713
|
+
boundaryType: s.boundaryType,
|
|
2714
|
+
...(s.importEdge ? { importEdge: s.importEdge } : {}),
|
|
2715
|
+
})),
|
|
2716
|
+
mode: intentRuntimeActive ? 'local_intent_runtime' : 'local_only_structural',
|
|
2396
2717
|
policyOnly: true,
|
|
2397
|
-
|
|
2398
|
-
|
|
2718
|
+
// NOTE: this is the structural-only checksum. When the canonical
|
|
2719
|
+
// envelope is attached below, `governanceVerification.replayChecksum`
|
|
2720
|
+
// becomes the authoritative hash over the merged finding set
|
|
2721
|
+
// (structural + drift + scope). The top-level `replayChecksum` is
|
|
2722
|
+
// rewritten post-attach so enterprise CI sees a single canonical
|
|
2723
|
+
// hash for the activated runtime.
|
|
2724
|
+
replayChecksum: (0, canonical_invariants_1.computeCanonicalFindingChecksum)(localStructuralFindings),
|
|
2725
|
+
replayMode: intentRuntimeActive ? 'local-intent-runtime' : 'local-structural',
|
|
2399
2726
|
structuralViolations: localStructural.violations,
|
|
2400
2727
|
structuralBlockingCount: blockingViolations.length,
|
|
2401
2728
|
structuralRulesApplied: localStructural.rulesApplied,
|
|
2402
2729
|
changeContract: changeContractSummary,
|
|
2730
|
+
// driftIntelligence drives intentGovernance summary + drift findings
|
|
2731
|
+
// inside attachCanonicalGovernance.
|
|
2732
|
+
driftIntelligence: localGovernanceResult?.driftIntelligence ?? null,
|
|
2733
|
+
engineeringContext: localGovernanceResult?.engineeringContext ?? null,
|
|
2734
|
+
intentRuntime: localActiveContext
|
|
2735
|
+
? {
|
|
2736
|
+
active: true,
|
|
2737
|
+
synthesized: Boolean(localActiveContext.synthesized),
|
|
2738
|
+
intentPackId: localActiveContext.intentPack.intentPackId,
|
|
2739
|
+
contextPackId: localActiveContext.contextPack.contextPackId,
|
|
2740
|
+
repositoryGraphId: localActiveContext.repositoryGraph.graphId,
|
|
2741
|
+
warnings: localActiveContext.warnings,
|
|
2742
|
+
}
|
|
2743
|
+
: { active: false, synthesized: false, intentPackId: null, contextPackId: null, repositoryGraphId: null, warnings: [] },
|
|
2744
|
+
// Machine-readable capability declaration for enterprise CI. Every
|
|
2745
|
+
// field is "what actually executed", not "what we wished happened".
|
|
2746
|
+
// CI gates that need a specific guarantee (e.g. intent-runtime active,
|
|
2747
|
+
// generated-code governance active) can assert against this envelope
|
|
2748
|
+
// rather than inferring from absence of fields. See
|
|
2749
|
+
// docs/validation/2026-05-16-activated/activation-report-2026-05-16.md
|
|
2750
|
+
// §6 for the rationale.
|
|
2751
|
+
runtimeCapabilities: {
|
|
2752
|
+
schemaVersion: 'neurcode.runtime-capabilities.v1',
|
|
2753
|
+
executionPath: 'local-only',
|
|
2754
|
+
intentRuntime: intentRuntimeActive
|
|
2755
|
+
? (localActiveContext?.synthesized ? 'active-synthesized' : 'active-authored')
|
|
2756
|
+
: 'inactive',
|
|
2757
|
+
intentContractSource: localActiveContext
|
|
2758
|
+
? (localActiveContext.synthesized ? 'intent-pack-only' : 'full-bundle')
|
|
2759
|
+
: 'none',
|
|
2760
|
+
// Reflect whether the caller required intent runtime to be active.
|
|
2761
|
+
// Mirrors how `requireRuntimeGuard` is surfaced; lets dashboards
|
|
2762
|
+
// distinguish "intent runtime inactive by choice" from
|
|
2763
|
+
// "intent runtime inactive against caller policy".
|
|
2764
|
+
intentRuntimeRequired: requireIntentRuntimeFlag,
|
|
2765
|
+
intentRuntimeRequirementSatisfied: !intentRuntimeRequirementFailed,
|
|
2766
|
+
driftIntelligence: localGovernanceResult?.driftIntelligence ? 'active' : 'inactive',
|
|
2767
|
+
scopeGuard: intentRuntimeActive ? 'enforced' : 'unenforced',
|
|
2768
|
+
forbiddenBoundaryEnforcement: intentRuntimeActive ? 'enforced' : 'unenforced',
|
|
2769
|
+
generatedCodeGovernance: 'pattern-deterministic',
|
|
2770
|
+
// Import-edge governance is enforced whenever the intent runtime
|
|
2771
|
+
// is active. Pattern-deterministic (regex over diff additions +
|
|
2772
|
+
// path classifier), no AST, no probability.
|
|
2773
|
+
importEdgeGovernance: intentRuntimeActive ? 'pattern-deterministic' : 'inactive',
|
|
2774
|
+
structuralRules: 'active',
|
|
2775
|
+
replayDeterminism: 'enforced',
|
|
2776
|
+
apiContractStatus: 'offline',
|
|
2777
|
+
// Counts of categories observed in THIS run (not capacity).
|
|
2778
|
+
observedScopeCategories: Array.from(new Set(localScopeIssues.map((s) => s.policy))).sort(),
|
|
2779
|
+
observedBoundaryTypes: Array.from(new Set(localScopeIssues
|
|
2780
|
+
.map((s) => s.boundaryType)
|
|
2781
|
+
.filter((b) => Boolean(b)))).sort(),
|
|
2782
|
+
// Import-edge observability — counts only, plus a sorted list of
|
|
2783
|
+
// observed boundary types from the edge pass. Helpful for CI gates
|
|
2784
|
+
// that want to assert "this run had ≥0 edges analysed".
|
|
2785
|
+
importEdgesAnalyzed: localImportEdgeResult?.edgeCount ?? 0,
|
|
2786
|
+
importEdgeBlockingFindings: localImportEdgeResult?.blockingFindingCount ?? 0,
|
|
2787
|
+
importEdgeAdvisoryFindings: localImportEdgeResult?.advisoryFindingCount ?? 0,
|
|
2788
|
+
observedImportEdgeBoundaryTypes: localImportEdgeResult?.observedBoundaryTypes ?? [],
|
|
2789
|
+
},
|
|
2403
2790
|
};
|
|
2404
|
-
|
|
2791
|
+
// Run the canonical pipeline once so we can extract the merged-finding
|
|
2792
|
+
// replayChecksum (structural + drift + scope) and back-write it to the
|
|
2793
|
+
// top-level payload + custody envelope. This keeps a single authoritative
|
|
2794
|
+
// hash visible at every replay surface when the intent runtime is active.
|
|
2795
|
+
const enrichedLocalPayload = (0, canonical_pipeline_1.attachCanonicalGovernance)(localPayload);
|
|
2796
|
+
const envelopeReplayChecksum = (() => {
|
|
2797
|
+
const env = enrichedLocalPayload.governanceVerification;
|
|
2798
|
+
return env && typeof env.replayChecksum === 'string' ? env.replayChecksum : localPayload.replayChecksum;
|
|
2799
|
+
})();
|
|
2800
|
+
enrichedLocalPayload.replayChecksum = envelopeReplayChecksum;
|
|
2801
|
+
localPayload.replayChecksum = envelopeReplayChecksum;
|
|
2802
|
+
captureEvidencePayload(enrichedLocalPayload);
|
|
2405
2803
|
const localReplayCustody = (0, replay_custody_1.captureVerifyReplayCustody)({
|
|
2406
2804
|
projectRoot,
|
|
2407
2805
|
diffContext: `${options.base || 'HEAD'} vs working tree`,
|
|
2408
2806
|
filesAnalyzed: diffFiles.length,
|
|
2409
2807
|
planId: null,
|
|
2410
|
-
verificationSource: 'local_only_structural',
|
|
2808
|
+
verificationSource: intentRuntimeActive ? 'local_intent_runtime' : 'local_only_structural',
|
|
2411
2809
|
policyLockFingerprint: null,
|
|
2412
2810
|
compiledPolicyFingerprint: null,
|
|
2413
2811
|
ruleIds: localStructural.rulesApplied,
|
|
2414
|
-
blockingCount: blockingViolations.length,
|
|
2415
|
-
advisoryCount: advisoryViolations.length,
|
|
2812
|
+
blockingCount: blockingViolations.length + blockingScopeCount,
|
|
2813
|
+
advisoryCount: advisoryViolations.length + advisoryScopeCount,
|
|
2416
2814
|
suppressedCount: localStructural.suppressedCount,
|
|
2417
2815
|
structuralBlockingCount: blockingViolations.length,
|
|
2418
2816
|
structuralAdvisoryCount: advisoryViolations.length,
|
|
@@ -2422,10 +2820,12 @@ async function verifyCommand(options) {
|
|
|
2422
2820
|
? Math.round((localStructural.violations.filter((v) => v.determinism === 'deterministic-structural').length / localStructural.violations.length) * 100)
|
|
2423
2821
|
: 100,
|
|
2424
2822
|
verdict: localVerdict,
|
|
2425
|
-
governanceDecision:
|
|
2823
|
+
governanceDecision: intentRuntimeActive
|
|
2824
|
+
? `local intent-runtime verification${localActiveContext?.synthesized ? ' (synthesised context)' : ''}`
|
|
2825
|
+
: 'local deterministic structural verification',
|
|
2426
2826
|
actor: custodyActor,
|
|
2427
2827
|
source: custodySource,
|
|
2428
|
-
replayChecksum:
|
|
2828
|
+
replayChecksum: envelopeReplayChecksum,
|
|
2429
2829
|
});
|
|
2430
2830
|
applyCapturedReplayCustody(lastCanonicalOutput, localReplayCustody);
|
|
2431
2831
|
if (options.json) {
|
|
@@ -2435,8 +2835,10 @@ async function verifyCommand(options) {
|
|
|
2435
2835
|
});
|
|
2436
2836
|
}
|
|
2437
2837
|
else {
|
|
2438
|
-
if (localStructural.violations.length === 0) {
|
|
2439
|
-
console.log(chalk.green(
|
|
2838
|
+
if (localStructural.violations.length === 0 && localScopeIssues.length === 0) {
|
|
2839
|
+
console.log(chalk.green(intentRuntimeActive
|
|
2840
|
+
? '\n✅ No structural or scope violations found (intent-runtime active, local-only).'
|
|
2841
|
+
: '\n✅ No structural violations found (local-only mode).'));
|
|
2440
2842
|
}
|
|
2441
2843
|
else {
|
|
2442
2844
|
localStructural.violations.forEach((v) => {
|
|
@@ -2445,14 +2847,42 @@ async function verifyCommand(options) {
|
|
|
2445
2847
|
console.log(chalk.dim(` ${v.ruleName}`));
|
|
2446
2848
|
console.log(chalk.dim(` ${v.evidence.slice(0, 100)}`));
|
|
2447
2849
|
});
|
|
2850
|
+
for (const issue of localScopeIssues) {
|
|
2851
|
+
const prefix = issue.policy === 'forbidden' || issue.policy === 'out-of-scope'
|
|
2852
|
+
? chalk.red(' ⛔ SCOPE ')
|
|
2853
|
+
: chalk.yellow(' ⚠ SCOPE ');
|
|
2854
|
+
console.log(`${prefix} ${issue.file}`);
|
|
2855
|
+
console.log(chalk.dim(` ${issue.message}`));
|
|
2856
|
+
}
|
|
2448
2857
|
}
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2858
|
+
const modeLabel = intentRuntimeActive
|
|
2859
|
+
? (localActiveContext?.synthesized ? 'Local intent-runtime (synthesised context)' : 'Local intent-runtime')
|
|
2860
|
+
: 'Local-only structural';
|
|
2861
|
+
console.log(chalk.dim(`\n[${modeLabel}] ${localStructural.violations.length} structural finding(s), ` +
|
|
2862
|
+
`${blockingViolations.length} blocking; ${localScopeIssues.length} scope issue(s), ${blockingScopeCount} blocking.\n`));
|
|
2863
|
+
// Governance posture banner: surface gate + rollout trust prominently
|
|
2864
|
+
// when the intent runtime is active so the most-glanced terminal line
|
|
2865
|
+
// reflects the canonical governance lifecycle, not just verify counts.
|
|
2866
|
+
if (intentRuntimeActive && localGovernanceResult?.driftIntelligence) {
|
|
2867
|
+
const drift = localGovernanceResult.driftIntelligence;
|
|
2868
|
+
const gate = drift.riskSynthesis?.governanceGate || drift.governancePosture?.governanceGate;
|
|
2869
|
+
const rolloutTrust = drift.riskSynthesis?.rolloutTrust || drift.governancePosture?.rolloutTrust;
|
|
2870
|
+
if (gate || rolloutTrust) {
|
|
2871
|
+
const gateLabel = gate ? `gate=${chalk.bold(gate)}` : 'gate=advisory';
|
|
2872
|
+
const trustLabel = rolloutTrust ? `rollout-trust=${chalk.bold(rolloutTrust)}` : 'rollout-trust=rollout-safe';
|
|
2873
|
+
console.log(chalk.dim(` Governance posture: ${gateLabel} · ${trustLabel}\n`));
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
console.log(chalk.dim(` Replay: same commit + same flags + same intent-pack → same canonical checksum.\n` +
|
|
2877
|
+
` Replay checksum: ${envelopeReplayChecksum.slice(0, 16)}…\n` +
|
|
2878
|
+
(intentRuntimeActive
|
|
2879
|
+
? ' Intent governance: ACTIVE (offline). Add full intent-runtime artefacts for richer semantic narratives.\n'
|
|
2880
|
+
: ' Intent governance: INACTIVE. Add `.neurcode/intent-pack.json` to activate scope + forbidden-boundary enforcement locally.\n')));
|
|
2881
|
+
}
|
|
2882
|
+
recordVerifyEvent(localVerdict, intentRuntimeActive
|
|
2883
|
+
? `local_intent_runtime;structural=${localStructural.violations.length};scope=${localScopeIssues.length}`
|
|
2884
|
+
: `local_only;structural=${localStructural.violations.length}`, diffFiles.map((f) => f.path));
|
|
2885
|
+
exitWithEvidence(localVerdict === 'FAIL' ? 2 : 0);
|
|
2456
2886
|
}
|
|
2457
2887
|
const summary = (0, diff_parser_1.getDiffSummary)(diffFiles);
|
|
2458
2888
|
if (diffFiles.length === 0) {
|