candor-ts 0.8.4 → 0.8.5
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/mcp.mjs +4 -2
- package/package.json +1 -1
- package/query-core.mjs +15 -0
- package/query.mjs +18 -4
package/mcp.mjs
CHANGED
|
@@ -162,12 +162,14 @@ const TOOLS = {
|
|
|
162
162
|
candor_diff: {
|
|
163
163
|
description: "The per-function effect delta versus a baseline report: gained (introduced vs inherited) and lost effects. 'What did this change do to the effect surface?'.",
|
|
164
164
|
schema: { type: "object", properties: { baseline: { type: "string", description: "the baseline report prefix" }, ...reportArg }, required: ["baseline"] },
|
|
165
|
-
run: (a, p) => Q.
|
|
165
|
+
run: (a, p) => ({ baseline_version: Q.reportVersion(a.baseline) ?? "", engine_version: Q.reportVersion(p) ?? "",
|
|
166
|
+
...Q.diff(Q.loadReport(p), Q.loadReport(a.baseline)) }),
|
|
166
167
|
},
|
|
167
168
|
candor_gains: {
|
|
168
169
|
description: "The supply-chain alarm: effects the surface GAINED versus a baseline (package-level + per-function) — 'did this dependency bump add Net/Exec somewhere?'.",
|
|
169
170
|
schema: { type: "object", properties: { baseline: { type: "string", description: "the baseline report prefix" }, ...reportArg }, required: ["baseline"] },
|
|
170
|
-
run: (a, p) => Q.
|
|
171
|
+
run: (a, p) => ({ baseline_version: Q.reportVersion(a.baseline) ?? "", engine_version: Q.reportVersion(p) ?? "",
|
|
172
|
+
...Q.gains(Q.loadReport(p), Q.loadReport(a.baseline)) }),
|
|
171
173
|
},
|
|
172
174
|
};
|
|
173
175
|
|
package/package.json
CHANGED
package/query-core.mjs
CHANGED
|
@@ -55,6 +55,21 @@ function normFns(parsed, source) {
|
|
|
55
55
|
return out;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/** The producing engine build of the report(s) at a prefix (the §2.1 envelope `candor.version`) — null
|
|
59
|
+
* when unreadable/absent (a legacy bare array has no provenance). Baselines are comparable only to
|
|
60
|
+
* their own producing version (§2.1): diff/gains consumers disclose a mismatch (an engine swap makes
|
|
61
|
+
* "gained" effects ambiguous — unmasking vs regression — the baseline-invalidation rule, AGENTS §2a). */
|
|
62
|
+
export function reportVersion(prefix) {
|
|
63
|
+
const files = fs.existsSync(`${prefix}.json`) ? [`${prefix}.json`] : siblings(prefix, isReport);
|
|
64
|
+
for (const f of files) {
|
|
65
|
+
try {
|
|
66
|
+
const v = JSON.parse(fs.readFileSync(f, "utf8"))?.candor?.version;
|
|
67
|
+
if (v) return String(v);
|
|
68
|
+
} catch { /* unreadable sibling — keep looking */ }
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
58
73
|
export function loadReport(prefix) {
|
|
59
74
|
if (fs.existsSync(`${prefix}.json`)) {
|
|
60
75
|
// The PRIMARY report parse must DISCLOSE-and-tolerate like the sibling path — a bare JSON.parse here
|
package/query.mjs
CHANGED
|
@@ -30,7 +30,7 @@ import { impact as coreImpact, path as corePath, gains as coreGains,
|
|
|
30
30
|
show as coreShow, blindspots as coreBlindspots,
|
|
31
31
|
callers as coreCallers, callersFrontier, loadHierarchy,
|
|
32
32
|
containment as coreContainment,
|
|
33
|
-
loadReport, loadCallgraph, matches } from "./query-core.mjs";
|
|
33
|
+
loadReport, loadCallgraph, matches , reportVersion } from "./query-core.mjs";
|
|
34
34
|
const emit = (v) => console.log(JSON.stringify(v, null, 1));
|
|
35
35
|
|
|
36
36
|
// ONE version + spec source, the SAME way scan.mjs reads them: PKG_VERSION is the bare semver from
|
|
@@ -180,8 +180,19 @@ switch (cmd) {
|
|
|
180
180
|
if (gained.length || lost.length) changes.push({ fn, gained, lost });
|
|
181
181
|
}
|
|
182
182
|
changes.sort((a, b) => a.fn.localeCompare(b.fn));
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
// §2.1: a baseline is comparable only to its own producing build — disclose a mismatch (the gains
|
|
184
|
+
// may be the engine reclassifying after a coverage batch, not the code changing). Same note + JSON
|
|
185
|
+
// provenance fields as the Rust candor-query (cross-engine parity, item 10).
|
|
186
|
+
const engineV = reportVersion(curPrefix), baseV = reportVersion(basePrefix);
|
|
187
|
+
const versionMismatch = engineV && baseV && engineV !== baseV;
|
|
188
|
+
if (versionMismatch)
|
|
189
|
+
console.error(`candor-ts: ⚠ baseline @${baseV} ≠ engine @${engineV} — some changes may be the engine reclassifying, not your code. Treat an engine swap as baseline-invalidating: review, then regenerate the baseline.`);
|
|
190
|
+
emit({ baseline_version: baseV ?? "", engine_version: engineV ?? "", changes });
|
|
191
|
+
// diff DISCLOSES (the posture) — it is not a gate. Its gained-effect exit 1 is a convenience for
|
|
192
|
+
// same-build ratchet use; under a version mismatch that signal is BOGUS (unmasking, not regression),
|
|
193
|
+
// so exit 0 and let the ⚠ inform — never deliver the wave as a CI failure (review §2.1: guards fail
|
|
194
|
+
// closed, queries disclose).
|
|
195
|
+
process.exit(!versionMismatch && changes.some((c) => c.gained.length) ? 1 : 0);
|
|
185
196
|
break; // unreachable (process.exit), but eslint can't prove it — defends against fallthrough
|
|
186
197
|
}
|
|
187
198
|
case "reachable": {
|
|
@@ -215,7 +226,10 @@ switch (cmd) {
|
|
|
215
226
|
// the supply-chain alarm (SPEC §5.1): {gained:[Effect], byFunction:[{fn,effect}]} — what the
|
|
216
227
|
// surface gained between two reports (base → cur), the cross-engine machine-readable form.
|
|
217
228
|
const [curPrefix, basePrefix] = args;
|
|
218
|
-
|
|
229
|
+
const gv = reportVersion(curPrefix), gbv = reportVersion(basePrefix);
|
|
230
|
+
if (gv && gbv && gv !== gbv)
|
|
231
|
+
console.error(`candor-ts: ⚠ baseline @${gbv} ≠ engine @${gv} — a "gained capability" may be the engine reclassifying, not the dependency changing. Regenerate both reports with one build to compare releases.`);
|
|
232
|
+
emit({ baseline_version: gbv ?? "", engine_version: gv ?? "", ...coreGains(loadReport(curPrefix), loadReport(basePrefix)) });
|
|
219
233
|
break;
|
|
220
234
|
}
|
|
221
235
|
case "path": {
|