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