@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
/**
|
|
7
|
+
* Run: npx tsx packages/telemetry/src/__tests__/harvest-verify.test.ts
|
|
8
|
+
*/
|
|
9
|
+
const node_test_1 = require("node:test");
|
|
10
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
11
|
+
const harvest_verify_1 = require("../harvest-verify");
|
|
12
|
+
const trust_scoring_1 = require("../trust-scoring");
|
|
13
|
+
const leaderboards_1 = require("../precision/leaderboards");
|
|
14
|
+
const contracts_1 = require("../contracts");
|
|
15
|
+
(0, node_test_1.describe)('harvestGovernanceVerifyCompleted', () => {
|
|
16
|
+
(0, node_test_1.test)('aggregates counts without leaking excerpts', () => {
|
|
17
|
+
const canonical = {
|
|
18
|
+
verdict: 'FAIL',
|
|
19
|
+
ciMode: true,
|
|
20
|
+
policyOnly: false,
|
|
21
|
+
governanceVerification: {
|
|
22
|
+
schemaVersion: 'v1',
|
|
23
|
+
generatedAt: '2026-01-01T00:00:00.000Z',
|
|
24
|
+
compressedDuplicateCount: 2,
|
|
25
|
+
replayIntegrity: { status: 'exact', missingArtifacts: [], provenanceMismatches: [], graphMismatches: [], semanticTruncationMismatches: [], notes: [] },
|
|
26
|
+
findings: [
|
|
27
|
+
{
|
|
28
|
+
id: 'a',
|
|
29
|
+
severity: 'BLOCKING',
|
|
30
|
+
determinismClassification: 'deterministic-structural',
|
|
31
|
+
suppressionMetadata: { suppressed: true, directive: 'suppress' },
|
|
32
|
+
structuralMetadata: { ruleId: 'SR001' },
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'b',
|
|
36
|
+
severity: 'ADVISORY',
|
|
37
|
+
determinismClassification: 'heuristic-advisory',
|
|
38
|
+
structuralMetadata: { ruleId: 'SR002' },
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
const out = (0, harvest_verify_1.harvestGovernanceVerifyCompleted)(canonical);
|
|
44
|
+
strict_1.default.ok(out);
|
|
45
|
+
strict_1.default.equal(out.payload.governanceFindingCount, 2);
|
|
46
|
+
strict_1.default.equal(out.payload.suppressedFindingCount, 1);
|
|
47
|
+
strict_1.default.equal(out.payload.structuralRuleTriggerHistogram.SR001, 1);
|
|
48
|
+
strict_1.default.equal(out.payload.structuralRuleSuppressionHistogram.SR001, 1);
|
|
49
|
+
strict_1.default.equal(out.payload.replayIntegrityStatus, 'exact');
|
|
50
|
+
strict_1.default.ok(out.findingSetDigest.length === 64);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
(0, node_test_1.describe)('trust and leaderboards', () => {
|
|
54
|
+
(0, node_test_1.test)('bounded scores', () => {
|
|
55
|
+
const canonical = (0, harvest_verify_1.harvestGovernanceVerifyCompleted)({
|
|
56
|
+
verdict: 'PASS',
|
|
57
|
+
governanceVerification: {
|
|
58
|
+
findings: [
|
|
59
|
+
{
|
|
60
|
+
id: 'x',
|
|
61
|
+
severity: 'BLOCKING',
|
|
62
|
+
determinismClassification: 'deterministic-structural',
|
|
63
|
+
suppressionMetadata: { suppressed: false },
|
|
64
|
+
structuralMetadata: { ruleId: 'SR010' },
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
compressedDuplicateCount: 0,
|
|
68
|
+
replayIntegrity: { status: 'bounded-degradation', missingArtifacts: ['a'], provenanceMismatches: [], graphMismatches: [], semanticTruncationMismatches: [], notes: [] },
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
strict_1.default.ok(canonical);
|
|
72
|
+
const t = (0, trust_scoring_1.trustFromVerifyPayload)(canonical.payload);
|
|
73
|
+
strict_1.default.ok(t.governanceUsefulnessScore >= 0 && t.governanceUsefulnessScore <= 1);
|
|
74
|
+
strict_1.default.equal(t.replayTrustScore, 0.65);
|
|
75
|
+
const ev = {
|
|
76
|
+
schemaVersion: contracts_1.GOVERNANCE_TELEMETRY_SCHEMA_VERSION,
|
|
77
|
+
emittedAt: '2026-01-01T00:00:00.000Z',
|
|
78
|
+
eventType: 'governance.verify.completed',
|
|
79
|
+
findingSetDigest: 'x'.repeat(64),
|
|
80
|
+
payload: canonical.payload,
|
|
81
|
+
};
|
|
82
|
+
const rollup = (0, leaderboards_1.rollupRulePrecisionFromEvents)([ev]);
|
|
83
|
+
const noisy = (0, leaderboards_1.noisyRuleLeaderboard)(rollup);
|
|
84
|
+
strict_1.default.ok(Array.isArray(noisy));
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governance telemetry contracts — deterministic, privacy-bounded, replay-friendly.
|
|
3
|
+
* No hidden network analytics; all persistence is explicit local files under .neurcode/telemetry.
|
|
4
|
+
*/
|
|
5
|
+
export declare const GOVERNANCE_TELEMETRY_SCHEMA_VERSION: "2026-05-11.telemetry.v1";
|
|
6
|
+
/** High-level event kinds (extend additively). */
|
|
7
|
+
export type GovernanceTelemetryEventType = 'governance.verify.completed' | 'finding.viewed' | 'finding.acknowledged' | 'finding.suppressed' | 'finding.waived' | 'finding.ignored' | 'finding.fixed' | 'merge.after_blocking' | 'replay.artifact.opened' | 'replay.artifact.ignored' | 'ci.bypass_attempt' | 'rule.trigger' | 'reviewer.interaction';
|
|
8
|
+
export interface GovernanceTelemetryEnvelope {
|
|
9
|
+
schemaVersion: typeof GOVERNANCE_TELEMETRY_SCHEMA_VERSION;
|
|
10
|
+
/** ISO-8601; wall clock for ordering only — replays must not depend on exact instant. */
|
|
11
|
+
emittedAt: string;
|
|
12
|
+
eventType: GovernanceTelemetryEventType;
|
|
13
|
+
/** Optional correlation to provenance when caller has a run id (UUID). */
|
|
14
|
+
runId?: string | null;
|
|
15
|
+
/** Stable digest of finding ids for this batch (sha256 hex, 64 chars). */
|
|
16
|
+
findingSetDigest?: string;
|
|
17
|
+
payload: GovernanceTelemetryPayload;
|
|
18
|
+
}
|
|
19
|
+
export type GovernanceTelemetryPayload = GovernanceVerifyCompletedPayload | FindingLifecyclePayload | RuleTriggerPayload | ReplayArtifactPayload | CiBypassPayload | ReviewerInteractionPayload | Record<string, never>;
|
|
20
|
+
/** Emitted once per verify exit path when canonical JSON is available. */
|
|
21
|
+
export interface GovernanceVerifyCompletedPayload {
|
|
22
|
+
verdict: 'PASS' | 'FAIL' | 'WARN' | string;
|
|
23
|
+
governanceFindingCount: number;
|
|
24
|
+
blockingFindingCount: number;
|
|
25
|
+
advisoryFindingCount: number;
|
|
26
|
+
determinismHistogram: Record<string, number>;
|
|
27
|
+
suppressedFindingCount: number;
|
|
28
|
+
waivedFindingCount: number;
|
|
29
|
+
structuralRuleTriggerHistogram: Record<string, number>;
|
|
30
|
+
structuralRuleSuppressionHistogram: Record<string, number>;
|
|
31
|
+
compressedDuplicateCount: number;
|
|
32
|
+
replayIntegrityStatus?: 'exact' | 'bounded-degradation' | 'invalidated' | null;
|
|
33
|
+
ciMode: boolean;
|
|
34
|
+
policyOnly: boolean;
|
|
35
|
+
/** Counts only — never file paths or code excerpts. */
|
|
36
|
+
mergeAfterBlocking?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface FindingLifecyclePayload {
|
|
39
|
+
findingId: string;
|
|
40
|
+
ruleId?: string;
|
|
41
|
+
action: 'viewed' | 'acknowledged' | 'suppressed' | 'waived' | 'ignored' | 'fixed';
|
|
42
|
+
}
|
|
43
|
+
export interface RuleTriggerPayload {
|
|
44
|
+
ruleId: string;
|
|
45
|
+
count: number;
|
|
46
|
+
}
|
|
47
|
+
export interface ReplayArtifactPayload {
|
|
48
|
+
artifactKind: 'evidence' | 'execution' | 'digest';
|
|
49
|
+
action: 'opened' | 'ignored';
|
|
50
|
+
}
|
|
51
|
+
export interface CiBypassPayload {
|
|
52
|
+
channel: 'env' | 'flag' | 'workflow' | 'unknown';
|
|
53
|
+
detail?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface ReviewerInteractionPayload {
|
|
56
|
+
kind: 'summary_expand' | 'summary_collapse' | 'comment_reply' | 'other';
|
|
57
|
+
signal?: string;
|
|
58
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Governance telemetry contracts — deterministic, privacy-bounded, replay-friendly.
|
|
4
|
+
* No hidden network analytics; all persistence is explicit local files under .neurcode/telemetry.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GOVERNANCE_TELEMETRY_SCHEMA_VERSION = void 0;
|
|
8
|
+
exports.GOVERNANCE_TELEMETRY_SCHEMA_VERSION = '2026-05-11.telemetry.v1';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GovernanceVerifyCompletedPayload } from './contracts';
|
|
2
|
+
/**
|
|
3
|
+
* Derive a privacy-safe, bounded payload from canonical verify JSON.
|
|
4
|
+
* Does not copy excerpts, titles, or file paths.
|
|
5
|
+
*/
|
|
6
|
+
export declare function harvestGovernanceVerifyCompleted(canonical: Record<string, unknown> | null): {
|
|
7
|
+
payload: GovernanceVerifyCompletedPayload;
|
|
8
|
+
findingSetDigest: string;
|
|
9
|
+
} | null;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.harvestGovernanceVerifyCompleted = harvestGovernanceVerifyCompleted;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
function isRecord(x) {
|
|
6
|
+
return typeof x === 'object' && x !== null && !Array.isArray(x);
|
|
7
|
+
}
|
|
8
|
+
function asString(x) {
|
|
9
|
+
return typeof x === 'string' ? x : undefined;
|
|
10
|
+
}
|
|
11
|
+
function asBoolean(x) {
|
|
12
|
+
return typeof x === 'boolean' ? x : undefined;
|
|
13
|
+
}
|
|
14
|
+
function asNumber(x) {
|
|
15
|
+
return typeof x === 'number' && Number.isFinite(x) ? x : undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Derive a privacy-safe, bounded payload from canonical verify JSON.
|
|
19
|
+
* Does not copy excerpts, titles, or file paths.
|
|
20
|
+
*/
|
|
21
|
+
function harvestGovernanceVerifyCompleted(canonical) {
|
|
22
|
+
if (!canonical) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const verdict = asString(canonical.verdict) ?? 'UNKNOWN';
|
|
26
|
+
const ciMode = asBoolean(canonical.ciMode) ?? false;
|
|
27
|
+
const policyOnly = asBoolean(canonical.policyOnly) ?? false;
|
|
28
|
+
const gv = canonical.governanceVerification;
|
|
29
|
+
if (!isRecord(gv)) {
|
|
30
|
+
const payload = {
|
|
31
|
+
verdict,
|
|
32
|
+
governanceFindingCount: 0,
|
|
33
|
+
blockingFindingCount: 0,
|
|
34
|
+
advisoryFindingCount: 0,
|
|
35
|
+
determinismHistogram: {},
|
|
36
|
+
suppressedFindingCount: 0,
|
|
37
|
+
waivedFindingCount: 0,
|
|
38
|
+
structuralRuleTriggerHistogram: {},
|
|
39
|
+
structuralRuleSuppressionHistogram: {},
|
|
40
|
+
compressedDuplicateCount: 0,
|
|
41
|
+
replayIntegrityStatus: null,
|
|
42
|
+
ciMode,
|
|
43
|
+
policyOnly,
|
|
44
|
+
};
|
|
45
|
+
const findingSetDigest = digestFindingIds([]);
|
|
46
|
+
return { payload, findingSetDigest };
|
|
47
|
+
}
|
|
48
|
+
const findingsRaw = gv.findings;
|
|
49
|
+
const findings = Array.isArray(findingsRaw) ? findingsRaw.filter(isRecord) : [];
|
|
50
|
+
const determinismHistogram = {};
|
|
51
|
+
let blockingFindingCount = 0;
|
|
52
|
+
let advisoryFindingCount = 0;
|
|
53
|
+
let suppressedFindingCount = 0;
|
|
54
|
+
let waivedFindingCount = 0;
|
|
55
|
+
const structuralRuleTriggerHistogram = {};
|
|
56
|
+
const structuralRuleSuppressionHistogram = {};
|
|
57
|
+
const findingIds = [];
|
|
58
|
+
for (const f of findings) {
|
|
59
|
+
const id = asString(f.id);
|
|
60
|
+
if (id) {
|
|
61
|
+
findingIds.push(id);
|
|
62
|
+
}
|
|
63
|
+
const sev = asString(f.severity);
|
|
64
|
+
if (sev === 'BLOCKING') {
|
|
65
|
+
blockingFindingCount += 1;
|
|
66
|
+
}
|
|
67
|
+
else if (sev === 'ADVISORY') {
|
|
68
|
+
advisoryFindingCount += 1;
|
|
69
|
+
}
|
|
70
|
+
const det = asString(f.determinismClassification) ?? 'unknown';
|
|
71
|
+
determinismHistogram[det] = (determinismHistogram[det] ?? 0) + 1;
|
|
72
|
+
const sup = f.suppressionMetadata;
|
|
73
|
+
let suppressed = false;
|
|
74
|
+
let waived = false;
|
|
75
|
+
if (isRecord(sup)) {
|
|
76
|
+
suppressed = sup.suppressed === true;
|
|
77
|
+
const directive = asString(sup.directive);
|
|
78
|
+
waived = directive === 'waive' || directive === 'waiver';
|
|
79
|
+
}
|
|
80
|
+
if (suppressed) {
|
|
81
|
+
suppressedFindingCount += 1;
|
|
82
|
+
}
|
|
83
|
+
if (waived) {
|
|
84
|
+
waivedFindingCount += 1;
|
|
85
|
+
}
|
|
86
|
+
const sm = f.structuralMetadata;
|
|
87
|
+
const ruleId = isRecord(sm) ? asString(sm.ruleId) : undefined;
|
|
88
|
+
if (ruleId) {
|
|
89
|
+
structuralRuleTriggerHistogram[ruleId] = (structuralRuleTriggerHistogram[ruleId] ?? 0) + 1;
|
|
90
|
+
if (suppressed) {
|
|
91
|
+
structuralRuleSuppressionHistogram[ruleId] =
|
|
92
|
+
(structuralRuleSuppressionHistogram[ruleId] ?? 0) + 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const compressedDuplicateCount = asNumber(gv.compressedDuplicateCount) ?? 0;
|
|
97
|
+
let replayIntegrityStatus = null;
|
|
98
|
+
const ri = gv.replayIntegrity;
|
|
99
|
+
if (isRecord(ri)) {
|
|
100
|
+
const st = asString(ri.status);
|
|
101
|
+
if (st === 'exact' || st === 'bounded-degradation') {
|
|
102
|
+
replayIntegrityStatus = st;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const payload = {
|
|
106
|
+
verdict,
|
|
107
|
+
governanceFindingCount: findings.length,
|
|
108
|
+
blockingFindingCount,
|
|
109
|
+
advisoryFindingCount,
|
|
110
|
+
determinismHistogram,
|
|
111
|
+
suppressedFindingCount,
|
|
112
|
+
waivedFindingCount,
|
|
113
|
+
structuralRuleTriggerHistogram,
|
|
114
|
+
structuralRuleSuppressionHistogram,
|
|
115
|
+
compressedDuplicateCount,
|
|
116
|
+
replayIntegrityStatus,
|
|
117
|
+
ciMode,
|
|
118
|
+
policyOnly,
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
payload,
|
|
122
|
+
findingSetDigest: digestFindingIds(findingIds),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function digestFindingIds(ids) {
|
|
126
|
+
const sorted = [...ids].sort();
|
|
127
|
+
return (0, crypto_1.createHash)('sha256').update(sorted.join('|'), 'utf8').digest('hex');
|
|
128
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { GOVERNANCE_TELEMETRY_SCHEMA_VERSION } from './contracts';
|
|
2
|
+
export type { GovernanceTelemetryEnvelope, GovernanceTelemetryEventType, GovernanceTelemetryPayload, GovernanceVerifyCompletedPayload, FindingLifecyclePayload, RuleTriggerPayload, ReplayArtifactPayload, CiBypassPayload, ReviewerInteractionPayload, } from './contracts';
|
|
3
|
+
export { stableStringify } from './stable-json';
|
|
4
|
+
export { harvestGovernanceVerifyCompleted } from './harvest-verify';
|
|
5
|
+
export { appendGovernanceTelemetryEvent, appendVerifyCompletedFromCanonical, telemetryEventsPath, } from './store';
|
|
6
|
+
export { readGovernanceTelemetryEvents } from './reader';
|
|
7
|
+
export { rollupRulePrecisionFromEvents, noisyRuleLeaderboard, highTrustRuleLeaderboard, } from './precision/leaderboards';
|
|
8
|
+
export type { RulePrecisionRollup, TelemetryRollup } from './precision/leaderboards';
|
|
9
|
+
export { trustFromVerifyPayload, trustFromRollups } from './trust-scoring';
|
|
10
|
+
export type { BoundedTrustScores } from './trust-scoring';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trustFromRollups = exports.trustFromVerifyPayload = exports.highTrustRuleLeaderboard = exports.noisyRuleLeaderboard = exports.rollupRulePrecisionFromEvents = exports.readGovernanceTelemetryEvents = exports.telemetryEventsPath = exports.appendVerifyCompletedFromCanonical = exports.appendGovernanceTelemetryEvent = exports.harvestGovernanceVerifyCompleted = exports.stableStringify = exports.GOVERNANCE_TELEMETRY_SCHEMA_VERSION = void 0;
|
|
4
|
+
var contracts_1 = require("./contracts");
|
|
5
|
+
Object.defineProperty(exports, "GOVERNANCE_TELEMETRY_SCHEMA_VERSION", { enumerable: true, get: function () { return contracts_1.GOVERNANCE_TELEMETRY_SCHEMA_VERSION; } });
|
|
6
|
+
var stable_json_1 = require("./stable-json");
|
|
7
|
+
Object.defineProperty(exports, "stableStringify", { enumerable: true, get: function () { return stable_json_1.stableStringify; } });
|
|
8
|
+
var harvest_verify_1 = require("./harvest-verify");
|
|
9
|
+
Object.defineProperty(exports, "harvestGovernanceVerifyCompleted", { enumerable: true, get: function () { return harvest_verify_1.harvestGovernanceVerifyCompleted; } });
|
|
10
|
+
var store_1 = require("./store");
|
|
11
|
+
Object.defineProperty(exports, "appendGovernanceTelemetryEvent", { enumerable: true, get: function () { return store_1.appendGovernanceTelemetryEvent; } });
|
|
12
|
+
Object.defineProperty(exports, "appendVerifyCompletedFromCanonical", { enumerable: true, get: function () { return store_1.appendVerifyCompletedFromCanonical; } });
|
|
13
|
+
Object.defineProperty(exports, "telemetryEventsPath", { enumerable: true, get: function () { return store_1.telemetryEventsPath; } });
|
|
14
|
+
var reader_1 = require("./reader");
|
|
15
|
+
Object.defineProperty(exports, "readGovernanceTelemetryEvents", { enumerable: true, get: function () { return reader_1.readGovernanceTelemetryEvents; } });
|
|
16
|
+
var leaderboards_1 = require("./precision/leaderboards");
|
|
17
|
+
Object.defineProperty(exports, "rollupRulePrecisionFromEvents", { enumerable: true, get: function () { return leaderboards_1.rollupRulePrecisionFromEvents; } });
|
|
18
|
+
Object.defineProperty(exports, "noisyRuleLeaderboard", { enumerable: true, get: function () { return leaderboards_1.noisyRuleLeaderboard; } });
|
|
19
|
+
Object.defineProperty(exports, "highTrustRuleLeaderboard", { enumerable: true, get: function () { return leaderboards_1.highTrustRuleLeaderboard; } });
|
|
20
|
+
var trust_scoring_1 = require("./trust-scoring");
|
|
21
|
+
Object.defineProperty(exports, "trustFromVerifyPayload", { enumerable: true, get: function () { return trust_scoring_1.trustFromVerifyPayload; } });
|
|
22
|
+
Object.defineProperty(exports, "trustFromRollups", { enumerable: true, get: function () { return trust_scoring_1.trustFromRollups; } });
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { GovernanceTelemetryEnvelope } from '../contracts';
|
|
2
|
+
export interface RulePrecisionRollup {
|
|
3
|
+
ruleId: string;
|
|
4
|
+
triggerCount: number;
|
|
5
|
+
suppressionCount: number;
|
|
6
|
+
suppressionRate: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TelemetryRollup {
|
|
9
|
+
verifyCompletedEvents: number;
|
|
10
|
+
ruleRollups: RulePrecisionRollup[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Aggregate rule-level signals from governance.verify.completed events only.
|
|
14
|
+
* Deterministic: rules sorted by ruleId for stable output order.
|
|
15
|
+
*/
|
|
16
|
+
export declare function rollupRulePrecisionFromEvents(events: GovernanceTelemetryEnvelope[]): TelemetryRollup;
|
|
17
|
+
/** Higher score = more noise (suppressions relative to triggers). */
|
|
18
|
+
export declare function noisyRuleLeaderboard(rollup: TelemetryRollup, limit?: number): RulePrecisionRollup[];
|
|
19
|
+
/** Higher score = fewer suppressions per trigger (reviewer trust proxy). */
|
|
20
|
+
export declare function highTrustRuleLeaderboard(rollup: TelemetryRollup, limit?: number): RulePrecisionRollup[];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rollupRulePrecisionFromEvents = rollupRulePrecisionFromEvents;
|
|
4
|
+
exports.noisyRuleLeaderboard = noisyRuleLeaderboard;
|
|
5
|
+
exports.highTrustRuleLeaderboard = highTrustRuleLeaderboard;
|
|
6
|
+
function isVerifyCompletedPayload(p) {
|
|
7
|
+
return (typeof p === 'object' &&
|
|
8
|
+
p !== null &&
|
|
9
|
+
'structuralRuleTriggerHistogram' in p &&
|
|
10
|
+
'structuralRuleSuppressionHistogram' in p);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Aggregate rule-level signals from governance.verify.completed events only.
|
|
14
|
+
* Deterministic: rules sorted by ruleId for stable output order.
|
|
15
|
+
*/
|
|
16
|
+
function rollupRulePrecisionFromEvents(events) {
|
|
17
|
+
const triggers = {};
|
|
18
|
+
const suppressions = {};
|
|
19
|
+
let verifyCompletedEvents = 0;
|
|
20
|
+
for (const ev of events) {
|
|
21
|
+
if (ev.eventType !== 'governance.verify.completed') {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (!isVerifyCompletedPayload(ev.payload)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
verifyCompletedEvents += 1;
|
|
28
|
+
const p = ev.payload;
|
|
29
|
+
for (const [ruleId, c] of Object.entries(p.structuralRuleTriggerHistogram)) {
|
|
30
|
+
triggers[ruleId] = (triggers[ruleId] ?? 0) + c;
|
|
31
|
+
}
|
|
32
|
+
for (const [ruleId, c] of Object.entries(p.structuralRuleSuppressionHistogram)) {
|
|
33
|
+
suppressions[ruleId] = (suppressions[ruleId] ?? 0) + c;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const ruleIds = new Set([...Object.keys(triggers), ...Object.keys(suppressions)]);
|
|
37
|
+
const ruleRollups = [...ruleIds]
|
|
38
|
+
.sort()
|
|
39
|
+
.map(ruleId => {
|
|
40
|
+
const triggerCount = triggers[ruleId] ?? 0;
|
|
41
|
+
const suppressionCount = suppressions[ruleId] ?? 0;
|
|
42
|
+
const suppressionRate = triggerCount > 0 ? suppressionCount / triggerCount : 0;
|
|
43
|
+
return { ruleId, triggerCount, suppressionCount, suppressionRate };
|
|
44
|
+
});
|
|
45
|
+
return { verifyCompletedEvents, ruleRollups };
|
|
46
|
+
}
|
|
47
|
+
/** Higher score = more noise (suppressions relative to triggers). */
|
|
48
|
+
function noisyRuleLeaderboard(rollup, limit = 20) {
|
|
49
|
+
return [...rollup.ruleRollups]
|
|
50
|
+
.filter(r => r.triggerCount > 0)
|
|
51
|
+
.sort((a, b) => {
|
|
52
|
+
const dr = b.suppressionRate - a.suppressionRate;
|
|
53
|
+
if (dr !== 0) {
|
|
54
|
+
return dr;
|
|
55
|
+
}
|
|
56
|
+
return b.triggerCount - a.triggerCount;
|
|
57
|
+
})
|
|
58
|
+
.slice(0, limit);
|
|
59
|
+
}
|
|
60
|
+
/** Higher score = fewer suppressions per trigger (reviewer trust proxy). */
|
|
61
|
+
function highTrustRuleLeaderboard(rollup, limit = 20) {
|
|
62
|
+
return [...rollup.ruleRollups]
|
|
63
|
+
.filter(r => r.triggerCount >= 3)
|
|
64
|
+
.sort((a, b) => {
|
|
65
|
+
const dr = a.suppressionRate - b.suppressionRate;
|
|
66
|
+
if (dr !== 0) {
|
|
67
|
+
return dr;
|
|
68
|
+
}
|
|
69
|
+
return b.triggerCount - a.triggerCount;
|
|
70
|
+
})
|
|
71
|
+
.slice(0, limit);
|
|
72
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readGovernanceTelemetryEvents = readGovernanceTelemetryEvents;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const contracts_1 = require("./contracts");
|
|
6
|
+
const store_1 = require("./store");
|
|
7
|
+
function isRecord(x) {
|
|
8
|
+
return typeof x === 'object' && x !== null && !Array.isArray(x);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Load all telemetry envelopes from the local JSONL store (newest lines last).
|
|
12
|
+
*/
|
|
13
|
+
function readGovernanceTelemetryEvents(repoRoot) {
|
|
14
|
+
const path = (0, store_1.telemetryEventsPath)(repoRoot);
|
|
15
|
+
if (!(0, fs_1.existsSync)(path)) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
let raw;
|
|
19
|
+
try {
|
|
20
|
+
raw = (0, fs_1.readFileSync)(path, 'utf8');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const out = [];
|
|
26
|
+
for (const line of raw.split('\n')) {
|
|
27
|
+
const t = line.trim();
|
|
28
|
+
if (!t) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const parsed = JSON.parse(t);
|
|
33
|
+
if (!isRecord(parsed)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (parsed.schemaVersion !== contracts_1.GOVERNANCE_TELEMETRY_SCHEMA_VERSION) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
out.push(parsed);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stableStringify = stableStringify;
|
|
4
|
+
/**
|
|
5
|
+
* Deterministic JSON serialization: sorted object keys at every depth.
|
|
6
|
+
* Used so identical logical events stringify identically across Node versions.
|
|
7
|
+
*/
|
|
8
|
+
function stableStringify(value) {
|
|
9
|
+
return JSON.stringify(sortKeysDeep(value));
|
|
10
|
+
}
|
|
11
|
+
function sortKeysDeep(value) {
|
|
12
|
+
if (value === null || typeof value !== 'object') {
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
return value.map(sortKeysDeep);
|
|
17
|
+
}
|
|
18
|
+
const obj = value;
|
|
19
|
+
const out = {};
|
|
20
|
+
for (const key of Object.keys(obj).sort()) {
|
|
21
|
+
out[key] = sortKeysDeep(obj[key]);
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GovernanceTelemetryEnvelope } from './contracts';
|
|
2
|
+
export declare function telemetryEventsPath(repoRoot: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Append one telemetry line. Never throws — calibration must not break verify.
|
|
5
|
+
*/
|
|
6
|
+
export declare function appendGovernanceTelemetryEvent(repoRoot: string, envelope: GovernanceTelemetryEnvelope): void;
|
|
7
|
+
/**
|
|
8
|
+
* Record verify completion from canonical CLI verify JSON (already normalized).
|
|
9
|
+
*/
|
|
10
|
+
export declare function appendVerifyCompletedFromCanonical(repoRoot: string, canonical: Record<string, unknown> | null, runId?: string | null): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.telemetryEventsPath = telemetryEventsPath;
|
|
4
|
+
exports.appendGovernanceTelemetryEvent = appendGovernanceTelemetryEvent;
|
|
5
|
+
exports.appendVerifyCompletedFromCanonical = appendVerifyCompletedFromCanonical;
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const contracts_1 = require("./contracts");
|
|
9
|
+
const harvest_verify_1 = require("./harvest-verify");
|
|
10
|
+
const stable_json_1 = require("./stable-json");
|
|
11
|
+
const REL_DIR = (0, path_1.join)('.neurcode', 'telemetry');
|
|
12
|
+
const EVENTS_FILE = 'governance-events.jsonl';
|
|
13
|
+
function telemetryEventsPath(repoRoot) {
|
|
14
|
+
return (0, path_1.join)(repoRoot, REL_DIR, EVENTS_FILE);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Append one telemetry line. Never throws — calibration must not break verify.
|
|
18
|
+
*/
|
|
19
|
+
function appendGovernanceTelemetryEvent(repoRoot, envelope) {
|
|
20
|
+
try {
|
|
21
|
+
const dir = (0, path_1.join)(repoRoot, REL_DIR);
|
|
22
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
23
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
const line = (0, stable_json_1.stableStringify)({
|
|
26
|
+
...envelope,
|
|
27
|
+
schemaVersion: contracts_1.GOVERNANCE_TELEMETRY_SCHEMA_VERSION,
|
|
28
|
+
});
|
|
29
|
+
(0, fs_1.appendFileSync)(telemetryEventsPath(repoRoot), `${line}\n`, 'utf8');
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// intentional swallow
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Record verify completion from canonical CLI verify JSON (already normalized).
|
|
37
|
+
*/
|
|
38
|
+
function appendVerifyCompletedFromCanonical(repoRoot, canonical, runId) {
|
|
39
|
+
const harvested = (0, harvest_verify_1.harvestGovernanceVerifyCompleted)(canonical);
|
|
40
|
+
if (!harvested) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const envelope = {
|
|
44
|
+
schemaVersion: contracts_1.GOVERNANCE_TELEMETRY_SCHEMA_VERSION,
|
|
45
|
+
emittedAt: new Date().toISOString(),
|
|
46
|
+
eventType: 'governance.verify.completed',
|
|
47
|
+
runId: runId ?? null,
|
|
48
|
+
findingSetDigest: harvested.findingSetDigest,
|
|
49
|
+
payload: harvested.payload,
|
|
50
|
+
};
|
|
51
|
+
appendGovernanceTelemetryEvent(repoRoot, envelope);
|
|
52
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded, explainable trust signals — no opaque ML.
|
|
3
|
+
* All outputs are in [0, 1] unless noted.
|
|
4
|
+
*/
|
|
5
|
+
import type { GovernanceVerifyCompletedPayload } from './contracts';
|
|
6
|
+
import type { TelemetryRollup } from './precision/leaderboards';
|
|
7
|
+
export interface BoundedTrustScores {
|
|
8
|
+
/** 1 − (suppressed findings / max(1, total findings)) from the last completed verify slice. */
|
|
9
|
+
findingTrustScore: number;
|
|
10
|
+
/** Mean of per-rule (1 − suppressionRate) over rules with ≥1 trigger, from rollups. */
|
|
11
|
+
ruleTrustScore: number;
|
|
12
|
+
/** 1 if replay exact, 0.65 if bounded degradation, 0.5 if unknown/missing. */
|
|
13
|
+
replayTrustScore: number;
|
|
14
|
+
/** Density of blocking findings vs advisory (blocking / max(1, total)). */
|
|
15
|
+
reviewerTrustDensity: number;
|
|
16
|
+
/** Harmonic-style blend of finding + rule trust (operational usefulness proxy). */
|
|
17
|
+
governanceUsefulnessScore: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function trustFromVerifyPayload(p: GovernanceVerifyCompletedPayload): BoundedTrustScores;
|
|
20
|
+
export declare function trustFromRollups(rollup: TelemetryRollup): Pick<BoundedTrustScores, 'ruleTrustScore'>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Bounded, explainable trust signals — no opaque ML.
|
|
4
|
+
* All outputs are in [0, 1] unless noted.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.trustFromVerifyPayload = trustFromVerifyPayload;
|
|
8
|
+
exports.trustFromRollups = trustFromRollups;
|
|
9
|
+
function trustFromVerifyPayload(p) {
|
|
10
|
+
const n = Math.max(1, p.governanceFindingCount);
|
|
11
|
+
const findingTrustScore = clamp01(1 - p.suppressedFindingCount / n);
|
|
12
|
+
const ruleIds = Object.keys(p.structuralRuleTriggerHistogram);
|
|
13
|
+
let sum = 0;
|
|
14
|
+
let count = 0;
|
|
15
|
+
for (const ruleId of ruleIds) {
|
|
16
|
+
const t = p.structuralRuleTriggerHistogram[ruleId] ?? 0;
|
|
17
|
+
const s = p.structuralRuleSuppressionHistogram[ruleId] ?? 0;
|
|
18
|
+
if (t <= 0) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
sum += 1 - s / t;
|
|
22
|
+
count += 1;
|
|
23
|
+
}
|
|
24
|
+
const ruleTrustScore = count > 0 ? clamp01(sum / count) : 1;
|
|
25
|
+
let replayTrustScore = 0.5;
|
|
26
|
+
if (p.replayIntegrityStatus === 'exact') {
|
|
27
|
+
replayTrustScore = 1;
|
|
28
|
+
}
|
|
29
|
+
else if (p.replayIntegrityStatus === 'bounded-degradation') {
|
|
30
|
+
replayTrustScore = 0.65;
|
|
31
|
+
}
|
|
32
|
+
const reviewerTrustDensity = clamp01(p.blockingFindingCount / n);
|
|
33
|
+
const governanceUsefulnessScore = clamp01(0.45 * findingTrustScore + 0.35 * ruleTrustScore + 0.2 * replayTrustScore);
|
|
34
|
+
return {
|
|
35
|
+
findingTrustScore,
|
|
36
|
+
ruleTrustScore,
|
|
37
|
+
replayTrustScore,
|
|
38
|
+
reviewerTrustDensity,
|
|
39
|
+
governanceUsefulnessScore,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function trustFromRollups(rollup) {
|
|
43
|
+
const rows = rollup.ruleRollups.filter(r => r.triggerCount > 0);
|
|
44
|
+
if (rows.length === 0) {
|
|
45
|
+
return { ruleTrustScore: 1 };
|
|
46
|
+
}
|
|
47
|
+
const acc = rows.reduce((s, r) => s + (1 - r.suppressionRate), 0) / rows.length;
|
|
48
|
+
return { ruleTrustScore: clamp01(acc) };
|
|
49
|
+
}
|
|
50
|
+
function clamp01(x) {
|
|
51
|
+
if (x < 0) {
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
if (x > 1) {
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
return x;
|
|
58
|
+
}
|