@deftai/directive-core 0.102.0 → 0.104.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/authz/classify.js +167 -4
- package/dist/check/gate-lists.d.ts +3 -2
- package/dist/check/gate-lists.js +5 -2
- package/dist/check/index.d.ts +1 -0
- package/dist/check/index.js +1 -0
- package/dist/check/session-completed-ac.d.ts +39 -0
- package/dist/check/session-completed-ac.js +198 -0
- package/dist/doctor/main.js +12 -7
- package/dist/fs/contained-write.js +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/init-deposit/hygiene.d.ts +7 -1
- package/dist/init-deposit/hygiene.js +11 -3
- package/dist/init-deposit/scaffold.d.ts +12 -0
- package/dist/init-deposit/scaffold.js +81 -8
- package/dist/intake/clause-derivation.d.ts +37 -0
- package/dist/intake/clause-derivation.js +207 -0
- package/dist/intake/index.d.ts +1 -0
- package/dist/intake/index.js +1 -0
- package/dist/intake/issue-ingest.js +2 -38
- package/dist/preflight/evaluate.d.ts +5 -0
- package/dist/preflight/evaluate.js +14 -0
- package/dist/preflight/index.d.ts +1 -1
- package/dist/product-first-done-gate/empty-resolution.d.ts +1 -1
- package/dist/product-first-done-gate/empty-resolution.js +1 -1
- package/dist/product-first-done-gate/evaluate.d.ts +29 -0
- package/dist/product-first-done-gate/evaluate.js +110 -23
- package/dist/product-first-done-gate/index.d.ts +1 -1
- package/dist/product-first-done-gate/index.js +1 -1
- package/dist/run-summary/emit.d.ts +42 -2
- package/dist/run-summary/emit.js +250 -25
- package/dist/run-summary/index.d.ts +1 -1
- package/dist/run-summary/index.js +1 -1
- package/dist/run-summary/share.d.ts +1 -1
- package/dist/run-summary/share.js +2 -2
- package/dist/run-summary/types.d.ts +10 -3
- package/dist/scope/acceptance-activate-gate.d.ts +1 -1
- package/dist/scope/acceptance-activate-gate.js +4 -4
- package/dist/scope/acceptance-evidence.d.ts +15 -0
- package/dist/scope/acceptance-evidence.js +39 -0
- package/dist/scope/capacity-stamp.d.ts +2 -0
- package/dist/scope/capacity-stamp.js +4 -0
- package/dist/scope/delivery-evidence.d.ts +6 -0
- package/dist/scope/delivery-evidence.js +17 -0
- package/dist/scope/transition.js +66 -4
- package/dist/session/ceremony-dial-evidence.d.ts +42 -0
- package/dist/session/ceremony-dial-evidence.js +194 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.js +1 -0
- package/dist/session/session-start.js +21 -2
- package/dist/slice/existing.js +12 -1
- package/dist/slice/record.d.ts +8 -5
- package/dist/slice/record.js +21 -13
- package/dist/telemetry-coverage/evaluate.d.ts +42 -0
- package/dist/telemetry-coverage/evaluate.js +148 -0
- package/dist/telemetry-coverage/fake-trial.d.ts +45 -0
- package/dist/telemetry-coverage/fake-trial.js +194 -0
- package/dist/telemetry-coverage/index.d.ts +5 -0
- package/dist/telemetry-coverage/index.js +5 -0
- package/dist/telemetry-coverage/kinds.d.ts +19 -0
- package/dist/telemetry-coverage/kinds.js +52 -0
- package/dist/telemetry-coverage/scan-callers.d.ts +25 -0
- package/dist/telemetry-coverage/scan-callers.js +168 -0
- package/dist/vbrief-reconcile/index.d.ts +2 -0
- package/dist/vbrief-reconcile/index.js +1 -0
- package/dist/vbrief-reconcile/origin-freshness.d.ts +44 -0
- package/dist/vbrief-reconcile/origin-freshness.js +221 -0
- package/dist/verify-ac/evaluate.d.ts +18 -0
- package/dist/verify-ac/evaluate.js +24 -2
- package/dist/verify-ac/index.d.ts +1 -1
- package/dist/verify-ac/index.js +1 -1
- package/dist/verify-source/index.d.ts +1 -0
- package/dist/verify-source/index.js +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verify:telemetry-coverage — dead-surface detector (#3362).
|
|
3
|
+
*
|
|
4
|
+
* Two checks, one remediation that names the missing half:
|
|
5
|
+
* 1. Every RUN_SUMMARY_EVENT_KINDS member (and exported emitter method)
|
|
6
|
+
* has a production caller outside the emitter module.
|
|
7
|
+
* 2. Every kind is enrolled, has a trial step, and appears in a run of
|
|
8
|
+
* the shared fake-trial harness JSONL.
|
|
9
|
+
*
|
|
10
|
+
* Default is warn-only (exit 0). Pass --enforce to fail closed.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, rmSync } from "node:fs";
|
|
13
|
+
import { resolve } from "node:path";
|
|
14
|
+
import { DEFAULT_TRIAL_STEPS, runFakeTrial } from "./fake-trial.js";
|
|
15
|
+
import { ENROLLED_FIELD_FIXTURE_KINDS, kindForMethod, RUN_SUMMARY_EVENT_KINDS } from "./kinds.js";
|
|
16
|
+
import { scanProductionCallers } from "./scan-callers.js";
|
|
17
|
+
const EXIT_OK = 0;
|
|
18
|
+
const EXIT_ENFORCE_FINDINGS = 1;
|
|
19
|
+
const EXIT_CONFIG = 2;
|
|
20
|
+
export function remediationFor(subject, missingCaller, missingFixture) {
|
|
21
|
+
if (missingCaller && missingFixture) {
|
|
22
|
+
return `event kind ${subject} has no production caller / no field fixture — wire it or remove it from the schema.`;
|
|
23
|
+
}
|
|
24
|
+
if (missingCaller) {
|
|
25
|
+
return `event kind ${subject} has no production caller — wire it or remove it from the schema.`;
|
|
26
|
+
}
|
|
27
|
+
return `event kind ${subject} has no field fixture — wire it or remove it from the schema.`;
|
|
28
|
+
}
|
|
29
|
+
function failedDeclaredSteps(outcomes) {
|
|
30
|
+
const failed = new Set();
|
|
31
|
+
if (outcomes === undefined) {
|
|
32
|
+
return failed;
|
|
33
|
+
}
|
|
34
|
+
for (const outcome of outcomes) {
|
|
35
|
+
if (!outcome.emittedKinds.includes(outcome.declaredKind)) {
|
|
36
|
+
failed.add(outcome.declaredKind);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return failed;
|
|
40
|
+
}
|
|
41
|
+
export function evaluateTelemetryCoverage(options) {
|
|
42
|
+
const root = resolve(options.projectRoot);
|
|
43
|
+
const enforce = options.enforce === true;
|
|
44
|
+
if (!existsSync(root)) {
|
|
45
|
+
return {
|
|
46
|
+
code: EXIT_CONFIG,
|
|
47
|
+
message: `verify:telemetry-coverage: project root not found: ${root}`,
|
|
48
|
+
stream: "stderr",
|
|
49
|
+
findings: [],
|
|
50
|
+
enforce,
|
|
51
|
+
failOpen: !enforce,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const kinds = options.kinds ?? [...RUN_SUMMARY_EVENT_KINDS];
|
|
55
|
+
const enrolled = new Set(options.enrolledKinds ?? ENROLLED_FIELD_FIXTURE_KINDS);
|
|
56
|
+
const trialKinds = new Set(options.trialKinds ?? DEFAULT_TRIAL_STEPS.map((step) => step.kind));
|
|
57
|
+
let trialRoot;
|
|
58
|
+
let presentFromTrial;
|
|
59
|
+
let failedStepKinds;
|
|
60
|
+
const findings = [];
|
|
61
|
+
try {
|
|
62
|
+
if (options.trialResult !== undefined) {
|
|
63
|
+
presentFromTrial = new Set(options.trialResult.presentKinds);
|
|
64
|
+
failedStepKinds = failedDeclaredSteps(options.trialResult.stepOutcomes);
|
|
65
|
+
}
|
|
66
|
+
else if (options.skipTrial !== true) {
|
|
67
|
+
const trial = runFakeTrial();
|
|
68
|
+
trialRoot = trial.projectRoot;
|
|
69
|
+
presentFromTrial = new Set(trial.presentKinds);
|
|
70
|
+
failedStepKinds = failedDeclaredSteps(trial.stepOutcomes);
|
|
71
|
+
}
|
|
72
|
+
const scan = scanProductionCallers({
|
|
73
|
+
projectRoot: root,
|
|
74
|
+
scanRoots: options.scanRoots,
|
|
75
|
+
kinds,
|
|
76
|
+
});
|
|
77
|
+
for (const kind of kinds) {
|
|
78
|
+
const missingCaller = (scan.callersByKind[kind] ?? []).length === 0;
|
|
79
|
+
const missingFromTrial = presentFromTrial !== undefined && !presentFromTrial.has(kind);
|
|
80
|
+
const brokenDeclaredStep = failedStepKinds?.has(kind) === true;
|
|
81
|
+
const missingFixture = !enrolled.has(kind) || !trialKinds.has(kind) || missingFromTrial || brokenDeclaredStep;
|
|
82
|
+
if (missingCaller || missingFixture) {
|
|
83
|
+
findings.push({
|
|
84
|
+
subject: kind,
|
|
85
|
+
missingCaller,
|
|
86
|
+
missingFixture,
|
|
87
|
+
remediation: remediationFor(kind, missingCaller, missingFixture),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const method of scan.discoveredMethods) {
|
|
92
|
+
const mappedKind = kindForMethod(method);
|
|
93
|
+
if (mappedKind !== undefined && kinds.includes(mappedKind)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const hits = scan.callersByMethod[method] ?? [];
|
|
97
|
+
if (hits.length === 0) {
|
|
98
|
+
findings.push({
|
|
99
|
+
subject: method,
|
|
100
|
+
missingCaller: true,
|
|
101
|
+
missingFixture: false,
|
|
102
|
+
remediation: `event kind ${method} has no production caller — wire it or remove it from the schema.`,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (findings.length === 0) {
|
|
107
|
+
return {
|
|
108
|
+
code: EXIT_OK,
|
|
109
|
+
message: `OK: verify:telemetry-coverage — every event kind has a production caller ` +
|
|
110
|
+
`and a field fixture (enforce=${enforce}).`,
|
|
111
|
+
stream: "stdout",
|
|
112
|
+
findings: [],
|
|
113
|
+
enforce,
|
|
114
|
+
failOpen: !enforce,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const lines = [
|
|
118
|
+
`verify:telemetry-coverage: ${findings.length} dead telemetry surface(s):`,
|
|
119
|
+
...findings.map((f) => ` ${f.remediation}`),
|
|
120
|
+
];
|
|
121
|
+
if (enforce) {
|
|
122
|
+
lines.push("FAIL: --enforce is set; wire the missing half or remove the kind from the schema (#3362).");
|
|
123
|
+
return {
|
|
124
|
+
code: EXIT_ENFORCE_FINDINGS,
|
|
125
|
+
message: lines.join("\n"),
|
|
126
|
+
stream: "stderr",
|
|
127
|
+
findings,
|
|
128
|
+
enforce: true,
|
|
129
|
+
failOpen: false,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
lines.push("ADVISORY (warn-only): exit 0. Pass --enforce to fail closed after #3355/#3356 land (#3362).");
|
|
133
|
+
return {
|
|
134
|
+
code: EXIT_OK,
|
|
135
|
+
message: lines.join("\n"),
|
|
136
|
+
stream: "stdout",
|
|
137
|
+
findings,
|
|
138
|
+
enforce: false,
|
|
139
|
+
failOpen: true,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
if (trialRoot !== undefined) {
|
|
144
|
+
rmSync(trialRoot, { recursive: true, force: true });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared fake-trial harness for field-shaped run-summary fixtures (#3362).
|
|
3
|
+
*
|
|
4
|
+
* One harness: temp consumer-shaped root, DEFT_RUN_SUMMARY_PATH set, production
|
|
5
|
+
* emitter write path, multi-invocation identity. Enroll kinds via trial steps
|
|
6
|
+
* rather than rebuilding a per-kind fixture.
|
|
7
|
+
*/
|
|
8
|
+
import { RunSummaryEmitter } from "../run-summary/emit.js";
|
|
9
|
+
import { type RunSummaryEventKind, type RunSummaryLine } from "../run-summary/index.js";
|
|
10
|
+
export interface FakeTrialStep {
|
|
11
|
+
readonly kind: RunSummaryEventKind;
|
|
12
|
+
readonly invoke: (emitter: RunSummaryEmitter) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare const DEFAULT_TRIAL_STEPS: readonly FakeTrialStep[];
|
|
15
|
+
export interface FakeTrialOptions {
|
|
16
|
+
/** Existing root. When omitted, a temp consumer-shaped deposit is created. */
|
|
17
|
+
readonly projectRoot?: string;
|
|
18
|
+
readonly sessionId?: string;
|
|
19
|
+
readonly destPath?: string;
|
|
20
|
+
readonly steps?: readonly FakeTrialStep[];
|
|
21
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
22
|
+
}
|
|
23
|
+
export interface FakeTrialStepOutcome {
|
|
24
|
+
readonly declaredKind: RunSummaryEventKind;
|
|
25
|
+
readonly emittedKinds: readonly RunSummaryEventKind[];
|
|
26
|
+
}
|
|
27
|
+
export interface FakeTrialResult {
|
|
28
|
+
readonly projectRoot: string;
|
|
29
|
+
readonly destPath: string;
|
|
30
|
+
readonly sessionId: string;
|
|
31
|
+
readonly lines: readonly RunSummaryLine[];
|
|
32
|
+
readonly presentKinds: readonly RunSummaryEventKind[];
|
|
33
|
+
readonly stepOutcomes: readonly FakeTrialStepOutcome[];
|
|
34
|
+
readonly seqMonotonic: boolean;
|
|
35
|
+
readonly sessionIdStable: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run one fake trial: write JSONL via the production emitter, then read it back.
|
|
39
|
+
* A second emitter instance appends so seq/session_id identity is asserted
|
|
40
|
+
* across invocations (#3350 class).
|
|
41
|
+
*/
|
|
42
|
+
export declare function runFakeTrial(options?: FakeTrialOptions): FakeTrialResult;
|
|
43
|
+
/** Assert every enrolled kind appears in a trial result. */
|
|
44
|
+
export declare function missingEnrolledKinds(result: FakeTrialResult, enrolled?: readonly RunSummaryEventKind[]): readonly RunSummaryEventKind[];
|
|
45
|
+
//# sourceMappingURL=fake-trial.d.ts.map
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared fake-trial harness for field-shaped run-summary fixtures (#3362).
|
|
3
|
+
*
|
|
4
|
+
* One harness: temp consumer-shaped root, DEFT_RUN_SUMMARY_PATH set, production
|
|
5
|
+
* emitter write path, multi-invocation identity. Enroll kinds via trial steps
|
|
6
|
+
* rather than rebuilding a per-kind fixture.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
12
|
+
import { RunSummaryEmitter } from "../run-summary/emit.js";
|
|
13
|
+
import { ENV_RUN_SUMMARY_PATH, ENV_TOTAL_TOOL_TURNS, parseRunSummaryJsonl, } from "../run-summary/index.js";
|
|
14
|
+
import { ENROLLED_FIELD_FIXTURE_KINDS } from "./kinds.js";
|
|
15
|
+
export const DEFAULT_TRIAL_STEPS = [
|
|
16
|
+
{
|
|
17
|
+
kind: "session_start",
|
|
18
|
+
invoke: (emitter) => {
|
|
19
|
+
emitter.emitSessionStart({ ready: true, exit_code: 0 });
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
kind: "dial_escalation_evaluation",
|
|
24
|
+
invoke: (emitter) => {
|
|
25
|
+
emitter.emitDialEscalationEvaluation({
|
|
26
|
+
tier: "standard",
|
|
27
|
+
outcome: "declined",
|
|
28
|
+
reason: "fake-trial",
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
kind: "dial_transition",
|
|
34
|
+
invoke: (emitter) => {
|
|
35
|
+
emitter.emitDialTransition({
|
|
36
|
+
from: "rapid",
|
|
37
|
+
to: "standard",
|
|
38
|
+
reason: "fake-trial",
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
kind: "check_invocation",
|
|
44
|
+
invoke: (emitter) => {
|
|
45
|
+
emitter.emitCheckInvocation({
|
|
46
|
+
target: "check:framework-source",
|
|
47
|
+
exit_code: 0,
|
|
48
|
+
gates: [],
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
kind: "verification",
|
|
54
|
+
invoke: (emitter) => {
|
|
55
|
+
emitter.emitVerification({
|
|
56
|
+
check_id: "fake-trial",
|
|
57
|
+
method_fingerprint: "fake-trial",
|
|
58
|
+
outcome: "pass",
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
kind: "acceptance",
|
|
64
|
+
invoke: (emitter) => {
|
|
65
|
+
emitter.emitAcceptance({
|
|
66
|
+
resolved_command_count: 1,
|
|
67
|
+
outcome: "verified-pass",
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
kind: "acceptance_stamp",
|
|
73
|
+
invoke: (emitter) => {
|
|
74
|
+
emitter.emitAcceptanceStamp({
|
|
75
|
+
rung: "stated",
|
|
76
|
+
none_stated: false,
|
|
77
|
+
command_count: 1,
|
|
78
|
+
clause_count: 0,
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
kind: "tool_turn_denominator",
|
|
84
|
+
invoke: (emitter) => {
|
|
85
|
+
emitter.emitKnownToolTurnDenominator();
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
function createConsumerShapedRoot() {
|
|
90
|
+
const root = mkdtempSync(join(tmpdir(), "deft-telemetry-trial-"));
|
|
91
|
+
try {
|
|
92
|
+
mkdirSync(join(root, "xbrief"), { recursive: true });
|
|
93
|
+
containedWrite({
|
|
94
|
+
root,
|
|
95
|
+
target: ".gitignore",
|
|
96
|
+
data: ".deft-run-summary.json\n",
|
|
97
|
+
mode: "create",
|
|
98
|
+
});
|
|
99
|
+
containedWrite({
|
|
100
|
+
root,
|
|
101
|
+
target: "package.json",
|
|
102
|
+
data: '{"name":"fake-trial-consumer"}\n',
|
|
103
|
+
mode: "create",
|
|
104
|
+
});
|
|
105
|
+
return root;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
rmSync(root, { recursive: true, force: true });
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function seqIsMonotonic(lines) {
|
|
113
|
+
if (lines.length === 0) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
117
|
+
if (lines[i]?.seq !== i + 1) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
function sessionIdIsStable(lines, sessionId) {
|
|
124
|
+
return lines.every((line) => line.session_id === sessionId);
|
|
125
|
+
}
|
|
126
|
+
/** Missing dest after a silent / fail-open step is empty emit, not ENOENT. */
|
|
127
|
+
function readTrialLines(destPath) {
|
|
128
|
+
if (!existsSync(destPath)) {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
return parseRunSummaryJsonl(readFileSync(destPath, "utf8"));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Run one fake trial: write JSONL via the production emitter, then read it back.
|
|
135
|
+
* A second emitter instance appends so seq/session_id identity is asserted
|
|
136
|
+
* across invocations (#3350 class).
|
|
137
|
+
*/
|
|
138
|
+
export function runFakeTrial(options = {}) {
|
|
139
|
+
const ownsTempRoot = options.projectRoot === undefined;
|
|
140
|
+
const projectRoot = options.projectRoot ?? createConsumerShapedRoot();
|
|
141
|
+
try {
|
|
142
|
+
const destPath = options.destPath ?? join(projectRoot, "trial-run-summary.jsonl");
|
|
143
|
+
const sessionId = options.sessionId ?? "fake-trial-session";
|
|
144
|
+
const steps = options.steps ?? DEFAULT_TRIAL_STEPS;
|
|
145
|
+
const env = {
|
|
146
|
+
...(options.env ?? process.env),
|
|
147
|
+
[ENV_RUN_SUMMARY_PATH]: destPath,
|
|
148
|
+
[ENV_TOTAL_TOOL_TURNS]: "8",
|
|
149
|
+
};
|
|
150
|
+
const first = new RunSummaryEmitter({ projectRoot, sessionId, env });
|
|
151
|
+
const stepOutcomes = [];
|
|
152
|
+
let seenLines = 0;
|
|
153
|
+
for (const step of steps) {
|
|
154
|
+
step.invoke(first);
|
|
155
|
+
const current = readTrialLines(destPath);
|
|
156
|
+
const emittedKinds = current.slice(seenLines).map((line) => line.event);
|
|
157
|
+
seenLines = current.length;
|
|
158
|
+
stepOutcomes.push({ declaredKind: step.kind, emittedKinds });
|
|
159
|
+
}
|
|
160
|
+
const second = new RunSummaryEmitter({ projectRoot, sessionId, env });
|
|
161
|
+
second.emitCheckInvocation({
|
|
162
|
+
target: "check:framework-source",
|
|
163
|
+
exit_code: 0,
|
|
164
|
+
gates: [],
|
|
165
|
+
});
|
|
166
|
+
const lines = readTrialLines(destPath);
|
|
167
|
+
const present = new Set();
|
|
168
|
+
for (const line of lines) {
|
|
169
|
+
present.add(line.event);
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
projectRoot,
|
|
173
|
+
destPath,
|
|
174
|
+
sessionId,
|
|
175
|
+
lines,
|
|
176
|
+
presentKinds: [...present],
|
|
177
|
+
stepOutcomes,
|
|
178
|
+
seqMonotonic: seqIsMonotonic(lines),
|
|
179
|
+
sessionIdStable: sessionIdIsStable(lines, sessionId),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
if (ownsTempRoot) {
|
|
184
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/** Assert every enrolled kind appears in a trial result. */
|
|
190
|
+
export function missingEnrolledKinds(result, enrolled = ENROLLED_FIELD_FIXTURE_KINDS) {
|
|
191
|
+
const present = new Set(result.presentKinds);
|
|
192
|
+
return enrolled.filter((kind) => !present.has(kind));
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=fake-trial.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { evaluateTelemetryCoverage, remediationFor, type TelemetryCoverageFinding, type TelemetryCoverageOptions, type TelemetryCoverageResult, } from "./evaluate.js";
|
|
2
|
+
export { DEFAULT_TRIAL_STEPS, type FakeTrialOptions, type FakeTrialResult, type FakeTrialStep, type FakeTrialStepOutcome, missingEnrolledKinds, runFakeTrial, } from "./fake-trial.js";
|
|
3
|
+
export { ENROLLED_FIELD_FIXTURE_KINDS, EVENT_KIND_TO_EMITTER_METHODS, isKindEmitterMethod, kindForMethod, methodsForKind, RUN_SUMMARY_EVENT_KINDS, type RunSummaryEventKind, } from "./kinds.js";
|
|
4
|
+
export { type CallerHit, type CallerScanResult, DEFAULT_SCAN_ROOTS, EMITTER_MODULE_REL, scanProductionCallers, } from "./scan-callers.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { evaluateTelemetryCoverage, remediationFor, } from "./evaluate.js";
|
|
2
|
+
export { DEFAULT_TRIAL_STEPS, missingEnrolledKinds, runFakeTrial, } from "./fake-trial.js";
|
|
3
|
+
export { ENROLLED_FIELD_FIXTURE_KINDS, EVENT_KIND_TO_EMITTER_METHODS, isKindEmitterMethod, kindForMethod, methodsForKind, RUN_SUMMARY_EVENT_KINDS, } from "./kinds.js";
|
|
4
|
+
export { DEFAULT_SCAN_ROOTS, EMITTER_MODULE_REL, scanProductionCallers, } from "./scan-callers.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event-kind ↔ emitter-method mapping for verify:telemetry-coverage (#3362).
|
|
3
|
+
*/
|
|
4
|
+
import { RUN_SUMMARY_EVENT_KINDS, type RunSummaryEventKind } from "../run-summary/types.js";
|
|
5
|
+
export { RUN_SUMMARY_EVENT_KINDS, type RunSummaryEventKind };
|
|
6
|
+
/** Typed RunSummaryEmitter methods that write each schema kind. */
|
|
7
|
+
export declare const EVENT_KIND_TO_EMITTER_METHODS: Readonly<Record<RunSummaryEventKind, readonly string[]>>;
|
|
8
|
+
/**
|
|
9
|
+
* Kinds asserted by the shared fake-trial harness.
|
|
10
|
+
* Author this list independently of RUN_SUMMARY_EVENT_KINDS — spreading the
|
|
11
|
+
* schema would make a missing fixture undetectable (#3362 Greptile).
|
|
12
|
+
* Enroll here and add a DEFAULT_TRIAL_STEPS entry; do not rebuild a per-kind harness.
|
|
13
|
+
*/
|
|
14
|
+
export declare const ENROLLED_FIELD_FIXTURE_KINDS: readonly RunSummaryEventKind[];
|
|
15
|
+
/** True when a discovered class method is a distinct event surface (not the generic emit). */
|
|
16
|
+
export declare function isKindEmitterMethod(name: string): boolean;
|
|
17
|
+
export declare function methodsForKind(kind: string): readonly string[];
|
|
18
|
+
export declare function kindForMethod(method: string): RunSummaryEventKind | undefined;
|
|
19
|
+
//# sourceMappingURL=kinds.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event-kind ↔ emitter-method mapping for verify:telemetry-coverage (#3362).
|
|
3
|
+
*/
|
|
4
|
+
import { RUN_SUMMARY_EVENT_KINDS } from "../run-summary/types.js";
|
|
5
|
+
export { RUN_SUMMARY_EVENT_KINDS };
|
|
6
|
+
/** Typed RunSummaryEmitter methods that write each schema kind. */
|
|
7
|
+
export const EVENT_KIND_TO_EMITTER_METHODS = {
|
|
8
|
+
session_start: ["emitSessionStart"],
|
|
9
|
+
dial_transition: ["emitDialTransition"],
|
|
10
|
+
dial_escalation_evaluation: ["emitDialEscalationEvaluation"],
|
|
11
|
+
check_invocation: ["emitCheckInvocation"],
|
|
12
|
+
tool_turn_denominator: ["emitToolTurnDenominator", "emitKnownToolTurnDenominator"],
|
|
13
|
+
verification: ["emitVerification"],
|
|
14
|
+
acceptance: ["emitAcceptance"],
|
|
15
|
+
acceptance_stamp: ["emitAcceptanceStamp"],
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Kinds asserted by the shared fake-trial harness.
|
|
19
|
+
* Author this list independently of RUN_SUMMARY_EVENT_KINDS — spreading the
|
|
20
|
+
* schema would make a missing fixture undetectable (#3362 Greptile).
|
|
21
|
+
* Enroll here and add a DEFAULT_TRIAL_STEPS entry; do not rebuild a per-kind harness.
|
|
22
|
+
*/
|
|
23
|
+
export const ENROLLED_FIELD_FIXTURE_KINDS = [
|
|
24
|
+
"session_start",
|
|
25
|
+
"dial_transition",
|
|
26
|
+
"dial_escalation_evaluation",
|
|
27
|
+
"check_invocation",
|
|
28
|
+
"tool_turn_denominator",
|
|
29
|
+
"verification",
|
|
30
|
+
"acceptance",
|
|
31
|
+
"acceptance_stamp",
|
|
32
|
+
];
|
|
33
|
+
const GENERIC_EMIT_METHODS = new Set(["emit"]);
|
|
34
|
+
/** True when a discovered class method is a distinct event surface (not the generic emit). */
|
|
35
|
+
export function isKindEmitterMethod(name) {
|
|
36
|
+
return name.startsWith("emit") && !GENERIC_EMIT_METHODS.has(name);
|
|
37
|
+
}
|
|
38
|
+
export function methodsForKind(kind) {
|
|
39
|
+
if (kind in EVENT_KIND_TO_EMITTER_METHODS) {
|
|
40
|
+
return EVENT_KIND_TO_EMITTER_METHODS[kind];
|
|
41
|
+
}
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
export function kindForMethod(method) {
|
|
45
|
+
for (const kind of RUN_SUMMARY_EVENT_KINDS) {
|
|
46
|
+
if (EVENT_KIND_TO_EMITTER_METHODS[kind].includes(method)) {
|
|
47
|
+
return kind;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=kinds.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production call-site scan for run-summary event kinds / emitter methods (#3362).
|
|
3
|
+
*/
|
|
4
|
+
export declare const DEFAULT_SCAN_ROOTS: readonly string[];
|
|
5
|
+
export declare const EMITTER_MODULE_REL = "packages/core/src/run-summary/emit.ts";
|
|
6
|
+
export interface CallerHit {
|
|
7
|
+
readonly path: string;
|
|
8
|
+
readonly line: number;
|
|
9
|
+
readonly match: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CallerScanResult {
|
|
12
|
+
readonly callersByKind: Readonly<Record<string, readonly CallerHit[]>>;
|
|
13
|
+
readonly callersByMethod: Readonly<Record<string, readonly CallerHit[]>>;
|
|
14
|
+
readonly discoveredMethods: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Scan production TypeScript for emitter method / event-kind call sites.
|
|
18
|
+
* Excludes the emitter module, this detector, and `*.test.ts`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function scanProductionCallers(options: {
|
|
21
|
+
readonly projectRoot: string;
|
|
22
|
+
readonly scanRoots?: readonly string[];
|
|
23
|
+
readonly kinds?: readonly string[];
|
|
24
|
+
}): CallerScanResult;
|
|
25
|
+
//# sourceMappingURL=scan-callers.d.ts.map
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production call-site scan for run-summary event kinds / emitter methods (#3362).
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
5
|
+
import { join, relative, resolve, sep } from "node:path";
|
|
6
|
+
import { isKindEmitterMethod, methodsForKind, RUN_SUMMARY_EVENT_KINDS } from "./kinds.js";
|
|
7
|
+
export const DEFAULT_SCAN_ROOTS = ["packages/core/src"];
|
|
8
|
+
export const EMITTER_MODULE_REL = "packages/core/src/run-summary/emit.ts";
|
|
9
|
+
const SKIP_DIR_NAMES = new Set(["node_modules", "dist", ".git", "coverage"]);
|
|
10
|
+
function toPosix(rel) {
|
|
11
|
+
return rel.split(sep).join("/");
|
|
12
|
+
}
|
|
13
|
+
function isTestFile(relPosix) {
|
|
14
|
+
return relPosix.endsWith(".test.ts") || relPosix.endsWith(".test.tsx");
|
|
15
|
+
}
|
|
16
|
+
function isExcludedProductionPath(relPosix) {
|
|
17
|
+
if (isTestFile(relPosix)) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (relPosix.includes("/telemetry-coverage/")) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return relPosix === EMITTER_MODULE_REL;
|
|
24
|
+
}
|
|
25
|
+
function walkTsFiles(dir, out) {
|
|
26
|
+
let entries;
|
|
27
|
+
try {
|
|
28
|
+
entries = readdirSync(dir);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
for (const name of entries) {
|
|
34
|
+
if (SKIP_DIR_NAMES.has(name)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const full = join(dir, name);
|
|
38
|
+
let st;
|
|
39
|
+
try {
|
|
40
|
+
st = statSync(full);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (st.isDirectory()) {
|
|
46
|
+
walkTsFiles(full, out);
|
|
47
|
+
}
|
|
48
|
+
else if (st.isFile() && (name.endsWith(".ts") || name.endsWith(".tsx"))) {
|
|
49
|
+
out.push(full);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function skipNoiseLine(trimmed) {
|
|
54
|
+
return (trimmed.startsWith("import ") ||
|
|
55
|
+
trimmed.startsWith("export ") ||
|
|
56
|
+
trimmed.startsWith("//") ||
|
|
57
|
+
trimmed.startsWith("*") ||
|
|
58
|
+
trimmed.startsWith("/*"));
|
|
59
|
+
}
|
|
60
|
+
function discoverEmitterMethods(emitSource) {
|
|
61
|
+
const names = new Set();
|
|
62
|
+
const re = /^\s+(emit[A-Z][A-Za-z0-9]*)\s*\(/gm;
|
|
63
|
+
let match = re.exec(emitSource);
|
|
64
|
+
while (match !== null) {
|
|
65
|
+
const name = match[1];
|
|
66
|
+
if (name !== undefined && isKindEmitterMethod(name)) {
|
|
67
|
+
names.add(name);
|
|
68
|
+
}
|
|
69
|
+
match = re.exec(emitSource);
|
|
70
|
+
}
|
|
71
|
+
return [...names].sort();
|
|
72
|
+
}
|
|
73
|
+
function kindLiteralPatterns(kind) {
|
|
74
|
+
const escaped = kind.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
75
|
+
return [
|
|
76
|
+
new RegExp(`\\.emit\\s*\\(\\s*['"]${escaped}['"]`),
|
|
77
|
+
new RegExp(`event\\s*:\\s*['"]${escaped}['"]`),
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
function methodCallPattern(method) {
|
|
81
|
+
const escaped = method.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
82
|
+
return new RegExp(`\\b${escaped}\\s*\\(`);
|
|
83
|
+
}
|
|
84
|
+
function collectHits(relPosix, lines, patterns) {
|
|
85
|
+
const hits = [];
|
|
86
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
87
|
+
const line = lines[i] ?? "";
|
|
88
|
+
const trimmed = line.trim();
|
|
89
|
+
if (skipNoiseLine(trimmed)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
for (const re of patterns) {
|
|
93
|
+
if (re.test(line)) {
|
|
94
|
+
hits.push({
|
|
95
|
+
path: relPosix,
|
|
96
|
+
line: i + 1,
|
|
97
|
+
match: trimmed.length > 100 ? `${trimmed.slice(0, 97)}...` : trimmed,
|
|
98
|
+
});
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return hits;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Scan production TypeScript for emitter method / event-kind call sites.
|
|
107
|
+
* Excludes the emitter module, this detector, and `*.test.ts`.
|
|
108
|
+
*/
|
|
109
|
+
export function scanProductionCallers(options) {
|
|
110
|
+
const root = resolve(options.projectRoot);
|
|
111
|
+
const scanRoots = options.scanRoots ?? DEFAULT_SCAN_ROOTS;
|
|
112
|
+
const kinds = options.kinds ?? [...RUN_SUMMARY_EVENT_KINDS];
|
|
113
|
+
const callersByKind = {};
|
|
114
|
+
const callersByMethod = {};
|
|
115
|
+
for (const kind of kinds) {
|
|
116
|
+
callersByKind[kind] = [];
|
|
117
|
+
for (const method of methodsForKind(kind)) {
|
|
118
|
+
callersByMethod[method] = callersByMethod[method] ?? [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
let discoveredMethods = [];
|
|
122
|
+
const emitAbs = resolve(root, EMITTER_MODULE_REL);
|
|
123
|
+
if (existsSync(emitAbs)) {
|
|
124
|
+
try {
|
|
125
|
+
discoveredMethods = discoverEmitterMethods(readFileSync(emitAbs, "utf8"));
|
|
126
|
+
for (const method of discoveredMethods) {
|
|
127
|
+
callersByMethod[method] = callersByMethod[method] ?? [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
discoveredMethods = [];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const scanRel of scanRoots) {
|
|
135
|
+
const scanAbs = resolve(root, scanRel);
|
|
136
|
+
if (!existsSync(scanAbs)) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const files = [];
|
|
140
|
+
walkTsFiles(scanAbs, files);
|
|
141
|
+
for (const abs of files) {
|
|
142
|
+
const relPosix = toPosix(relative(root, abs));
|
|
143
|
+
if (isExcludedProductionPath(relPosix)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
let text;
|
|
147
|
+
try {
|
|
148
|
+
text = readFileSync(abs, "utf8");
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const lines = text.split(/\r?\n/);
|
|
154
|
+
for (const kind of kinds) {
|
|
155
|
+
const patterns = [
|
|
156
|
+
...kindLiteralPatterns(kind),
|
|
157
|
+
...methodsForKind(kind).map(methodCallPattern),
|
|
158
|
+
];
|
|
159
|
+
callersByKind[kind]?.push(...collectHits(relPosix, lines, patterns));
|
|
160
|
+
}
|
|
161
|
+
for (const method of Object.keys(callersByMethod)) {
|
|
162
|
+
callersByMethod[method]?.push(...collectHits(relPosix, lines, [methodCallPattern(method)]));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { callersByKind, callersByMethod, discoveredMethods };
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=scan-callers.js.map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { depResolved, graphOutcomeToJson, RESOLVED_FOLDERS, reconcileGraph, renderGraphReport, } from "./graph.js";
|
|
2
2
|
export { computeDesiredLabels, labelsOutcomeToJson, MANAGED_LABELS, reconcileLabels, renderLabelsReport, SCAN_FOLDERS, ScmLabelClient, ScmLabelError, } from "./labels.js";
|
|
3
3
|
export { cmdVbriefReconcile, run, usage } from "./main.js";
|
|
4
|
+
export type { EvaluateOriginFreshnessOptions, FetchOriginUpdatedAt, GithubIssueOrigin, OriginFreshnessKind, OriginFreshnessResult, } from "./origin-freshness.js";
|
|
5
|
+
export { briefUpdatedOf, compareOriginFreshness, evaluateOriginFreshness, extractGithubIssueOrigin, extractGithubIssueOrigins, fetchGithubIssueUpdatedAt, formatOriginStaleMessage, ORIGIN_FRESHNESS_REMEDIATION, } from "./origin-freshness.js";
|
|
4
6
|
export { PARITY_SCENARIO_NAMES, renderScenarioOutput, runParityScenario, } from "./parity-scenarios.js";
|
|
5
7
|
export { pyRepr } from "./py-repr.js";
|
|
6
8
|
export { buildSpecTaskIndex, detectStatusMarker, folderFromStatus, formatReconciliationMarkdown, hasDisagreement, loadOverrides, normalizeTaskId, OVERRIDES_FILENAME, parseOverridesYaml, reconcileScopeItems, writeReconciliationReport, } from "./reconciliation.js";
|