rfc: a window's extent is the producer's to decide; window.start and window.end are the earliest and latest event time of the lines it contains - #14
Merged
Conversation
… of the window's lines, and how a producer decides a window's extent is its own The two instants had no definition. A producer could write the bounds its own rule used, or the times of the lines it read, and a consumer could not tell which; §12.1 takes their min and max, so two documents could compose into an interval that meant neither. §2.2 now defines them as the earliest and the latest event time among the lines the window contains, requires start equal to end for a window with no line, and states that which lines a window contains, and how and when a producer decides it, is implementation-defined: no fixed interval, no decision on a single line, no online decision. The glossary gains Event time and redefines Window. The §1 table, §5 (previous_window_end is the previous window's window.end), §8 (four window relations), §12.1, §16.6 (the regime note becomes a MUST NOT, and loses a tag nothing defined), §16.9, §16.10 and RATIONALE §R5 drop the wording that assumed a fixed interval closed as lines arrive. Breaking under GOVERNANCE.md §2; this pull request is its RFC. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…indow with no line has `start` equal to `end`, judged on the instants §8 now counts that equality among the window relations this validator decides, and until this commit nothing decided it. A schema-valid document with `lines_observed` 0 whose `start` precedes its `end` by 600 seconds, and whose `duration_seconds` is 600, read CONFORMANT, exit 0: ordering and duration both hold, so no existing clause could see it. - metalog_validate.py: a fifth window clause, `empty-extent`, decided apart from ordering and on the parsed instants, never on the strings. RFC 3339 spells one instant several ways, and §2.2 constrains the time, not its spelling. The printed scope names the clause, and also names what the window arm cannot decide now that §2.2 defines `start` and `end` as the event-time envelope of the window's lines: a relation to lines the document does not carry. - invalid/window_empty_extent.metalog.jsonl (control `window-empty-extent`): the must-fail document above. Red first, against the validator before this commit: the self-test with this manifest entry reads `SELFTEST FAILED: 1/31 fixtures — ['invalid/window_empty_extent.metalog.jsonl']`, and the fixture validated alone reads `VERDICT: CONFORMANT`, exit 0. - valid/window_empty_equal_instants.metalog.jsonl (control `window-empty-equal-instants`): the clause's positive witness, two empty windows with `start` equal to `end`, the second spelling `end` as `2026-04-24T10:00:00.000+00:00` against a `start` of `2026-04-24T10:00:00Z`. A clause that compares the strings reds it, and only it: `SELFTEST FAILED: 1/31 fixtures — ['valid/window_empty_equal_instants.metalog.jsonl']`. - README: the counts (thirty-one fixtures, nineteen tagged, seventeen distinct controls), a table row for every control the self-test arms and the table did not list (five, three of them already armed before this commit), and the clause-2 limit restated with the fifth relation and the envelope it cannot reach. After: `SELFTEST PASSED: 31/31 fixtures`, seventeen controls armed; the shipped example reads CONFORMANT with `--expect-documents 1`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change class: BREAKING under
GOVERNANCE.md§2. MINOR bump during 0.x; MAJOR stays 0, and both schema files keep theirv0names.This pull request is the RFC.
GOVERNANCE.md§2 names an RFC issue; the editor asked for this one as a pull request, so that section 2 below is the actual diff rather than a transcription of it. There is no separate issue. The four sections §2 requires follow.The 14-day comment window runs from this pull request's opening: 2026-09-29 to 2026-10-13. The editor merges after it closes. The change is written into the unreleased
0.10.0entry ofCHANGELOG.md; if0.10.0is cut before the window closes, the entry moves to the next MINOR at merge.Still to be added to this pull request before merge: the conformance validator's arm for the one new relation between
windowmembers (a window with no line hasstartequal toend), with a fixture that must fail it. §8 in this diff already counts that relation among the ones the validator decides.1. The problem, with a concrete example
SPEC.mdnever says how a producer decides where a window starts and ends, and it should not. Several of its sentences assume one way of deciding anyway: a window is a time interval fixed in advance, closed online as lines arrive, and each document is emitted when its interval ends. Section 4 lists those sentences.A producer is free to decide a window's extent in other ways, and those sentences rule out some good ones:
None of these decides where a window ends on the line it has just read. A reader who knows a log well decides the same way: by looking ahead, then scrolling back.
§2.2 also leaves
startandendundefined. It requiresstart <= endandduration_seconds = end - start, rounded to the nearest second, but it does not say what the two times are. Consider a producer that collects lines for 25 seconds, whose last line carries an event time one second before that interval ends. It may emitduration_seconds: 25(its own interval) or24(its lines), and a consumer cannot tell which one it received. §12.1 composes documents by takingmin(start)andmax(end), so documents from two such producers compose into an interval that means neither.2. The proposed change, as a diff against
SPEC.mdThe full diff is this pull request's. The hunks that carry the proposal are these.
Glossary:
§2.2, after the
windowblock:Every other sentence that assumed a closure model changes in the same diff; section 4 lists each one with its old and new wording.
3. Alternatives considered
start <= endcould fail. §12.1'smin/maxalso does not compose "first and last line read": it does compose envelopes, because the envelope of a union is theminof the starts and themaxof the ends.window.bounds: "observed" | "declared"). This keeps two meanings conforming, moves the ambiguity to every consumer, and leaves the composition of mixed documents undefined.4. Migration impact
Producers.
start/endbecomes non-conformant. It moves that interval to an extension (§7). This is why the change is classed breaking.startequal toendfor it. The old text permitted equality there but did not require it.previous_window_end(§5) is the previous window'swindow.end. A producer that wrote an interval boundary there writes that window'sendinstead.cube_coord(§16.6).end, the instant at which its interval rule closed the window. UnderGOVERNANCE.md§3 that is a defect in the implementation once this text is merged, and the implementation changes to conform.Consumers.
startandendnow mean the same thing in every conformant document, so two producers' windows can be compared and composed. Nothing a consumer did before becomes wrong.Schemas and examples. Neither schema changes: the types are the same. The examples keep their round-minute times, which remain valid: they read as the event times of lines that fell on those instants.
Conformance tooling. The validator decides §2.2's relations between
windowmembers. The empty-window equality is a new one. Its arm and a failing fixture are added to this pull request before merge (see the note at the top).Every passage changed, old and new wording.
startandendare defined through it, and §15 already used the term undefined.windowrowpreviousdocument being the previous closed window"previousdocument being the window before it in the producer's order"previous_window_endwindow.end"C.window.duration_seconds = C.window.end - C.window.start(real time, not sum of inputs)"cube_coord." The old text also carried a tag that nothing in the specification defines; it goes.RATIONALE.md§R5previous_window_end"previous_window_endby that window'swindow.end"Checked and left unchanged, because none assumes how a window's extent is decided:
bounds. That constrains which lines such a window contains, not how or when the producer decides it, and §2.2 now points at it.🤖 Generated with Claude Code