@neurcode-ai/cli 0.9.65 → 0.10.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/dist/commands/bootstrap-policy.d.ts +29 -0
- package/dist/commands/bootstrap-policy.d.ts.map +1 -0
- package/dist/commands/bootstrap-policy.js +334 -0
- package/dist/commands/bootstrap-policy.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +82 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/governance.d.ts +3 -0
- package/dist/commands/governance.d.ts.map +1 -0
- package/dist/commands/governance.js +390 -0
- package/dist/commands/governance.js.map +1 -0
- package/dist/commands/quickstart.d.ts +21 -0
- package/dist/commands/quickstart.d.ts.map +1 -0
- package/dist/commands/quickstart.js +178 -0
- package/dist/commands/quickstart.js.map +1 -0
- package/dist/commands/remediate-export.d.ts +36 -0
- package/dist/commands/remediate-export.d.ts.map +1 -0
- package/dist/commands/remediate-export.js +1072 -0
- package/dist/commands/remediate-export.js.map +1 -0
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +14 -0
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/session.d.ts +7 -0
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +156 -0
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/start-intent.d.ts.map +1 -1
- package/dist/commands/start-intent.js +61 -11
- package/dist/commands/start-intent.js.map +1 -1
- package/dist/commands/verify-guidance.d.ts +5 -0
- package/dist/commands/verify-guidance.d.ts.map +1 -0
- package/dist/commands/verify-guidance.js +49 -0
- package/dist/commands/verify-guidance.js.map +1 -0
- package/dist/commands/verify-output.d.ts +37 -0
- package/dist/commands/verify-output.d.ts.map +1 -0
- package/dist/commands/verify-output.js +572 -0
- package/dist/commands/verify-output.js.map +1 -0
- package/dist/commands/verify-render.d.ts +41 -0
- package/dist/commands/verify-render.d.ts.map +1 -0
- package/dist/commands/verify-render.js +457 -0
- package/dist/commands/verify-render.js.map +1 -0
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +384 -1091
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/workspace.d.ts.map +1 -1
- package/dist/commands/workspace.js +3 -14
- package/dist/commands/workspace.js.map +1 -1
- package/dist/context-engine/graph.d.ts.map +1 -1
- package/dist/context-engine/graph.js +69 -7
- package/dist/context-engine/graph.js.map +1 -1
- package/dist/context-engine/scanner.d.ts.map +1 -1
- package/dist/context-engine/scanner.js +9 -2
- package/dist/context-engine/scanner.js.map +1 -1
- package/dist/daemon/compatibility/execution.d.ts +42 -0
- package/dist/daemon/compatibility/execution.d.ts.map +1 -0
- package/dist/daemon/compatibility/execution.js +183 -0
- package/dist/daemon/compatibility/execution.js.map +1 -0
- package/dist/daemon/compatibility/mutation.d.ts +24 -0
- package/dist/daemon/compatibility/mutation.d.ts.map +1 -0
- package/dist/daemon/compatibility/mutation.js +724 -0
- package/dist/daemon/compatibility/mutation.js.map +1 -0
- package/dist/daemon/routes.d.ts +19 -0
- package/dist/daemon/routes.d.ts.map +1 -0
- package/dist/daemon/routes.js +123 -0
- package/dist/daemon/routes.js.map +1 -0
- package/dist/daemon/runtime/execution-bus.d.ts +217 -0
- package/dist/daemon/runtime/execution-bus.d.ts.map +1 -0
- package/dist/daemon/runtime/execution-bus.js +1420 -0
- package/dist/daemon/runtime/execution-bus.js.map +1 -0
- package/dist/daemon/runtime/workspace-runtime.d.ts +280 -0
- package/dist/daemon/runtime/workspace-runtime.d.ts.map +1 -0
- package/dist/daemon/runtime/workspace-runtime.js +1473 -0
- package/dist/daemon/runtime/workspace-runtime.js.map +1 -0
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +171 -874
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/shaping.d.ts +11 -0
- package/dist/daemon/shaping.d.ts.map +1 -0
- package/dist/daemon/shaping.js +240 -0
- package/dist/daemon/shaping.js.map +1 -0
- package/dist/governance/canonical-invariants.d.ts +88 -0
- package/dist/governance/canonical-invariants.d.ts.map +1 -0
- package/dist/governance/canonical-invariants.js +197 -0
- package/dist/governance/canonical-invariants.js.map +1 -0
- package/dist/governance/canonical-ordering.d.ts +76 -0
- package/dist/governance/canonical-ordering.d.ts.map +1 -0
- package/dist/governance/canonical-ordering.js +189 -0
- package/dist/governance/canonical-ordering.js.map +1 -0
- package/dist/governance/canonical-pipeline.d.ts +9 -1
- package/dist/governance/canonical-pipeline.d.ts.map +1 -1
- package/dist/governance/canonical-pipeline.js +367 -24
- package/dist/governance/canonical-pipeline.js.map +1 -1
- package/dist/governance/diff-line-provenance.d.ts +59 -0
- package/dist/governance/diff-line-provenance.d.ts.map +1 -0
- package/dist/governance/diff-line-provenance.js +118 -0
- package/dist/governance/diff-line-provenance.js.map +1 -0
- package/dist/governance/pilot-readiness.d.ts +34 -0
- package/dist/governance/pilot-readiness.d.ts.map +1 -0
- package/dist/governance/pilot-readiness.js +226 -0
- package/dist/governance/pilot-readiness.js.map +1 -0
- package/dist/governance/policy-parity-validator.d.ts +62 -0
- package/dist/governance/policy-parity-validator.d.ts.map +1 -0
- package/dist/governance/policy-parity-validator.js +137 -0
- package/dist/governance/policy-parity-validator.js.map +1 -0
- package/dist/governance/remediation-boundary.d.ts +55 -0
- package/dist/governance/remediation-boundary.d.ts.map +1 -0
- package/dist/governance/remediation-boundary.js +120 -0
- package/dist/governance/remediation-boundary.js.map +1 -0
- package/dist/governance/structural-cache.d.ts +103 -0
- package/dist/governance/structural-cache.d.ts.map +1 -0
- package/dist/governance/structural-cache.js +235 -0
- package/dist/governance/structural-cache.js.map +1 -0
- package/dist/governance/structural-on-diff.d.ts +22 -2
- package/dist/governance/structural-on-diff.d.ts.map +1 -1
- package/dist/governance/structural-on-diff.js +36 -4
- package/dist/governance/structural-on-diff.js.map +1 -1
- package/dist/governance/structural-policy-merge.d.ts +8 -0
- package/dist/governance/structural-policy-merge.d.ts.map +1 -1
- package/dist/governance/structural-policy-merge.js +7 -0
- package/dist/governance/structural-policy-merge.js.map +1 -1
- package/dist/governance/verify-runtime-guard.d.ts +99 -0
- package/dist/governance/verify-runtime-guard.d.ts.map +1 -0
- package/dist/governance/verify-runtime-guard.js +129 -0
- package/dist/governance/verify-runtime-guard.js.map +1 -0
- package/dist/index.js +277 -77
- package/dist/index.js.map +1 -1
- package/dist/intent-engine/repo-classifier.d.ts +64 -0
- package/dist/intent-engine/repo-classifier.d.ts.map +1 -0
- package/dist/intent-engine/repo-classifier.js +178 -0
- package/dist/intent-engine/repo-classifier.js.map +1 -0
- package/dist/structural-rules/index.d.ts +4 -0
- package/dist/structural-rules/index.d.ts.map +1 -1
- package/dist/structural-rules/index.js +18 -1
- package/dist/structural-rules/index.js.map +1 -1
- package/dist/structural-rules/python/PY003-broad-except-clause.d.ts +21 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.d.ts.map +1 -1
- package/dist/structural-rules/python/PY003-broad-except-clause.js +212 -21
- package/dist/structural-rules/python/PY003-broad-except-clause.js.map +1 -1
- package/dist/structural-rules/python/PY011-thread-lifecycle.d.ts +11 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.d.ts.map +1 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.js +97 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.js.map +1 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.d.ts +11 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.d.ts.map +1 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.js +83 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.js.map +1 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.d.ts +11 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.d.ts.map +1 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.js +73 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.js.map +1 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.d.ts +11 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.d.ts.map +1 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.js +115 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.js.map +1 -0
- package/dist/structural-rules/types.d.ts +12 -0
- package/dist/structural-rules/types.d.ts.map +1 -1
- package/dist/utils/active-engineering-context.d.ts +12 -0
- package/dist/utils/active-engineering-context.d.ts.map +1 -0
- package/dist/utils/active-engineering-context.js +67 -0
- package/dist/utils/active-engineering-context.js.map +1 -0
- package/dist/utils/artifact-io.d.ts +33 -0
- package/dist/utils/artifact-io.d.ts.map +1 -0
- package/dist/utils/artifact-io.js +183 -0
- package/dist/utils/artifact-io.js.map +1 -0
- package/dist/utils/change-contract.d.ts +6 -2
- package/dist/utils/change-contract.d.ts.map +1 -1
- package/dist/utils/change-contract.js +175 -0
- package/dist/utils/change-contract.js.map +1 -1
- package/dist/utils/context-pack.d.ts +12 -0
- package/dist/utils/context-pack.d.ts.map +1 -0
- package/dist/utils/context-pack.js +147 -0
- package/dist/utils/context-pack.js.map +1 -0
- package/dist/utils/control-plane.d.ts +18 -0
- package/dist/utils/control-plane.d.ts.map +1 -1
- package/dist/utils/control-plane.js +31 -4
- package/dist/utils/control-plane.js.map +1 -1
- package/dist/utils/drift-intelligence.d.ts +47 -0
- package/dist/utils/drift-intelligence.d.ts.map +1 -0
- package/dist/utils/drift-intelligence.js +2099 -0
- package/dist/utils/drift-intelligence.js.map +1 -0
- package/dist/utils/execution-actions.d.ts +22 -0
- package/dist/utils/execution-actions.d.ts.map +1 -0
- package/dist/utils/execution-actions.js +103 -0
- package/dist/utils/execution-actions.js.map +1 -0
- package/dist/utils/execution-bus.d.ts +1 -214
- package/dist/utils/execution-bus.d.ts.map +1 -1
- package/dist/utils/execution-bus.js +15 -1359
- package/dist/utils/execution-bus.js.map +1 -1
- package/dist/utils/git.d.ts +1 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +13 -3
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/governance-decisions.d.ts +75 -0
- package/dist/utils/governance-decisions.d.ts.map +1 -0
- package/dist/utils/governance-decisions.js +412 -0
- package/dist/utils/governance-decisions.js.map +1 -0
- package/dist/utils/governance-provenance.d.ts +1 -1
- package/dist/utils/governance-provenance.d.ts.map +1 -1
- package/dist/utils/governance-provenance.js +5 -7
- package/dist/utils/governance-provenance.js.map +1 -1
- package/dist/utils/governance.d.ts +108 -0
- package/dist/utils/governance.d.ts.map +1 -1
- package/dist/utils/governance.js +209 -7
- package/dist/utils/governance.js.map +1 -1
- package/dist/utils/intelligence-runtime-common.d.ts +30 -0
- package/dist/utils/intelligence-runtime-common.d.ts.map +1 -0
- package/dist/utils/intelligence-runtime-common.js +156 -0
- package/dist/utils/intelligence-runtime-common.js.map +1 -0
- package/dist/utils/intent-contract-diagnostics.d.ts +9 -0
- package/dist/utils/intent-contract-diagnostics.d.ts.map +1 -0
- package/dist/utils/intent-contract-diagnostics.js +322 -0
- package/dist/utils/intent-contract-diagnostics.js.map +1 -0
- package/dist/utils/intent-pack.d.ts +15 -0
- package/dist/utils/intent-pack.d.ts.map +1 -0
- package/dist/utils/intent-pack.js +196 -0
- package/dist/utils/intent-pack.js.map +1 -0
- package/dist/utils/plan-sync.d.ts +1 -0
- package/dist/utils/plan-sync.d.ts.map +1 -1
- package/dist/utils/plan-sync.js +23 -0
- package/dist/utils/plan-sync.js.map +1 -1
- package/dist/utils/policy-decision.d.ts +5 -0
- package/dist/utils/policy-decision.d.ts.map +1 -0
- package/dist/utils/policy-decision.js +17 -0
- package/dist/utils/policy-decision.js.map +1 -0
- package/dist/utils/replay-custody.d.ts +43 -0
- package/dist/utils/replay-custody.d.ts.map +1 -0
- package/dist/utils/replay-custody.js +168 -0
- package/dist/utils/replay-custody.js.map +1 -0
- package/dist/utils/replay-runtime.d.ts +13 -0
- package/dist/utils/replay-runtime.d.ts.map +1 -1
- package/dist/utils/replay-runtime.js +96 -9
- package/dist/utils/replay-runtime.js.map +1 -1
- package/dist/utils/repository-intelligence.d.ts +9 -0
- package/dist/utils/repository-intelligence.d.ts.map +1 -0
- package/dist/utils/repository-intelligence.js +372 -0
- package/dist/utils/repository-intelligence.js.map +1 -0
- package/dist/utils/runtime-events.d.ts.map +1 -1
- package/dist/utils/runtime-events.js +25 -6
- package/dist/utils/runtime-events.js.map +1 -1
- package/dist/utils/semantic-contract-intelligence.d.ts +20 -0
- package/dist/utils/semantic-contract-intelligence.d.ts.map +1 -0
- package/dist/utils/semantic-contract-intelligence.js +825 -0
- package/dist/utils/semantic-contract-intelligence.js.map +1 -0
- package/dist/utils/session-continuity.d.ts +56 -0
- package/dist/utils/session-continuity.d.ts.map +1 -0
- package/dist/utils/session-continuity.js +318 -0
- package/dist/utils/session-continuity.js.map +1 -0
- package/dist/utils/verification-evidence.d.ts.map +1 -1
- package/dist/utils/verification-evidence.js +4 -1
- package/dist/utils/verification-evidence.js.map +1 -1
- package/dist/utils/verify-runtime-stability.d.ts +142 -0
- package/dist/utils/verify-runtime-stability.d.ts.map +1 -0
- package/dist/utils/verify-runtime-stability.js +230 -0
- package/dist/utils/verify-runtime-stability.js.map +1 -0
- package/dist/utils/workspace-runtime.d.ts +1 -266
- package/dist/utils/workspace-runtime.d.ts.map +1 -1
- package/dist/utils/workspace-runtime.js +15 -1412
- package/dist/utils/workspace-runtime.js.map +1 -1
- package/package.json +11 -10
- package/LICENSE +0 -201
|
@@ -0,0 +1,1072 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* neurcode remediate-export
|
|
4
|
+
*
|
|
5
|
+
* Exports a structured, deterministic remediation payload for a governance finding.
|
|
6
|
+
* The payload is designed to be passed to an external AI coding assistant
|
|
7
|
+
* (Cursor, Claude, Codex, GitHub Copilot) for remediation.
|
|
8
|
+
*
|
|
9
|
+
* TRUST BOUNDARY:
|
|
10
|
+
* Neurcode detects and exports. Your AI assistant remediates.
|
|
11
|
+
* This command never modifies any file.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* neurcode remediate-export --finding <id>
|
|
15
|
+
* neurcode remediate-export --finding-index 0
|
|
16
|
+
* neurcode remediate-export --all
|
|
17
|
+
* neurcode remediate-export --finding <id> --format mcp
|
|
18
|
+
* neurcode remediate-export --finding <id> --out ./payload.json
|
|
19
|
+
* neurcode remediate-export --finding <id> --copy
|
|
20
|
+
* neurcode remediate-export --verify-output-file ./verify.json --project-root ./repo
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.remediateExportCommand = remediateExportCommand;
|
|
24
|
+
const fs_1 = require("fs");
|
|
25
|
+
const path_1 = require("path");
|
|
26
|
+
const crypto_1 = require("crypto");
|
|
27
|
+
const child_process_1 = require("child_process");
|
|
28
|
+
const cli_json_1 = require("../utils/cli-json");
|
|
29
|
+
const chalk = (0, cli_json_1.loadChalk)();
|
|
30
|
+
// ── Trust boundary statement — fixed, never changes ──────────────────────────
|
|
31
|
+
const TRUST_BOUNDARY_STATEMENT = 'Neurcode deterministically detects and governs. ' +
|
|
32
|
+
'Your AI coding assistant (Cursor, Claude, Codex, GitHub Copilot) performs remediation. ' +
|
|
33
|
+
'Neurcode never autonomously modifies production code.';
|
|
34
|
+
// ── Remediation category map — deterministic, ruleId-keyed ───────────────────
|
|
35
|
+
const REMEDIATION_CATEGORY = {
|
|
36
|
+
PY003: 'exception-handling',
|
|
37
|
+
PY005: 'input-validation',
|
|
38
|
+
PY001: 'async-lifecycle',
|
|
39
|
+
PY006: 'async-lifecycle',
|
|
40
|
+
PY007: 'resource-lifecycle',
|
|
41
|
+
PY008: 'retry-resilience',
|
|
42
|
+
PY009: 'security',
|
|
43
|
+
PY010: 'resource-lifecycle',
|
|
44
|
+
PY011: 'thread-lifecycle',
|
|
45
|
+
PY012: 'async-lifecycle',
|
|
46
|
+
PY013: 'correctness',
|
|
47
|
+
PY014: 'retry-resilience',
|
|
48
|
+
SR001: 'exception-handling',
|
|
49
|
+
SR002: 'data-flow',
|
|
50
|
+
SR003: 'resource-lifecycle',
|
|
51
|
+
SR004: 'input-validation',
|
|
52
|
+
SR009: 'retry-resilience',
|
|
53
|
+
SR010: 'retry-resilience',
|
|
54
|
+
DS001: 'distributed-consistency',
|
|
55
|
+
'potential-secret-default': 'security',
|
|
56
|
+
'potential-secret-high': 'security',
|
|
57
|
+
governance_decision_block: 'governance-boundary',
|
|
58
|
+
scope_guard: 'governance-boundary',
|
|
59
|
+
'drift_narrative:service-boundary-escape': 'governance-boundary',
|
|
60
|
+
'drift_narrative:dependency-expansion': 'governance-boundary',
|
|
61
|
+
'drift_narrative:forbidden-boundary-breach': 'governance-boundary',
|
|
62
|
+
'drift_narrative:semantic-coupling': 'governance-boundary',
|
|
63
|
+
'drift_narrative:blast-radius-expansion': 'governance-boundary',
|
|
64
|
+
'drift_narrative:localized-scope-drift': 'governance-boundary',
|
|
65
|
+
'drift_narrative:ownership-boundary-breach': 'governance-boundary',
|
|
66
|
+
'drift_narrative:architectural-invariant-erosion': 'governance-boundary',
|
|
67
|
+
'drift_narrative:runtime-behavior-shift': 'governance-boundary',
|
|
68
|
+
'drift_narrative:deployment-semantics-breach': 'governance-boundary',
|
|
69
|
+
'drift_narrative:state-ownership-erosion': 'governance-boundary',
|
|
70
|
+
'drift_intelligence:cross-service': 'governance-boundary',
|
|
71
|
+
'drift_intelligence:dependency-spread': 'governance-boundary',
|
|
72
|
+
'drift_intelligence:infra-leakage': 'governance-boundary',
|
|
73
|
+
'drift_intelligence:sensitive-boundary': 'governance-boundary',
|
|
74
|
+
'drift_intelligence:blast-radius': 'governance-boundary',
|
|
75
|
+
'drift_intelligence:rollout-risk': 'governance-boundary',
|
|
76
|
+
'drift_intelligence:runtime-coupling': 'governance-boundary',
|
|
77
|
+
'drift_intelligence:architectural-leakage': 'governance-boundary',
|
|
78
|
+
'drift_intelligence:layer-violation': 'governance-boundary',
|
|
79
|
+
'drift_intelligence:contract-misuse': 'governance-boundary',
|
|
80
|
+
'drift_intelligence:ownership-inversion': 'governance-boundary',
|
|
81
|
+
'drift_intelligence:responsibility-drift': 'governance-boundary',
|
|
82
|
+
'drift_intelligence:invariant-violation': 'governance-boundary',
|
|
83
|
+
'drift_intelligence:behavioral-drift': 'governance-boundary',
|
|
84
|
+
'drift_intelligence:deployment-coupling': 'governance-boundary',
|
|
85
|
+
'drift_intelligence:state-ownership-risk': 'governance-boundary',
|
|
86
|
+
};
|
|
87
|
+
// ── Suggested prompt hint per category — advisory, never prescriptive ─────────
|
|
88
|
+
const PROMPT_HINT = {
|
|
89
|
+
'exception-handling': 'The finding identifies an exception handling pattern that silently swallows errors. ' +
|
|
90
|
+
'Remediation should ensure exceptions are re-raised or converted to structured error responses.',
|
|
91
|
+
'input-validation': 'The finding identifies a missing input validation boundary. ' +
|
|
92
|
+
'Remediation should add schema validation (e.g., Pydantic model) before processing the input.',
|
|
93
|
+
'async-lifecycle': 'The finding identifies an async pattern that may cause silent failures or event loop blocking. ' +
|
|
94
|
+
'Remediation should ensure async tasks are tracked and exceptions are handled.',
|
|
95
|
+
'resource-lifecycle': 'The finding identifies a resource (session, connection, thread) that may not be properly closed. ' +
|
|
96
|
+
'Remediation should use context managers or explicit cleanup in finally blocks.',
|
|
97
|
+
'thread-lifecycle': 'The finding identifies a thread created without daemon=True or without a stored reference. ' +
|
|
98
|
+
'Remediation should set daemon=True and store the thread reference for join() on shutdown.',
|
|
99
|
+
'retry-resilience': 'The finding identifies a retry pattern without exponential backoff or a thundering-herd risk. ' +
|
|
100
|
+
'Remediation should implement exponential backoff with jitter.',
|
|
101
|
+
'security': 'The finding identifies a security-sensitive pattern (hardcoded credential, unsafe deserialization). ' +
|
|
102
|
+
'Remediation must use environment variables, secret managers, or safe alternatives.',
|
|
103
|
+
'correctness': 'The finding identifies a correctness issue (e.g., mutable default argument). ' +
|
|
104
|
+
'Remediation should follow standard Python idioms to avoid shared mutable state.',
|
|
105
|
+
'distributed-consistency': 'The finding identifies a distributed consistency issue. ' +
|
|
106
|
+
'Remediation should add compensating logic, idempotency, or saga rollback.',
|
|
107
|
+
'data-flow': 'The finding identifies a data flow issue (unbounded collection, leaking state). ' +
|
|
108
|
+
'Remediation should add bounds or explicit cleanup.',
|
|
109
|
+
'governance-boundary': 'The finding identifies engineering drift outside the approved intent envelope. ' +
|
|
110
|
+
'Remediation should pull the change back inside the declared service, dependency, and rollout boundary before re-verification.',
|
|
111
|
+
};
|
|
112
|
+
async function remediateExportCommand(options) {
|
|
113
|
+
const projectRoot = options.projectRoot ? (0, path_1.resolve)(options.projectRoot) : process.cwd();
|
|
114
|
+
const verifyPath = options.verifyOutputFile
|
|
115
|
+
? (0, path_1.resolve)(options.verifyOutputFile)
|
|
116
|
+
: (0, path_1.join)(projectRoot, '.neurcode', 'last-verify-output.json');
|
|
117
|
+
if (!(0, fs_1.existsSync)(verifyPath)) {
|
|
118
|
+
console.error(chalk.red('✗ No verify output found.'));
|
|
119
|
+
console.error(chalk.dim(` Expected: ${verifyPath}`));
|
|
120
|
+
console.error(chalk.dim(' Run: neurcode verify --policy-only --json'));
|
|
121
|
+
console.error(chalk.dim(' Or pass: neurcode remediate-export --verify-output-file <path-to-verify.json>'));
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
let verifyOutput;
|
|
125
|
+
try {
|
|
126
|
+
verifyOutput = JSON.parse((0, fs_1.readFileSync)(verifyPath, 'utf-8'));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
console.error(chalk.red(`✗ Could not parse verify output: ${verifyPath}`));
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
// Collect findings from verify output
|
|
133
|
+
const findings = collectFindings(verifyOutput);
|
|
134
|
+
if (findings.length === 0) {
|
|
135
|
+
console.log(chalk.green('✅ No findings in last verify run. Nothing to export.'));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Select which findings to export
|
|
139
|
+
let selected = [];
|
|
140
|
+
if (options.all) {
|
|
141
|
+
selected = findings;
|
|
142
|
+
}
|
|
143
|
+
else if (options.findingIndex !== undefined) {
|
|
144
|
+
const idx = parseInt(options.findingIndex, 10);
|
|
145
|
+
if (isNaN(idx) || idx < 0 || idx >= findings.length) {
|
|
146
|
+
console.error(chalk.red(`✗ --finding-index ${options.findingIndex} out of range. ${findings.length} findings available.`));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
selected = [findings[idx]];
|
|
150
|
+
}
|
|
151
|
+
else if (options.finding) {
|
|
152
|
+
const found = findings.filter((f) => (f.id ?? f.findingId ?? '') === options.finding ||
|
|
153
|
+
String(f.findingId ?? f.id ?? '').startsWith(options.finding));
|
|
154
|
+
if (found.length === 0) {
|
|
155
|
+
console.error(chalk.red(`✗ Finding "${options.finding}" not found in last verify output.`));
|
|
156
|
+
console.error(chalk.dim(` Available IDs:`));
|
|
157
|
+
findings.slice(0, 10).forEach((f) => console.error(chalk.dim(` ${f.id ?? f.findingId ?? '(no id)'} — ${f.ruleId ?? f.rule ?? '?'} @ ${f.file ?? f.filePath ?? '?'}`)));
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
selected = found;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// Default: export index 0 with a prompt
|
|
164
|
+
console.log(chalk.dim(`No finding specified. Exporting finding at index 0. Use --finding-index N or --all.\n`));
|
|
165
|
+
selected = [findings[0]];
|
|
166
|
+
}
|
|
167
|
+
const format = options.format ?? 'json';
|
|
168
|
+
const replayChecksum = resolveReplayChecksum(verifyOutput);
|
|
169
|
+
const replayMode = resolveReplayMode(verifyOutput);
|
|
170
|
+
const payloads = selected.map((finding) => buildPayload(finding, verifyOutput, projectRoot, replayChecksum, replayMode, format));
|
|
171
|
+
const output = payloads.length === 1
|
|
172
|
+
? JSON.stringify(format === 'mcp' ? payloads[0].mcpEnvelope : payloads[0], null, 2)
|
|
173
|
+
: JSON.stringify(format === 'mcp' ? payloads.map(p => p.mcpEnvelope) : payloads, null, 2);
|
|
174
|
+
// Write to file or stdout
|
|
175
|
+
if (options.out) {
|
|
176
|
+
const outPath = (0, path_1.resolve)(projectRoot, options.out);
|
|
177
|
+
(0, fs_1.writeFileSync)(outPath, output, 'utf-8');
|
|
178
|
+
console.log(chalk.green(`✅ Remediation export written to ${outPath}`));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
console.log(output);
|
|
182
|
+
}
|
|
183
|
+
// Copy to clipboard
|
|
184
|
+
if (options.copy) {
|
|
185
|
+
try {
|
|
186
|
+
(0, child_process_1.execSync)('pbcopy', { input: output });
|
|
187
|
+
console.error(chalk.green('\n✅ Remediation payload copied to clipboard.'));
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
console.error(chalk.yellow('\n⚠ --copy failed (pbcopy not available on this system).'));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Print trust boundary reminder
|
|
194
|
+
if (!options.json) {
|
|
195
|
+
console.error(chalk.dim('\n─────────────────────────────────────────────────────────'));
|
|
196
|
+
console.error(chalk.cyan(' Trust Boundary'));
|
|
197
|
+
console.error(chalk.dim(' Neurcode detects. Your AI assistant remediates.'));
|
|
198
|
+
console.error(chalk.dim(' Pass this payload to Cursor, Claude, Codex, or any provider.'));
|
|
199
|
+
console.error(chalk.dim(' Neurcode will re-verify after remediation.'));
|
|
200
|
+
console.error(chalk.dim('─────────────────────────────────────────────────────────\n'));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// ── Builders ──────────────────────────────────────────────────────────────────
|
|
204
|
+
function collectFindings(verifyOutput) {
|
|
205
|
+
// Try multiple possible locations in verify output shape
|
|
206
|
+
const govEnvelope = verifyOutput.governanceVerification?.findings ?? [];
|
|
207
|
+
const violations = verifyOutput.violations ?? [];
|
|
208
|
+
const blockingItems = verifyOutput.blockingItems ?? [];
|
|
209
|
+
const advisoryItems = verifyOutput.advisoryItems ?? [];
|
|
210
|
+
if (govEnvelope.length > 0)
|
|
211
|
+
return govEnvelope;
|
|
212
|
+
return [...violations, ...blockingItems, ...advisoryItems];
|
|
213
|
+
}
|
|
214
|
+
function buildPayload(finding, verifyOutput, projectRoot, replayChecksum, replayMode, format) {
|
|
215
|
+
const ruleId = resolveFindingRuleId(finding);
|
|
216
|
+
const filePath = finding.filePath ?? finding.file ?? finding.evidence?.filePath ?? '';
|
|
217
|
+
const line = finding.line ?? finding.evidence?.line ?? null;
|
|
218
|
+
const column = finding.column ?? finding.evidence?.column ?? null;
|
|
219
|
+
const severity = finding.severity ?? 'BLOCKING';
|
|
220
|
+
const determinismClass = finding.determinismClassification ?? finding.determinism ?? 'deterministic-structural';
|
|
221
|
+
const findingId = finding.id ?? finding.findingId ?? '';
|
|
222
|
+
const ruleName = finding.title ?? finding.ruleName ?? finding.name ?? ruleId;
|
|
223
|
+
const operationalExplanation = finding.operationalImplication ?? finding.message ?? finding.explanation ?? '';
|
|
224
|
+
// Extract code span from file if it exists
|
|
225
|
+
const { codeSpan, surroundingContext } = extractCodeSpan(projectRoot, filePath, line);
|
|
226
|
+
// Deterministic export ID
|
|
227
|
+
const exportId = (0, crypto_1.createHash)('sha256')
|
|
228
|
+
.update(`${findingId}|${filePath}|${line ?? 0}|${ruleId}`)
|
|
229
|
+
.digest('hex')
|
|
230
|
+
.slice(0, 32);
|
|
231
|
+
// Finding graph hash (deterministic over finding identity fields)
|
|
232
|
+
const findingGraphHash = (0, crypto_1.createHash)('sha256')
|
|
233
|
+
.update(`${ruleId}|${filePath}|${line ?? 0}|${severity}|${determinismClass}`)
|
|
234
|
+
.digest('hex')
|
|
235
|
+
.slice(0, 16);
|
|
236
|
+
const remediationCategory = REMEDIATION_CATEGORY[ruleId] ?? 'general';
|
|
237
|
+
const suggestedPromptHint = PROMPT_HINT[remediationCategory] ?? PROMPT_HINT['correctness'];
|
|
238
|
+
const snapshotIds = Array.isArray(finding.replayMetadata?.snapshotIds)
|
|
239
|
+
? finding.replayMetadata.snapshotIds.filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
|
|
240
|
+
: [];
|
|
241
|
+
const controlPlaneSnapshotId = typeof verifyOutput.controlPlaneSnapshotId === 'string'
|
|
242
|
+
? verifyOutput.controlPlaneSnapshotId
|
|
243
|
+
: snapshotIds.find((entry) => entry.startsWith('cps-')) ?? null;
|
|
244
|
+
const workspaceSnapshotId = typeof verifyOutput.workspaceSnapshotId === 'string'
|
|
245
|
+
? verifyOutput.workspaceSnapshotId
|
|
246
|
+
: snapshotIds.find((entry) => entry.startsWith('wss-')) ?? null;
|
|
247
|
+
const policyViolations = [];
|
|
248
|
+
if (finding.structuralMetadata?.policyRef)
|
|
249
|
+
policyViolations.push(finding.structuralMetadata.policyRef);
|
|
250
|
+
if (finding.policy)
|
|
251
|
+
policyViolations.push(finding.policy);
|
|
252
|
+
const blastRadiusRisk = typeof verifyOutput.blastRadius === 'object'
|
|
253
|
+
&& verifyOutput.blastRadius
|
|
254
|
+
&& typeof verifyOutput.blastRadius.riskScore === 'string'
|
|
255
|
+
? verifyOutput.blastRadius.riskScore
|
|
256
|
+
: null;
|
|
257
|
+
const scopeReason = typeof verifyOutput.suspiciousChange === 'object'
|
|
258
|
+
&& verifyOutput.suspiciousChange
|
|
259
|
+
&& typeof verifyOutput.suspiciousChange.reason === 'string'
|
|
260
|
+
? verifyOutput.suspiciousChange.reason
|
|
261
|
+
: null;
|
|
262
|
+
const scopeUnexpectedFiles = typeof verifyOutput.suspiciousChange === 'object'
|
|
263
|
+
&& verifyOutput.suspiciousChange
|
|
264
|
+
&& Array.isArray(verifyOutput.suspiciousChange.unexpectedFiles)
|
|
265
|
+
? verifyOutput.suspiciousChange.unexpectedFiles
|
|
266
|
+
.filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
|
|
267
|
+
.slice(0, 12)
|
|
268
|
+
: [];
|
|
269
|
+
const contractViolationSummary = typeof verifyOutput.changeContract === 'object'
|
|
270
|
+
&& verifyOutput.changeContract
|
|
271
|
+
&& Array.isArray(verifyOutput.changeContract.violations)
|
|
272
|
+
? verifyOutput.changeContract.violations
|
|
273
|
+
.map((entry) => typeof entry.message === 'string' ? entry.message.trim() : '')
|
|
274
|
+
.filter((entry) => entry.length > 0)
|
|
275
|
+
.slice(0, 12)
|
|
276
|
+
: [];
|
|
277
|
+
const engineeringContext = extractEngineeringContext(verifyOutput);
|
|
278
|
+
const intentGovernance = extractIntentGovernance(verifyOutput);
|
|
279
|
+
const driftIntelligence = extractDriftIntelligence(verifyOutput);
|
|
280
|
+
const graphImpact = extractGraphImpact(verifyOutput);
|
|
281
|
+
const relevantNarratives = selectRelevantNarratives(driftIntelligence, filePath, ruleId);
|
|
282
|
+
const semanticInsights = deriveSemanticExportInsights(engineeringContext, driftIntelligence, relevantNarratives, filePath);
|
|
283
|
+
const payload = {
|
|
284
|
+
exportId,
|
|
285
|
+
exportedAt: new Date().toISOString(),
|
|
286
|
+
neurcodeVersion: '0.10.0',
|
|
287
|
+
schemaVersion: '2026-05-14',
|
|
288
|
+
findingId,
|
|
289
|
+
ruleId,
|
|
290
|
+
ruleName,
|
|
291
|
+
severity,
|
|
292
|
+
determinismClass,
|
|
293
|
+
filePath,
|
|
294
|
+
line,
|
|
295
|
+
column,
|
|
296
|
+
codeSpan,
|
|
297
|
+
surroundingContext,
|
|
298
|
+
policyViolations,
|
|
299
|
+
operationalExplanation,
|
|
300
|
+
remediationCategory,
|
|
301
|
+
blastRadiusRisk,
|
|
302
|
+
scopeReason,
|
|
303
|
+
scopeUnexpectedFiles,
|
|
304
|
+
contractViolationSummary,
|
|
305
|
+
violatedContracts: semanticInsights.violatedContracts,
|
|
306
|
+
ownershipBoundaryCrossed: semanticInsights.ownershipBoundaryCrossed,
|
|
307
|
+
invariantSummaries: semanticInsights.invariantSummaries,
|
|
308
|
+
semanticRiskSummary: semanticInsights.semanticRiskSummary,
|
|
309
|
+
intentGovernance,
|
|
310
|
+
trustBoundaryStatement: TRUST_BOUNDARY_STATEMENT,
|
|
311
|
+
replayChecksum,
|
|
312
|
+
replayMode,
|
|
313
|
+
findingGraphHash,
|
|
314
|
+
provenanceRunId: finding.provenanceMetadata?.runId ?? verifyOutput.provenanceRunId ?? null,
|
|
315
|
+
provenanceAt: finding.provenanceMetadata?.generatedAt ?? verifyOutput.provenanceRunAt ?? null,
|
|
316
|
+
planId: finding.provenanceMetadata?.planId ?? verifyOutput.planId ?? null,
|
|
317
|
+
policyLockFingerprint: finding.provenanceMetadata?.policyLockFingerprint ?? verifyOutput.policyLockFingerprint ?? null,
|
|
318
|
+
compiledPolicyFingerprint: finding.provenanceMetadata?.compiledPolicyFingerprint ?? verifyOutput.compiledPolicyFingerprint ?? null,
|
|
319
|
+
controlPlaneSnapshotId,
|
|
320
|
+
workspaceSnapshotId,
|
|
321
|
+
engineeringContext,
|
|
322
|
+
driftIntelligence,
|
|
323
|
+
graphImpact,
|
|
324
|
+
relevantNarratives,
|
|
325
|
+
suggestedPromptHint,
|
|
326
|
+
};
|
|
327
|
+
if (format === 'mcp') {
|
|
328
|
+
payload.mcpEnvelope = {
|
|
329
|
+
type: 'neurcode/remediation-request',
|
|
330
|
+
version: '1.0',
|
|
331
|
+
trust: 'deterministic-governance',
|
|
332
|
+
finding: {
|
|
333
|
+
id: findingId,
|
|
334
|
+
ruleId,
|
|
335
|
+
severity,
|
|
336
|
+
file: filePath,
|
|
337
|
+
line,
|
|
338
|
+
codeSpan,
|
|
339
|
+
},
|
|
340
|
+
context: buildMcpContext(surroundingContext, engineeringContext, driftIntelligence, graphImpact, relevantNarratives, semanticInsights, intentGovernance),
|
|
341
|
+
constraint: TRUST_BOUNDARY_STATEMENT,
|
|
342
|
+
promptHint: suggestedPromptHint,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
return payload;
|
|
346
|
+
}
|
|
347
|
+
function resolveFindingRuleId(finding) {
|
|
348
|
+
const direct = finding.ruleId
|
|
349
|
+
?? finding.rule
|
|
350
|
+
?? finding.structuralMetadata?.ruleId
|
|
351
|
+
?? null;
|
|
352
|
+
if (typeof direct === 'string' && direct.trim().length > 0) {
|
|
353
|
+
return direct.trim();
|
|
354
|
+
}
|
|
355
|
+
const title = typeof finding.title === 'string' ? finding.title.trim() : '';
|
|
356
|
+
const titleMatch = title.match(/·\s*([A-Za-z0-9:_-]+)/);
|
|
357
|
+
if (titleMatch?.[1]) {
|
|
358
|
+
return titleMatch[1];
|
|
359
|
+
}
|
|
360
|
+
return 'UNKNOWN';
|
|
361
|
+
}
|
|
362
|
+
function asRecord(value) {
|
|
363
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
return value;
|
|
367
|
+
}
|
|
368
|
+
function asStringArray(value, limit = 12) {
|
|
369
|
+
if (!Array.isArray(value)) {
|
|
370
|
+
return [];
|
|
371
|
+
}
|
|
372
|
+
return value
|
|
373
|
+
.filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
|
|
374
|
+
.slice(0, limit);
|
|
375
|
+
}
|
|
376
|
+
function extractGovernanceDecisionLineage(value) {
|
|
377
|
+
const record = asRecord(value);
|
|
378
|
+
if (!record)
|
|
379
|
+
return null;
|
|
380
|
+
return {
|
|
381
|
+
decisionId: typeof record.decisionId === 'string' ? record.decisionId : 'unknown',
|
|
382
|
+
state: typeof record.state === 'string' ? record.state : 'acknowledged',
|
|
383
|
+
findingId: typeof record.findingId === 'string' ? record.findingId : null,
|
|
384
|
+
category: typeof record.category === 'string' ? record.category : null,
|
|
385
|
+
reason: typeof record.reason === 'string' ? record.reason : 'Governance decision reason unavailable.',
|
|
386
|
+
actor: typeof record.actor === 'string' ? record.actor : 'unknown',
|
|
387
|
+
decidedAt: typeof record.decidedAt === 'string' ? record.decidedAt : '',
|
|
388
|
+
expiresAt: typeof record.expiresAt === 'string' ? record.expiresAt : null,
|
|
389
|
+
temporary: record.temporary === true,
|
|
390
|
+
expired: record.expired === true,
|
|
391
|
+
previousGate: typeof record.previousGate === 'string' ? record.previousGate : null,
|
|
392
|
+
resultingGate: typeof record.resultingGate === 'string' ? record.resultingGate : null,
|
|
393
|
+
previousRolloutTrust: typeof record.previousRolloutTrust === 'string' ? record.previousRolloutTrust : null,
|
|
394
|
+
resultingRolloutTrust: typeof record.resultingRolloutTrust === 'string' ? record.resultingRolloutTrust : null,
|
|
395
|
+
sourcePath: typeof record.sourcePath === 'string' ? record.sourcePath : null,
|
|
396
|
+
lineageHash: typeof record.lineageHash === 'string' ? record.lineageHash : 'unknown',
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function asBoundaryArray(value) {
|
|
400
|
+
if (!Array.isArray(value)) {
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
403
|
+
return value
|
|
404
|
+
.map((entry) => asRecord(entry))
|
|
405
|
+
.filter((entry) => entry !== null)
|
|
406
|
+
.map((entry) => ({
|
|
407
|
+
type: typeof entry.type === 'string' ? entry.type : 'unknown',
|
|
408
|
+
path: typeof entry.path === 'string' ? entry.path : '',
|
|
409
|
+
policy: typeof entry.policy === 'string' ? entry.policy : 'review-required',
|
|
410
|
+
reason: typeof entry.reason === 'string' ? entry.reason : '',
|
|
411
|
+
}))
|
|
412
|
+
.filter((entry) => entry.path.trim().length > 0)
|
|
413
|
+
.slice(0, 12);
|
|
414
|
+
}
|
|
415
|
+
function extractEngineeringContext(verifyOutput) {
|
|
416
|
+
const context = asRecord(verifyOutput.engineeringContext);
|
|
417
|
+
if (!context) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
const approvedScope = asRecord(context.approvedScope);
|
|
421
|
+
const semanticExpectations = asRecord(context.semanticExpectations);
|
|
422
|
+
return {
|
|
423
|
+
source: typeof context.source === 'string' ? context.source : null,
|
|
424
|
+
sessionId: typeof context.sessionId === 'string' ? context.sessionId : null,
|
|
425
|
+
intentPackId: typeof context.intentPackId === 'string' ? context.intentPackId : null,
|
|
426
|
+
contextPackId: typeof context.contextPackId === 'string' ? context.contextPackId : null,
|
|
427
|
+
repositoryGraphId: typeof context.repositoryGraphId === 'string' ? context.repositoryGraphId : null,
|
|
428
|
+
intentSummary: typeof context.intentSummary === 'string' ? context.intentSummary : null,
|
|
429
|
+
approvedScope: {
|
|
430
|
+
files: asStringArray(approvedScope?.files, 20),
|
|
431
|
+
modules: asStringArray(approvedScope?.modules, 20),
|
|
432
|
+
services: asStringArray(approvedScope?.services, 20),
|
|
433
|
+
},
|
|
434
|
+
expectedDependencies: asStringArray(context.expectedDependencies, 20),
|
|
435
|
+
expectedInfrastructure: asStringArray(context.expectedInfrastructure, 20),
|
|
436
|
+
rolloutExpectations: asStringArray(context.rolloutExpectations, 12),
|
|
437
|
+
forbiddenBoundaries: asBoundaryArray(context.forbiddenBoundaries),
|
|
438
|
+
semanticExpectations: semanticExpectations
|
|
439
|
+
? {
|
|
440
|
+
ownershipBoundaries: asStringArray(semanticExpectations.ownershipBoundaries, 16),
|
|
441
|
+
contractIds: asStringArray(semanticExpectations.contractIds, 20),
|
|
442
|
+
invariantIds: asStringArray(semanticExpectations.invariantIds, 20),
|
|
443
|
+
expectedResponsibilities: asStringArray(semanticExpectations.expectedResponsibilities, 20),
|
|
444
|
+
expectedBehaviorKinds: asStringArray(semanticExpectations.expectedBehaviorKinds, 20),
|
|
445
|
+
expectedRuntimeFlows: asStringArray(semanticExpectations.expectedRuntimeFlows, 20),
|
|
446
|
+
expectedRolloutUnits: asStringArray(semanticExpectations.expectedRolloutUnits, 20),
|
|
447
|
+
}
|
|
448
|
+
: null,
|
|
449
|
+
contextFiles: Array.isArray(context.contextFiles)
|
|
450
|
+
? context.contextFiles
|
|
451
|
+
.map((entry) => asRecord(entry))
|
|
452
|
+
.filter((entry) => entry !== null)
|
|
453
|
+
.map((entry) => (typeof entry.path === 'string' ? entry.path : ''))
|
|
454
|
+
.filter((entry) => entry.length > 0)
|
|
455
|
+
.slice(0, 16)
|
|
456
|
+
: [],
|
|
457
|
+
relatedModules: asStringArray(context.relatedModules, 20),
|
|
458
|
+
serviceBoundaries: Array.isArray(context.serviceBoundaries)
|
|
459
|
+
? context.serviceBoundaries
|
|
460
|
+
.map((entry) => asRecord(entry))
|
|
461
|
+
.filter((entry) => entry !== null)
|
|
462
|
+
.map((entry) => `${typeof entry.name === 'string' ? entry.name : 'unknown'}:${typeof entry.path === 'string' ? entry.path : ''}`)
|
|
463
|
+
.filter((entry) => !entry.endsWith(':'))
|
|
464
|
+
.slice(0, 16)
|
|
465
|
+
: [],
|
|
466
|
+
ownershipBoundaries: Array.isArray(context.ownershipBoundaries)
|
|
467
|
+
? context.ownershipBoundaries
|
|
468
|
+
.map((entry) => asRecord(entry))
|
|
469
|
+
.filter((entry) => entry !== null)
|
|
470
|
+
.map((entry) => ({
|
|
471
|
+
name: typeof entry.name === 'string' ? entry.name : 'unknown',
|
|
472
|
+
domain: typeof entry.domain === 'string' ? entry.domain : 'unknown',
|
|
473
|
+
kind: typeof entry.kind === 'string' ? entry.kind : 'unknown',
|
|
474
|
+
primaryOwner: typeof entry.primaryOwner === 'string' ? entry.primaryOwner : 'unknown',
|
|
475
|
+
responsibilities: asStringArray(entry.responsibilities, 12),
|
|
476
|
+
forbiddenResponsibilities: asStringArray(entry.forbiddenResponsibilities, 12),
|
|
477
|
+
criticality: typeof entry.criticality === 'string' ? entry.criticality : 'standard',
|
|
478
|
+
}))
|
|
479
|
+
.slice(0, 16)
|
|
480
|
+
: [],
|
|
481
|
+
invariants: Array.isArray(context.invariants)
|
|
482
|
+
? context.invariants
|
|
483
|
+
.map((entry) => asRecord(entry))
|
|
484
|
+
.filter((entry) => entry !== null)
|
|
485
|
+
.map((entry) => ({
|
|
486
|
+
id: typeof entry.id === 'string' ? entry.id : 'unknown',
|
|
487
|
+
name: typeof entry.name === 'string' ? entry.name : 'Invariant',
|
|
488
|
+
category: typeof entry.category === 'string' ? entry.category : 'unknown',
|
|
489
|
+
expectation: typeof entry.expectation === 'string' ? entry.expectation : 'Expectation unavailable.',
|
|
490
|
+
impact: typeof entry.impact === 'string' ? entry.impact : 'unknown',
|
|
491
|
+
boundaryName: typeof entry.boundaryName === 'string' ? entry.boundaryName : null,
|
|
492
|
+
}))
|
|
493
|
+
.slice(0, 20)
|
|
494
|
+
: [],
|
|
495
|
+
invariantMemory: (() => {
|
|
496
|
+
const memory = asRecord(context.invariantMemory);
|
|
497
|
+
if (!memory)
|
|
498
|
+
return null;
|
|
499
|
+
return {
|
|
500
|
+
invariantMemoryId: typeof memory.invariantMemoryId === 'string' ? memory.invariantMemoryId : null,
|
|
501
|
+
historicalDriftPatterns: Array.isArray(memory.historicalDriftPatterns)
|
|
502
|
+
? memory.historicalDriftPatterns
|
|
503
|
+
.map((entry) => asRecord(entry))
|
|
504
|
+
.filter((entry) => entry !== null)
|
|
505
|
+
.map((entry) => ({
|
|
506
|
+
category: typeof entry.category === 'string' ? entry.category : 'unknown',
|
|
507
|
+
count: typeof entry.count === 'number' ? entry.count : 0,
|
|
508
|
+
latestSummary: typeof entry.latestSummary === 'string' ? entry.latestSummary : '',
|
|
509
|
+
}))
|
|
510
|
+
.slice(0, 12)
|
|
511
|
+
: [],
|
|
512
|
+
};
|
|
513
|
+
})(),
|
|
514
|
+
runtimeBehaviors: Array.isArray(context.runtimeBehaviors)
|
|
515
|
+
? context.runtimeBehaviors
|
|
516
|
+
.map((entry) => asRecord(entry))
|
|
517
|
+
.filter((entry) => entry !== null)
|
|
518
|
+
.map((entry) => ({
|
|
519
|
+
boundaryName: typeof entry.boundaryName === 'string' ? entry.boundaryName : 'unknown',
|
|
520
|
+
behaviorKinds: asStringArray(entry.behaviorKinds, 12),
|
|
521
|
+
sideEffectKinds: asStringArray(entry.sideEffectKinds, 12),
|
|
522
|
+
stateSurfaces: asStringArray(entry.stateSurfaces, 12),
|
|
523
|
+
rolloutUnits: asStringArray(entry.rolloutUnits, 12),
|
|
524
|
+
runtimeEnvironments: asStringArray(entry.runtimeEnvironments, 8),
|
|
525
|
+
criticalFlows: asStringArray(entry.criticalFlows, 12),
|
|
526
|
+
}))
|
|
527
|
+
.slice(0, 20)
|
|
528
|
+
: [],
|
|
529
|
+
runtimeInteractions: Array.isArray(context.runtimeInteractions)
|
|
530
|
+
? context.runtimeInteractions
|
|
531
|
+
.map((entry) => asRecord(entry))
|
|
532
|
+
.filter((entry) => entry !== null)
|
|
533
|
+
.map((entry) => ({
|
|
534
|
+
kind: typeof entry.kind === 'string' ? entry.kind : 'unknown',
|
|
535
|
+
fromBoundaryName: typeof entry.fromBoundaryName === 'string' ? entry.fromBoundaryName : 'unknown',
|
|
536
|
+
toBoundaryName: typeof entry.toBoundaryName === 'string' ? entry.toBoundaryName : null,
|
|
537
|
+
subject: typeof entry.subject === 'string' ? entry.subject : 'unknown',
|
|
538
|
+
rationale: typeof entry.rationale === 'string' ? entry.rationale : '',
|
|
539
|
+
}))
|
|
540
|
+
.slice(0, 24)
|
|
541
|
+
: [],
|
|
542
|
+
deploymentBoundaries: Array.isArray(context.deploymentBoundaries)
|
|
543
|
+
? context.deploymentBoundaries
|
|
544
|
+
.map((entry) => asRecord(entry))
|
|
545
|
+
.filter((entry) => entry !== null)
|
|
546
|
+
.map((entry) => ({
|
|
547
|
+
name: typeof entry.name === 'string' ? entry.name : 'unknown',
|
|
548
|
+
type: typeof entry.type === 'string' ? entry.type : 'unknown',
|
|
549
|
+
rolloutUnits: asStringArray(entry.rolloutUnits, 12),
|
|
550
|
+
runtimeEnvironments: asStringArray(entry.runtimeEnvironments, 8),
|
|
551
|
+
dependentBoundaryNames: asStringArray(entry.dependentBoundaryNames, 12),
|
|
552
|
+
}))
|
|
553
|
+
.slice(0, 16)
|
|
554
|
+
: [],
|
|
555
|
+
sessionLineage: asStringArray(context.sessionLineage, 12),
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function extractDriftIntelligence(verifyOutput) {
|
|
559
|
+
const drift = asRecord(verifyOutput.driftIntelligence);
|
|
560
|
+
if (!drift) {
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
const findings = Array.isArray(drift.findings)
|
|
564
|
+
? drift.findings
|
|
565
|
+
.map((entry) => asRecord(entry))
|
|
566
|
+
.filter((entry) => entry !== null)
|
|
567
|
+
.map((entry) => {
|
|
568
|
+
const evidence = asRecord(entry.evidence);
|
|
569
|
+
const remediationGuidance = asRecord(entry.remediationGuidance);
|
|
570
|
+
return {
|
|
571
|
+
category: typeof entry.category === 'string' ? entry.category : 'unknown',
|
|
572
|
+
severity: typeof entry.severity === 'string' ? entry.severity : 'unknown',
|
|
573
|
+
message: typeof entry.message === 'string' ? entry.message : 'Drift signal detected.',
|
|
574
|
+
rationale: typeof entry.rationale === 'string' ? entry.rationale : null,
|
|
575
|
+
file: typeof entry.file === 'string' ? entry.file : null,
|
|
576
|
+
module: typeof entry.module === 'string' ? entry.module : null,
|
|
577
|
+
service: typeof entry.service === 'string' ? entry.service : null,
|
|
578
|
+
evidenceTier: typeof entry.evidenceTier === 'string' ? entry.evidenceTier : null,
|
|
579
|
+
actionability: typeof entry.actionability === 'string' ? entry.actionability : null,
|
|
580
|
+
priority: typeof entry.priority === 'string' ? entry.priority : null,
|
|
581
|
+
governanceGate: typeof entry.governanceGate === 'string' ? entry.governanceGate : null,
|
|
582
|
+
rolloutTrust: typeof entry.rolloutTrust === 'string' ? entry.rolloutTrust : null,
|
|
583
|
+
relationships: Array.isArray(entry.relationships)
|
|
584
|
+
? entry.relationships
|
|
585
|
+
.map((relationship) => asRecord(relationship))
|
|
586
|
+
.filter((relationship) => relationship !== null)
|
|
587
|
+
.map((relationship) => ({
|
|
588
|
+
type: typeof relationship.type === 'string' ? relationship.type : 'derived-from',
|
|
589
|
+
targetFindingId: typeof relationship.targetFindingId === 'string'
|
|
590
|
+
? relationship.targetFindingId
|
|
591
|
+
: '',
|
|
592
|
+
rationale: typeof relationship.rationale === 'string'
|
|
593
|
+
? relationship.rationale
|
|
594
|
+
: 'Finding relationship rationale unavailable.',
|
|
595
|
+
}))
|
|
596
|
+
.filter((relationship) => relationship.targetFindingId.length > 0)
|
|
597
|
+
.slice(0, 4)
|
|
598
|
+
: [],
|
|
599
|
+
governanceDecision: extractGovernanceDecisionLineage(entry.governanceDecision),
|
|
600
|
+
evidence: evidence
|
|
601
|
+
? {
|
|
602
|
+
tier: typeof evidence.tier === 'string' ? evidence.tier : null,
|
|
603
|
+
changedFiles: asStringArray(evidence.changedFiles, 8),
|
|
604
|
+
changedLines: Array.isArray(evidence.changedLines)
|
|
605
|
+
? evidence.changedLines
|
|
606
|
+
.map((line) => asRecord(line))
|
|
607
|
+
.filter((line) => line !== null)
|
|
608
|
+
.map((line) => ({
|
|
609
|
+
file: typeof line.file === 'string' ? line.file : 'unknown',
|
|
610
|
+
line: typeof line.line === 'number' ? line.line : 0,
|
|
611
|
+
text: typeof line.text === 'string' ? line.text : '',
|
|
612
|
+
}))
|
|
613
|
+
.filter((line) => line.line > 0 || line.text.length > 0)
|
|
614
|
+
.slice(0, 8)
|
|
615
|
+
: [],
|
|
616
|
+
dependencyEdges: asStringArray(evidence.dependencyEdges, 8),
|
|
617
|
+
boundary: typeof evidence.boundary === 'string' ? evidence.boundary : null,
|
|
618
|
+
explanation: typeof evidence.explanation === 'string' ? evidence.explanation : null,
|
|
619
|
+
}
|
|
620
|
+
: null,
|
|
621
|
+
remediationGuidance: remediationGuidance
|
|
622
|
+
? {
|
|
623
|
+
actionability: typeof remediationGuidance.actionability === 'string'
|
|
624
|
+
? remediationGuidance.actionability
|
|
625
|
+
: null,
|
|
626
|
+
evidenceTier: typeof remediationGuidance.evidenceTier === 'string'
|
|
627
|
+
? remediationGuidance.evidenceTier
|
|
628
|
+
: null,
|
|
629
|
+
minimalCorrection: typeof remediationGuidance.minimalCorrection === 'string'
|
|
630
|
+
? remediationGuidance.minimalCorrection
|
|
631
|
+
: null,
|
|
632
|
+
boundaryToPreserve: typeof remediationGuidance.boundaryToPreserve === 'string'
|
|
633
|
+
? remediationGuidance.boundaryToPreserve
|
|
634
|
+
: null,
|
|
635
|
+
verifyAfterRemediation: typeof remediationGuidance.verifyAfterRemediation === 'string'
|
|
636
|
+
? remediationGuidance.verifyAfterRemediation
|
|
637
|
+
: null,
|
|
638
|
+
uncertainty: asStringArray(remediationGuidance.uncertainty, 6),
|
|
639
|
+
}
|
|
640
|
+
: null,
|
|
641
|
+
};
|
|
642
|
+
})
|
|
643
|
+
.slice(0, 8)
|
|
644
|
+
: [];
|
|
645
|
+
const narratives = Array.isArray(drift.narratives)
|
|
646
|
+
? drift.narratives
|
|
647
|
+
.map((entry) => asRecord(entry))
|
|
648
|
+
.filter((entry) => entry !== null)
|
|
649
|
+
.map((entry) => ({
|
|
650
|
+
category: typeof entry.category === 'string' ? entry.category : 'unknown',
|
|
651
|
+
severity: typeof entry.severity === 'string' ? entry.severity : 'unknown',
|
|
652
|
+
summary: typeof entry.summary === 'string' ? entry.summary : 'Compressed governance narrative detected.',
|
|
653
|
+
rootCause: typeof entry.rootCause === 'string' ? entry.rootCause : 'Root cause unavailable.',
|
|
654
|
+
operationalRisk: typeof entry.operationalRisk === 'string' ? entry.operationalRisk : 'Operational risk unavailable.',
|
|
655
|
+
remediationBoundary: typeof entry.remediationBoundary === 'string' ? entry.remediationBoundary : 'Keep remediation inside the approved scope.',
|
|
656
|
+
causalChain: asStringArray(entry.causalChain, 8),
|
|
657
|
+
affectedFiles: asStringArray(entry.affectedFiles, 16),
|
|
658
|
+
affectedModules: asStringArray(entry.affectedModules, 16),
|
|
659
|
+
affectedServices: asStringArray(entry.affectedServices, 16),
|
|
660
|
+
}))
|
|
661
|
+
.slice(0, 6)
|
|
662
|
+
: [];
|
|
663
|
+
const riskSynthesisRecord = asRecord(drift.riskSynthesis);
|
|
664
|
+
const priorityCountsRecord = asRecord(riskSynthesisRecord?.priorityCounts);
|
|
665
|
+
const governancePostureRecord = asRecord(drift.governancePosture);
|
|
666
|
+
const posturePriorityCountsRecord = asRecord(governancePostureRecord?.priorityCounts);
|
|
667
|
+
const governanceDecisionsRecord = asRecord(drift.governanceDecisions);
|
|
668
|
+
return {
|
|
669
|
+
source: typeof drift.source === 'string' ? drift.source : null,
|
|
670
|
+
confidence: typeof drift.confidence === 'string' ? drift.confidence : null,
|
|
671
|
+
rolloutRisk: typeof drift.rolloutRisk === 'string' ? drift.rolloutRisk : null,
|
|
672
|
+
unexpectedFiles: asStringArray(drift.unexpectedFiles, 20),
|
|
673
|
+
unexpectedModules: asStringArray(drift.unexpectedModules, 20),
|
|
674
|
+
unexpectedServices: asStringArray(drift.unexpectedServices, 20),
|
|
675
|
+
impactedModules: asStringArray(drift.impactedModules, 20),
|
|
676
|
+
impactedServices: asStringArray(drift.impactedServices, 20),
|
|
677
|
+
impactedRuntimeFlows: asStringArray(drift.impactedRuntimeFlows, 20),
|
|
678
|
+
affectedRolloutUnits: asStringArray(drift.affectedRolloutUnits, 20),
|
|
679
|
+
findings,
|
|
680
|
+
narratives,
|
|
681
|
+
riskSynthesis: riskSynthesisRecord
|
|
682
|
+
? {
|
|
683
|
+
overallRisk: typeof riskSynthesisRecord.overallRisk === 'string' ? riskSynthesisRecord.overallRisk : null,
|
|
684
|
+
summary: typeof riskSynthesisRecord.summary === 'string' ? riskSynthesisRecord.summary : null,
|
|
685
|
+
primaryNarratives: asStringArray(riskSynthesisRecord.primaryNarratives, 6),
|
|
686
|
+
rawFindingCount: typeof riskSynthesisRecord.rawFindingCount === 'number' ? riskSynthesisRecord.rawFindingCount : null,
|
|
687
|
+
compressedNarrativeCount: typeof riskSynthesisRecord.compressedNarrativeCount === 'number'
|
|
688
|
+
? riskSynthesisRecord.compressedNarrativeCount
|
|
689
|
+
: null,
|
|
690
|
+
authExposure: riskSynthesisRecord.authExposure === true,
|
|
691
|
+
infraExposure: riskSynthesisRecord.infraExposure === true,
|
|
692
|
+
deploymentExposure: riskSynthesisRecord.deploymentExposure === true,
|
|
693
|
+
dependencyExposure: riskSynthesisRecord.dependencyExposure === true,
|
|
694
|
+
transitiveImpactCount: typeof riskSynthesisRecord.transitiveImpactCount === 'number'
|
|
695
|
+
? riskSynthesisRecord.transitiveImpactCount
|
|
696
|
+
: null,
|
|
697
|
+
runtimeFlowExposure: riskSynthesisRecord.runtimeFlowExposure === true,
|
|
698
|
+
externalSideEffectExposure: riskSynthesisRecord.externalSideEffectExposure === true,
|
|
699
|
+
stateOwnershipExposure: riskSynthesisRecord.stateOwnershipExposure === true,
|
|
700
|
+
affectedRolloutUnits: asStringArray(riskSynthesisRecord.affectedRolloutUnits, 12),
|
|
701
|
+
cascadingRisk: typeof riskSynthesisRecord.cascadingRisk === 'string'
|
|
702
|
+
? riskSynthesisRecord.cascadingRisk
|
|
703
|
+
: null,
|
|
704
|
+
rolloutTrust: typeof riskSynthesisRecord.rolloutTrust === 'string'
|
|
705
|
+
? riskSynthesisRecord.rolloutTrust
|
|
706
|
+
: null,
|
|
707
|
+
governanceGate: typeof riskSynthesisRecord.governanceGate === 'string'
|
|
708
|
+
? riskSynthesisRecord.governanceGate
|
|
709
|
+
: null,
|
|
710
|
+
postureSummary: typeof riskSynthesisRecord.postureSummary === 'string'
|
|
711
|
+
? riskSynthesisRecord.postureSummary
|
|
712
|
+
: null,
|
|
713
|
+
priorityCounts: priorityCountsRecord
|
|
714
|
+
? {
|
|
715
|
+
p0RolloutBlockers: typeof priorityCountsRecord.p0RolloutBlockers === 'number'
|
|
716
|
+
? priorityCountsRecord.p0RolloutBlockers
|
|
717
|
+
: 0,
|
|
718
|
+
p1ArchitectureBlockers: typeof priorityCountsRecord.p1ArchitectureBlockers === 'number'
|
|
719
|
+
? priorityCountsRecord.p1ArchitectureBlockers
|
|
720
|
+
: 0,
|
|
721
|
+
p2ReviewRequired: typeof priorityCountsRecord.p2ReviewRequired === 'number'
|
|
722
|
+
? priorityCountsRecord.p2ReviewRequired
|
|
723
|
+
: 0,
|
|
724
|
+
p3Advisory: typeof priorityCountsRecord.p3Advisory === 'number'
|
|
725
|
+
? priorityCountsRecord.p3Advisory
|
|
726
|
+
: 0,
|
|
727
|
+
}
|
|
728
|
+
: null,
|
|
729
|
+
remediationOrder: asStringArray(riskSynthesisRecord.remediationOrder, 12),
|
|
730
|
+
}
|
|
731
|
+
: null,
|
|
732
|
+
governancePosture: governancePostureRecord
|
|
733
|
+
? {
|
|
734
|
+
rolloutTrust: typeof governancePostureRecord.rolloutTrust === 'string'
|
|
735
|
+
? governancePostureRecord.rolloutTrust
|
|
736
|
+
: null,
|
|
737
|
+
governanceGate: typeof governancePostureRecord.governanceGate === 'string'
|
|
738
|
+
? governancePostureRecord.governanceGate
|
|
739
|
+
: null,
|
|
740
|
+
summary: typeof governancePostureRecord.summary === 'string'
|
|
741
|
+
? governancePostureRecord.summary
|
|
742
|
+
: null,
|
|
743
|
+
reasons: asStringArray(governancePostureRecord.reasons, 6),
|
|
744
|
+
priorityCounts: posturePriorityCountsRecord
|
|
745
|
+
? {
|
|
746
|
+
p0RolloutBlockers: typeof posturePriorityCountsRecord.p0RolloutBlockers === 'number'
|
|
747
|
+
? posturePriorityCountsRecord.p0RolloutBlockers
|
|
748
|
+
: 0,
|
|
749
|
+
p1ArchitectureBlockers: typeof posturePriorityCountsRecord.p1ArchitectureBlockers === 'number'
|
|
750
|
+
? posturePriorityCountsRecord.p1ArchitectureBlockers
|
|
751
|
+
: 0,
|
|
752
|
+
p2ReviewRequired: typeof posturePriorityCountsRecord.p2ReviewRequired === 'number'
|
|
753
|
+
? posturePriorityCountsRecord.p2ReviewRequired
|
|
754
|
+
: 0,
|
|
755
|
+
p3Advisory: typeof posturePriorityCountsRecord.p3Advisory === 'number'
|
|
756
|
+
? posturePriorityCountsRecord.p3Advisory
|
|
757
|
+
: 0,
|
|
758
|
+
}
|
|
759
|
+
: null,
|
|
760
|
+
remediationOrder: asStringArray(governancePostureRecord.remediationOrder, 12),
|
|
761
|
+
}
|
|
762
|
+
: null,
|
|
763
|
+
governanceDecisions: governanceDecisionsRecord
|
|
764
|
+
? {
|
|
765
|
+
sourcePath: typeof governanceDecisionsRecord.sourcePath === 'string'
|
|
766
|
+
? governanceDecisionsRecord.sourcePath
|
|
767
|
+
: null,
|
|
768
|
+
decisionsApplied: typeof governanceDecisionsRecord.decisionsApplied === 'number'
|
|
769
|
+
? governanceDecisionsRecord.decisionsApplied
|
|
770
|
+
: 0,
|
|
771
|
+
activeOverrides: typeof governanceDecisionsRecord.activeOverrides === 'number'
|
|
772
|
+
? governanceDecisionsRecord.activeOverrides
|
|
773
|
+
: 0,
|
|
774
|
+
expiredOverrides: typeof governanceDecisionsRecord.expiredOverrides === 'number'
|
|
775
|
+
? governanceDecisionsRecord.expiredOverrides
|
|
776
|
+
: 0,
|
|
777
|
+
findingsChanged: typeof governanceDecisionsRecord.findingsChanged === 'number'
|
|
778
|
+
? governanceDecisionsRecord.findingsChanged
|
|
779
|
+
: 0,
|
|
780
|
+
lineage: Array.isArray(governanceDecisionsRecord.lineage)
|
|
781
|
+
? governanceDecisionsRecord.lineage
|
|
782
|
+
.map((entry) => extractGovernanceDecisionLineage(entry))
|
|
783
|
+
.filter((entry) => entry !== null)
|
|
784
|
+
.slice(0, 12)
|
|
785
|
+
: [],
|
|
786
|
+
}
|
|
787
|
+
: null,
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
function extractIntentGovernance(verifyOutput) {
|
|
791
|
+
const intentGovernance = asRecord(verifyOutput.intentGovernance);
|
|
792
|
+
if (!intentGovernance) {
|
|
793
|
+
return null;
|
|
794
|
+
}
|
|
795
|
+
return {
|
|
796
|
+
source: typeof intentGovernance.source === 'string' ? intentGovernance.source : null,
|
|
797
|
+
deterministic: intentGovernance.deterministic === true,
|
|
798
|
+
flagged: intentGovernance.flagged === true,
|
|
799
|
+
confidence: typeof intentGovernance.confidence === 'string' ? intentGovernance.confidence : null,
|
|
800
|
+
rolloutRisk: typeof intentGovernance.rolloutRisk === 'string' ? intentGovernance.rolloutRisk : null,
|
|
801
|
+
canonicalFindingCount: typeof intentGovernance.canonicalFindingCount === 'number' ? intentGovernance.canonicalFindingCount : null,
|
|
802
|
+
blockingFindingCount: typeof intentGovernance.blockingFindingCount === 'number' ? intentGovernance.blockingFindingCount : null,
|
|
803
|
+
advisoryFindingCount: typeof intentGovernance.advisoryFindingCount === 'number' ? intentGovernance.advisoryFindingCount : null,
|
|
804
|
+
riskSummary: typeof intentGovernance.riskSummary === 'string' ? intentGovernance.riskSummary : null,
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
function extractGraphImpact(verifyOutput) {
|
|
808
|
+
const blastRadius = asRecord(verifyOutput.blastRadius);
|
|
809
|
+
if (!blastRadius) {
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
return {
|
|
813
|
+
affectedServices: asStringArray(blastRadius.affectedServices, 20),
|
|
814
|
+
impactedModules: asStringArray(blastRadius.impactedModules, 20),
|
|
815
|
+
impactedServices: asStringArray(blastRadius.impactedServices, 20),
|
|
816
|
+
transitiveImpactCount: typeof blastRadius.transitiveImpactCount === 'number' ? blastRadius.transitiveImpactCount : null,
|
|
817
|
+
rolloutComplexity: typeof blastRadius.rolloutComplexity === 'string' ? blastRadius.rolloutComplexity : null,
|
|
818
|
+
affectedRuntimeFlows: asStringArray(blastRadius.affectedRuntimeFlows, 20),
|
|
819
|
+
affectedRolloutUnits: asStringArray(blastRadius.affectedRolloutUnits, 20),
|
|
820
|
+
cascadingRisk: typeof blastRadius.cascadingRisk === 'string' ? blastRadius.cascadingRisk : null,
|
|
821
|
+
stateOwnershipExposure: blastRadius.stateOwnershipExposure === true,
|
|
822
|
+
externalSideEffectExposure: blastRadius.externalSideEffectExposure === true,
|
|
823
|
+
authTouched: blastRadius.authTouched === true,
|
|
824
|
+
apiTouched: blastRadius.apiTouched === true,
|
|
825
|
+
infraTouched: blastRadius.infraTouched === true,
|
|
826
|
+
deploymentTouched: blastRadius.deploymentTouched === true,
|
|
827
|
+
dependencyManifestTouched: blastRadius.dependencyManifestTouched === true,
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
function deriveModulePathForExport(filePath) {
|
|
831
|
+
const normalized = filePath.replace(/\\/g, '/').replace(/^\.\//, '').trim();
|
|
832
|
+
const parts = normalized.split('/').filter(Boolean);
|
|
833
|
+
if (parts.length <= 1)
|
|
834
|
+
return parts[0] || normalized;
|
|
835
|
+
if (['src', 'app', 'apps', 'services', 'packages', 'libs', 'lib', 'web'].includes(parts[0]) && parts.length >= 2) {
|
|
836
|
+
return `${parts[0]}/${parts[1]}`;
|
|
837
|
+
}
|
|
838
|
+
return parts[0];
|
|
839
|
+
}
|
|
840
|
+
function selectRelevantNarratives(driftIntelligence, filePath, ruleId) {
|
|
841
|
+
if (!driftIntelligence || driftIntelligence.narratives.length === 0) {
|
|
842
|
+
return [];
|
|
843
|
+
}
|
|
844
|
+
const moduleName = deriveModulePathForExport(filePath);
|
|
845
|
+
const driftRuleCategory = ruleId.startsWith('drift_') && ruleId.includes(':')
|
|
846
|
+
? ruleId.split(':').slice(1).join(':')
|
|
847
|
+
: null;
|
|
848
|
+
const matched = driftIntelligence.narratives.filter((entry) => entry.affectedFiles.includes(filePath)
|
|
849
|
+
|| entry.affectedModules.includes(moduleName)
|
|
850
|
+
|| (driftRuleCategory ? entry.category.includes(driftRuleCategory.replace('drift_intelligence:', '')) : false));
|
|
851
|
+
const selected = matched.length > 0 ? matched : driftIntelligence.narratives.slice(0, 3);
|
|
852
|
+
return selected.slice(0, 3).map((entry) => ({
|
|
853
|
+
category: entry.category,
|
|
854
|
+
severity: entry.severity,
|
|
855
|
+
summary: entry.summary,
|
|
856
|
+
rootCause: entry.rootCause,
|
|
857
|
+
operationalRisk: entry.operationalRisk,
|
|
858
|
+
remediationBoundary: entry.remediationBoundary,
|
|
859
|
+
causalChain: entry.causalChain.slice(0, 5),
|
|
860
|
+
}));
|
|
861
|
+
}
|
|
862
|
+
function dedupeStrings(values, limit = 12) {
|
|
863
|
+
return [...new Set(values.map((value) => value.trim()).filter(Boolean))].slice(0, limit);
|
|
864
|
+
}
|
|
865
|
+
function deriveSemanticExportInsights(engineeringContext, driftIntelligence, relevantNarratives, filePath) {
|
|
866
|
+
const moduleName = deriveModulePathForExport(filePath);
|
|
867
|
+
const touchedOwnership = engineeringContext?.ownershipBoundaries.filter((boundary) => boundary.name === moduleName
|
|
868
|
+
|| driftIntelligence?.unexpectedModules.includes(boundary.name)
|
|
869
|
+
|| driftIntelligence?.unexpectedServices.includes(boundary.name)
|
|
870
|
+
|| relevantNarratives.some((entry) => entry.summary.includes(boundary.name))) || [];
|
|
871
|
+
const violatedContracts = dedupeStrings([
|
|
872
|
+
...(engineeringContext?.semanticExpectations?.contractIds || []),
|
|
873
|
+
...touchedOwnership.flatMap((boundary) => boundary.forbiddenResponsibilities.map((item) => `${boundary.name}:${item}`)),
|
|
874
|
+
], 16);
|
|
875
|
+
const ownershipBoundaryCrossed = dedupeStrings(touchedOwnership.map((boundary) => `${boundary.name} (${boundary.primaryOwner})`), 12);
|
|
876
|
+
const invariantSummaries = dedupeStrings([
|
|
877
|
+
...(engineeringContext?.invariants
|
|
878
|
+
.filter((invariant) => !invariant.boundaryName
|
|
879
|
+
|| touchedOwnership.some((boundary) => boundary.name === invariant.boundaryName)
|
|
880
|
+
|| relevantNarratives.some((entry) => entry.summary.includes(invariant.boundaryName || ''))
|
|
881
|
+
|| invariant.expectation.includes(moduleName))
|
|
882
|
+
.map((invariant) => invariant.expectation) || []),
|
|
883
|
+
...relevantNarratives
|
|
884
|
+
.filter((entry) => entry.category === 'ownership-boundary-breach'
|
|
885
|
+
|| entry.category === 'architectural-invariant-erosion'
|
|
886
|
+
|| entry.category === 'semantic-coupling')
|
|
887
|
+
.map((entry) => entry.rootCause),
|
|
888
|
+
], 12);
|
|
889
|
+
const semanticRiskSummary = relevantNarratives[0]?.operationalRisk
|
|
890
|
+
|| driftIntelligence?.riskSynthesis?.summary
|
|
891
|
+
|| null;
|
|
892
|
+
return {
|
|
893
|
+
violatedContracts,
|
|
894
|
+
ownershipBoundaryCrossed,
|
|
895
|
+
invariantSummaries,
|
|
896
|
+
semanticRiskSummary,
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
function buildMcpContext(surroundingContext, engineeringContext, driftIntelligence, graphImpact, relevantNarratives, semanticInsights, intentGovernance) {
|
|
900
|
+
const lines = [];
|
|
901
|
+
if (engineeringContext?.intentSummary) {
|
|
902
|
+
lines.push(`Intent: ${engineeringContext.intentSummary}`);
|
|
903
|
+
}
|
|
904
|
+
if (engineeringContext) {
|
|
905
|
+
lines.push(`Approved scope: files=${engineeringContext.approvedScope.files.slice(0, 6).join(', ') || 'none'}; modules=${engineeringContext.approvedScope.modules.slice(0, 6).join(', ') || 'none'}; services=${engineeringContext.approvedScope.services.slice(0, 6).join(', ') || 'none'}`);
|
|
906
|
+
}
|
|
907
|
+
if (driftIntelligence?.riskSynthesis?.summary) {
|
|
908
|
+
lines.push(`Risk synthesis: ${driftIntelligence.riskSynthesis.summary}`);
|
|
909
|
+
}
|
|
910
|
+
if (driftIntelligence?.governancePosture?.summary) {
|
|
911
|
+
lines.push(`Governance posture: ${driftIntelligence.governancePosture.governanceGate || 'advisory'} / ${driftIntelligence.governancePosture.rolloutTrust || 'rollout-safe'} — ${driftIntelligence.governancePosture.summary}`);
|
|
912
|
+
}
|
|
913
|
+
if (driftIntelligence?.governanceDecisions && driftIntelligence.governanceDecisions.decisionsApplied > 0) {
|
|
914
|
+
lines.push(`Governance decisions: ${driftIntelligence.governanceDecisions.activeOverrides} active, ${driftIntelligence.governanceDecisions.expiredOverrides} expired/invalid, ${driftIntelligence.governanceDecisions.findingsChanged} changed finding posture.`);
|
|
915
|
+
}
|
|
916
|
+
if (driftIntelligence?.findings.length) {
|
|
917
|
+
driftIntelligence.findings.slice(0, 3).forEach((finding, index) => {
|
|
918
|
+
lines.push(`Drift evidence ${index + 1}: [${finding.priority || 'p2-review-required'} / ${finding.governanceGate || 'review-blocker'} / ${finding.actionability || 'review-required'} / ${finding.evidenceTier || 'unknown-evidence'}] ${finding.message}`);
|
|
919
|
+
if (finding.rolloutTrust) {
|
|
920
|
+
lines.push(`Rollout posture ${index + 1}: ${finding.rolloutTrust}`);
|
|
921
|
+
}
|
|
922
|
+
if (finding.evidence?.explanation) {
|
|
923
|
+
lines.push(`Evidence basis ${index + 1}: ${finding.evidence.explanation}`);
|
|
924
|
+
}
|
|
925
|
+
if (finding.evidence?.changedLines.length) {
|
|
926
|
+
const lineRefs = finding.evidence.changedLines
|
|
927
|
+
.slice(0, 3)
|
|
928
|
+
.map((line) => `${line.file}:${line.line}`)
|
|
929
|
+
.join(', ');
|
|
930
|
+
lines.push(`Changed-line evidence ${index + 1}: ${lineRefs}`);
|
|
931
|
+
}
|
|
932
|
+
if (finding.evidence?.dependencyEdges.length) {
|
|
933
|
+
lines.push(`Dependency edge evidence ${index + 1}: ${finding.evidence.dependencyEdges.slice(0, 4).join(' | ')}`);
|
|
934
|
+
}
|
|
935
|
+
if (finding.relationships.length) {
|
|
936
|
+
lines.push(`Finding relationship ${index + 1}: ${finding.relationships
|
|
937
|
+
.slice(0, 2)
|
|
938
|
+
.map((relationship) => `${relationship.type}->${relationship.targetFindingId}`)
|
|
939
|
+
.join(' | ')}`);
|
|
940
|
+
}
|
|
941
|
+
if (finding.governanceDecision) {
|
|
942
|
+
lines.push(`Governance decision ${index + 1}: ${finding.governanceDecision.state} by ${finding.governanceDecision.actor}; reason=${finding.governanceDecision.reason}; lineage=${finding.governanceDecision.lineageHash}`);
|
|
943
|
+
}
|
|
944
|
+
if (finding.remediationGuidance?.minimalCorrection) {
|
|
945
|
+
lines.push(`Bounded correction ${index + 1}: ${finding.remediationGuidance.minimalCorrection}`);
|
|
946
|
+
}
|
|
947
|
+
if (finding.remediationGuidance?.uncertainty.length) {
|
|
948
|
+
lines.push(`Uncertainty ${index + 1}: ${finding.remediationGuidance.uncertainty.slice(0, 2).join(' | ')}`);
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
if (intentGovernance) {
|
|
953
|
+
lines.push(`Intent governance: source=${intentGovernance.source || 'unknown'}; deterministic=${intentGovernance.deterministic ? 'yes' : 'no'}; findings=${intentGovernance.canonicalFindingCount ?? 0}; blocking=${intentGovernance.blockingFindingCount ?? 0}; rollout=${intentGovernance.rolloutRisk || 'unknown'}`);
|
|
954
|
+
}
|
|
955
|
+
if (semanticInsights.ownershipBoundaryCrossed.length > 0) {
|
|
956
|
+
lines.push(`Ownership boundary: ${semanticInsights.ownershipBoundaryCrossed.join(' | ')}`);
|
|
957
|
+
}
|
|
958
|
+
if (semanticInsights.violatedContracts.length > 0) {
|
|
959
|
+
lines.push(`Violated contracts: ${semanticInsights.violatedContracts.slice(0, 6).join(' | ')}`);
|
|
960
|
+
}
|
|
961
|
+
if (semanticInsights.invariantSummaries.length > 0) {
|
|
962
|
+
lines.push(`Invariant expectations: ${semanticInsights.invariantSummaries.slice(0, 3).join(' | ')}`);
|
|
963
|
+
}
|
|
964
|
+
if (semanticInsights.semanticRiskSummary) {
|
|
965
|
+
lines.push(`Semantic risk: ${semanticInsights.semanticRiskSummary}`);
|
|
966
|
+
}
|
|
967
|
+
if (engineeringContext?.semanticExpectations?.expectedBehaviorKinds.length) {
|
|
968
|
+
lines.push(`Expected runtime behaviors: ${engineeringContext.semanticExpectations.expectedBehaviorKinds.slice(0, 6).join(' | ')}`);
|
|
969
|
+
}
|
|
970
|
+
if (engineeringContext?.semanticExpectations?.expectedRuntimeFlows.length) {
|
|
971
|
+
lines.push(`Expected runtime flows: ${engineeringContext.semanticExpectations.expectedRuntimeFlows.slice(0, 6).join(' | ')}`);
|
|
972
|
+
}
|
|
973
|
+
if (engineeringContext?.semanticExpectations?.expectedRolloutUnits.length) {
|
|
974
|
+
lines.push(`Expected rollout units: ${engineeringContext.semanticExpectations.expectedRolloutUnits.slice(0, 6).join(' | ')}`);
|
|
975
|
+
}
|
|
976
|
+
if (engineeringContext?.runtimeBehaviors.length) {
|
|
977
|
+
const summaries = engineeringContext.runtimeBehaviors
|
|
978
|
+
.slice(0, 4)
|
|
979
|
+
.map((entry) => `${entry.boundaryName}:${entry.behaviorKinds.slice(0, 3).join('/') || 'unknown'}`);
|
|
980
|
+
lines.push(`Runtime behaviors: ${summaries.join(' | ')}`);
|
|
981
|
+
}
|
|
982
|
+
if (engineeringContext?.deploymentBoundaries.length) {
|
|
983
|
+
const summaries = engineeringContext.deploymentBoundaries
|
|
984
|
+
.slice(0, 4)
|
|
985
|
+
.map((entry) => `${entry.name}:${entry.type}:${entry.rolloutUnits.slice(0, 2).join('/') || 'default'}`);
|
|
986
|
+
lines.push(`Deployment boundaries: ${summaries.join(' | ')}`);
|
|
987
|
+
}
|
|
988
|
+
if (relevantNarratives.length > 0) {
|
|
989
|
+
relevantNarratives.forEach((narrative, index) => {
|
|
990
|
+
lines.push(`Narrative ${index + 1}: ${narrative.summary}`);
|
|
991
|
+
lines.push(`Root cause ${index + 1}: ${narrative.rootCause}`);
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
else if (driftIntelligence?.findings.length) {
|
|
995
|
+
lines.push(`Drift: ${driftIntelligence.findings.slice(0, 3).map((entry) => entry.message).join(' | ')}`);
|
|
996
|
+
}
|
|
997
|
+
if (graphImpact) {
|
|
998
|
+
lines.push(`Graph impact: services=${graphImpact.impactedServices.slice(0, 6).join(', ') || 'none'}; modules=${graphImpact.impactedModules.slice(0, 6).join(', ') || 'none'}; rollout=${graphImpact.rolloutComplexity || 'unknown'}`);
|
|
999
|
+
if (graphImpact.affectedRuntimeFlows.length > 0) {
|
|
1000
|
+
lines.push(`Runtime flows impacted: ${graphImpact.affectedRuntimeFlows.slice(0, 6).join(' | ')}`);
|
|
1001
|
+
}
|
|
1002
|
+
if (graphImpact.affectedRolloutUnits.length > 0) {
|
|
1003
|
+
lines.push(`Rollout units impacted: ${graphImpact.affectedRolloutUnits.slice(0, 6).join(' | ')}`);
|
|
1004
|
+
}
|
|
1005
|
+
if (graphImpact.cascadingRisk) {
|
|
1006
|
+
lines.push(`Cascading risk: ${graphImpact.cascadingRisk}`);
|
|
1007
|
+
}
|
|
1008
|
+
if (graphImpact.stateOwnershipExposure) {
|
|
1009
|
+
lines.push('State ownership risk: runtime state mutation spans multiple boundaries.');
|
|
1010
|
+
}
|
|
1011
|
+
if (graphImpact.externalSideEffectExposure) {
|
|
1012
|
+
lines.push('External side effects detected in the affected runtime path.');
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
if (surroundingContext.trim().length > 0) {
|
|
1016
|
+
lines.push('Code context:');
|
|
1017
|
+
lines.push(surroundingContext);
|
|
1018
|
+
}
|
|
1019
|
+
return lines.join('\n');
|
|
1020
|
+
}
|
|
1021
|
+
function resolveReplayChecksum(verifyOutput) {
|
|
1022
|
+
const direct = typeof verifyOutput.replayChecksum === 'string' && verifyOutput.replayChecksum.trim().length > 0
|
|
1023
|
+
? verifyOutput.replayChecksum.trim()
|
|
1024
|
+
: null;
|
|
1025
|
+
if (direct)
|
|
1026
|
+
return direct;
|
|
1027
|
+
const nested = verifyOutput.governanceVerification?.replayChecksum;
|
|
1028
|
+
return typeof nested === 'string' && nested.trim().length > 0 ? nested.trim() : null;
|
|
1029
|
+
}
|
|
1030
|
+
function resolveReplayMode(verifyOutput) {
|
|
1031
|
+
const direct = typeof verifyOutput.replayMode === 'string' && verifyOutput.replayMode.trim().length > 0
|
|
1032
|
+
? verifyOutput.replayMode.trim()
|
|
1033
|
+
: null;
|
|
1034
|
+
if (direct)
|
|
1035
|
+
return direct;
|
|
1036
|
+
const policyOnly = verifyOutput.policyOnly === true;
|
|
1037
|
+
const mode = typeof verifyOutput.mode === 'string' ? verifyOutput.mode : '';
|
|
1038
|
+
if (policyOnly || mode === 'policy_only') {
|
|
1039
|
+
return 'local-structural';
|
|
1040
|
+
}
|
|
1041
|
+
return null;
|
|
1042
|
+
}
|
|
1043
|
+
function extractCodeSpan(projectRoot, filePath, line) {
|
|
1044
|
+
if (!filePath || line === null) {
|
|
1045
|
+
return { codeSpan: '(file or line not available)', surroundingContext: '' };
|
|
1046
|
+
}
|
|
1047
|
+
const fullPath = (0, path_1.resolve)(projectRoot, filePath);
|
|
1048
|
+
if (!(0, fs_1.existsSync)(fullPath)) {
|
|
1049
|
+
return { codeSpan: `(file not found: ${filePath})`, surroundingContext: '' };
|
|
1050
|
+
}
|
|
1051
|
+
try {
|
|
1052
|
+
const content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
|
|
1053
|
+
const lines = content.split('\n');
|
|
1054
|
+
const zeroIdx = line - 1;
|
|
1055
|
+
const targetLine = lines[zeroIdx] ?? '';
|
|
1056
|
+
const contextStart = Math.max(0, zeroIdx - 5);
|
|
1057
|
+
const contextEnd = Math.min(lines.length - 1, zeroIdx + 5);
|
|
1058
|
+
const contextLines = [];
|
|
1059
|
+
for (let i = contextStart; i <= contextEnd; i++) {
|
|
1060
|
+
const prefix = i === zeroIdx ? '→ ' : ' ';
|
|
1061
|
+
contextLines.push(`${String(i + 1).padStart(4)} ${prefix}${lines[i]}`);
|
|
1062
|
+
}
|
|
1063
|
+
return {
|
|
1064
|
+
codeSpan: targetLine.trim(),
|
|
1065
|
+
surroundingContext: contextLines.join('\n'),
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
catch {
|
|
1069
|
+
return { codeSpan: '(could not read file)', surroundingContext: '' };
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
//# sourceMappingURL=remediate-export.js.map
|