mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
fix(qlog): mark records with unknown STREAM FIN incomplete
Keep known STREAM ranges and the unknown FIN value, while listing the source event among incomplete fact records so summary and retained views agree. Fixes #6598
This commit is contained in:
@@ -820,7 +820,7 @@ by null; there is no single events pointer shared by all traces.
|
||||
| Original event and loss declaration | Observed endpoint report; `recovery:packet_lost` does not prove actual network loss. Missing packet number/type remains unknown. |
|
||||
| STREAM ranges and byte totals | Derived per trace and direction from reported offsets and lengths using exact integer arithmetic. `unique_bytes` unions intervals; `frame_length_sum` includes overlaps; `repeated_bytes` is their difference. Overlap alone does not prove retransmission or equal contents. |
|
||||
| FIN final sizes | Reported offset plus length where FIN is true; multiple conflicting sizes remain visible. A final size does not establish complete coverage or a received body. |
|
||||
| Incomplete fact records | Ordinals with omitted/redacted interpretable frame metadata; usable fields in other records survive. An empty list does not establish complete logging or capture. |
|
||||
| Incomplete fact records | Ordinals with omitted/redacted interpretable frame metadata, including an unknown STREAM FIN; usable fields such as known ranges in that record survive. An empty list does not establish complete logging or capture. |
|
||||
| HTTP bodies and causality | `body_bytes: "not-reported"`; lengths and headers are metadata, with no reconstructed body, hash, timing causality or live process attribution. |
|
||||
|
||||
QUIC integer fields interpreted here accept exact nonnegative JSON integer
|
||||
|
||||
@@ -134,6 +134,38 @@ it("keeps incomplete fields unknown and FIN without bytes as metadata", () => {
|
||||
expect(traces[0]?.loss_declarations[0]?.packet_number.state).toBe("unknown");
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ fin: undefined, incomplete: [0] },
|
||||
{ fin: null, incomplete: [0] },
|
||||
{ fin: false, incomplete: [] },
|
||||
{ fin: true, incomplete: [] },
|
||||
])(
|
||||
"retains STREAM ranges and marks unknown FIN records incomplete: $fin",
|
||||
({ fin, incomplete }) => {
|
||||
const streamFrame: Record<string, unknown> = {
|
||||
frame_type: "stream",
|
||||
stream_id: 4,
|
||||
offset: 8,
|
||||
length: 3,
|
||||
};
|
||||
if (fin !== undefined) streamFrame.fin = fin;
|
||||
const { traces } = facts(capture([event([streamFrame])]));
|
||||
expect(traces[0]?.incomplete_fact_records).toEqual(incomplete);
|
||||
expect(traces[0]?.streams[0]?.contributions).toEqual([
|
||||
{
|
||||
record_ordinal: 0,
|
||||
frame_index: 0,
|
||||
offset: "8",
|
||||
length: "3",
|
||||
fin: typeof fin === "boolean" ? fin : null,
|
||||
},
|
||||
]);
|
||||
expect(traces[0]?.streams[0]?.covered_ranges).toEqual([
|
||||
{ start: "8", end: "11" },
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
it("excludes structural auth material and explicit normalized values without guessing extension secrecy", () => {
|
||||
const text = capture([
|
||||
{
|
||||
|
||||
@@ -312,6 +312,8 @@ const collectTransportFacts = (
|
||||
length: length.toString(),
|
||||
fin: typeof frame.fin === "boolean" ? frame.fin : null,
|
||||
});
|
||||
if (typeof frame.fin !== "boolean")
|
||||
fact.incomplete_fact_records.push(ordinal);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -29,9 +29,7 @@ const event = {
|
||||
time: 1791819895000.25,
|
||||
data: {
|
||||
header: { packet_type: "1RTT", packet_number: 5 },
|
||||
frames: [
|
||||
{ frame_type: "stream", stream_id: 0, offset: 10, length: 5, fin: true },
|
||||
],
|
||||
frames: [{ frame_type: "stream", stream_id: 0, offset: 10, length: 5 }],
|
||||
},
|
||||
};
|
||||
const qlog = (events: unknown[]) =>
|
||||
@@ -60,7 +58,7 @@ const assertAdditionalQlogFacets = async (
|
||||
{ kind: "qlog", facet: "loss-declarations", trace_index: 0 },
|
||||
[{ record_ordinal: 1, packet_number: { state: "reported", value: "5" } }],
|
||||
],
|
||||
[{ kind: "qlog", facet: "incomplete-records", trace_index: 0 }, []],
|
||||
[{ kind: "qlog", facet: "incomplete-records", trace_index: 0 }, [0]],
|
||||
[
|
||||
{
|
||||
kind: "qlog",
|
||||
@@ -79,7 +77,7 @@ const assertAdditionalQlogFacets = async (
|
||||
stream_id: "0",
|
||||
direction: "sent",
|
||||
},
|
||||
["15"],
|
||||
[],
|
||||
],
|
||||
[{ kind: "qlog", facet: "traces", offset: 99 }, []],
|
||||
] as const) {
|
||||
@@ -206,7 +204,15 @@ it("pages original trace-scoped facts after source deletion without conflating s
|
||||
);
|
||||
expect(contribution.normalized_result).toMatchObject({
|
||||
page: {
|
||||
items: [{ record_ordinal: 0, frame_index: 0, offset: "10", length: "5" }],
|
||||
items: [
|
||||
{
|
||||
record_ordinal: 0,
|
||||
frame_index: 0,
|
||||
offset: "10",
|
||||
length: "5",
|
||||
fin: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
coverage: { total: 1, exhausted: true },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user