fix(qlog): exclude hidden custom events from incomplete facts (#7825)

This commit is contained in:
morluto authored and GitHub committed 2026-10-29 04:58:53 +08:00
1 parent 2dd9a3092e
commit b0880d660f
3 files changed
+69 -4

No files matched your search

+17
View File
@@ -332,6 +332,23 @@ it.each([
},
);
it("counts hidden payloads only for events interpreted as transport facts", () => {
const text = capture([
{ name: "extension:custom", time: 0, data: { body: "ordinary" } },
event([frame(0, 10, false)]),
{ name: "recovery:packet_lost", time: 2, data: { packet_number: 5 } },
]);
const control = facts(text);
expect(control.traces[0]?.incomplete_fact_records).toEqual([]);
const hidden = facts(text, ["data"]);
expect(hidden.traces[0]?.incomplete_fact_records).toEqual([1, 2]);
expect(hidden.decoded.records.map((record) => record.reported)).toEqual([
{ name: "extension:custom", time: 0 },
{ name: "transport:packet_sent", time: 1791819895000.25 },
{ name: "recovery:packet_lost", time: 2 },
]);
});
it("omits a hidden derived total for a stream with more contributions than call arguments allow", () => {
const events = Array.from({ length: 130 }, (_, index) =>
event(
+4 -4
View File
@@ -228,6 +228,9 @@ const collectTransportFacts = (
},
): void => {
const { fact, streams, excluded, name } = state;
// Unknown event payloads carry no facts under this interpretation profile.
// Their omission cannot make the transport-fact inventory incomplete.
if (name !== "recovery:packet_lost" && !packetEvent(name)) return;
if (!object(projection.reported) || !object(projection.reported.data)) {
fact.incomplete_fact_records.push(ordinal);
return;
@@ -235,10 +238,7 @@ const collectTransportFacts = (
const visible = projection.reported;
// Facts are selected by event name, so a declaration that hides the name
// of a loss or packet event omits its facts like any other hidden field.
if (
(name === "recovery:packet_lost" || packetEvent(name)) &&
visible.name !== name
) {
if (visible.name !== name) {
fact.incomplete_fact_records.push(ordinal);
return;
}
@@ -45,6 +45,54 @@ const qlog = (events: unknown[]) =>
],
});
it("does not classify hidden custom event data as incomplete transport facts", async () => {
const root = await createTestTempDirectory("rea-qlog-hidden-extension-");
const path = join(root, "input.qlog");
await writeFile(
path,
qlog([
{ name: "extension:custom", time: 1, data: { body: "ordinary" } },
{
...event,
data: {
...event.data,
frames: [{ ...event.data.frames[0], fin: false }],
},
},
]),
);
const { call } = await connectLocalToolsMcp();
for (const sensitive of [[], ["data"]]) {
const response = await call("inspect_web_network_capture", {
capture_path: path,
format: "qlog",
sensitive_values: sensitive,
});
expect(response.isError, JSON.stringify(response)).not.toBe(true);
const mcp = parseEvidence(response.structuredContent);
const cliResult = await execute(process.execPath, [
cli,
"inspect-web-network-capture",
path,
"qlog",
...sensitive.flatMap((value) => ["--sensitive-value", value]),
"--json",
]);
const cliEvidence = parseEvidence(JSON.parse(cliResult.stdout));
expect(cliEvidence.normalized_result).toEqual(mcp.normalized_result);
const capture = webNetworkCaptureSchema.parse(mcp.normalized_result);
if (capture.format !== "qlog") throw new Error("qlog format required");
expect(capture.qlog.traces[0]?.incomplete_fact_records).toEqual(
sensitive.length === 0 ? [] : [1],
);
if (sensitive.length > 0)
expect(capture.records[0]?.reported).toEqual({
name: "extension:custom",
time: 1,
});
}
});
const assertAdditionalQlogFacets = async (
call: Awaited<ReturnType<typeof connectLocalToolsMcp>>["call"],
retained: { kind: string; evidence_id: string },