myxce/.kiro/specs/scheduler-sim-step-verbosity/design.md
Rongsong Shen 1374540954
docs(scheduler-sim-step-verbosity): add approved spec (requirements/design/tasks)
Follow-on to scheduler-sim-repl-verbosity: collapses the REPL's
per-event "[sim] t=... session=..." preamble to print once per
distinct rendered (timestamp, session) run of consecutive echoed
events, instead of once per event, in both step mode and continue
mode's structural-event echo. Requirement 1.3 deliberately keys the
dedup on the rendered, second-granularity timestamp rather than the
raw nanosecond clock value, which ticks on every event and would
otherwise never repeat -- confirmed against a real user-supplied
transcript before writing requirements (see research.md). Requirement
2 preserves event selection, ordering, content, every other REPL
command, and all scheduling decisions/state exactly as
scheduler-sim-repl-verbosity's Requirement 5 already established.

Generated via kiro-spec-quick (single-pass, no approval gates) with
an inline requirements review gate, an inline design review gate, and
an independent task-graph sanity review (one NEEDS_FIXES round,
repaired: added file-size watch bullets to tasks 1.1/1.2 per
design.md's own housekeeping directives).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YAWMhfRJFnmmnG8h97yUDd
2026-09-03 03:53:24 +00:00

15 KiB

Design Document

Overview

repl_print_event_summary() (repl_break.c) prints a "[sim] t=<ns> (<ISO8601>) session=<N>" preamble line unconditionally before every echoed event's own content line — this is its only call site, xce_repl_on_event(), which already gates WHICH events reach it per scheduler-sim-repl-verbosity's Event Echo Gate (structural events always; routine events only in step mode). Because the preamble is a fixed prefix printed on every call regardless of what the previous call printed, an operator watching several consecutive events that land in the same displayed second and session sees that context restated once per event, diluting the actual event content it's meant to introduce.

This feature makes repl_print_event_summary() preamble-aware of its own immediately-preceding output: it prints the preamble only when the rendered (second-granularity) timestamp or the displayed session number has changed since the last time a preamble was actually printed; otherwise it prints only the event's content line. No other REPL behavior changes.

Users: Operators running step or continue (structural-event) transcripts through xce_scheduler --sim <file> --interactive. Impact: repl_print_event_summary() gains a short-circuit at its top; xce_sched_repl_state_s gains two small cache fields recording what was last actually printed.

Goals

  • Print the timestamp/session preamble once per distinct (rendered timestamp, session) run of consecutive echoed events, not once per event.
  • Base "distinct" on the rendered, second-granularity timestamp and displayed session number — not the underlying raw nanosecond clock value, which changes on every event and would otherwise defeat deduplication entirely.
  • Leave every echoed event's own content line, its ordering, and whether it is echoed at all completely unchanged.

Non-Goals

  • Changing the Event Echo Gate's routine/structural classification (repl_event_is_structural()) — which events reach repl_print_event_summary() at all is unaffected.
  • Changing the Round Rollup / collapsing behavior continue mode already uses for routine events and per-round decision summaries.
  • Changing decision output (sim_print_decision/sim_print_decision_gate), which has no preamble of its own and is untouched.
  • Reformatting the preamble's own content (timestamp precision, session-number convention) — only whether it is printed, not what it looks like when it is.

Boundary Commitments

This Spec Owns

  • The preamble-print decision inside repl_print_event_summary()'s single call site.
  • Two new cache fields on xce_sched_repl_state_s (repl_internal.h) recording the last preamble actually printed.

Out of Boundary

  • The Event Echo Gate's classification logic (repl_event_is_structural(), repl_break.c) — unmodified, this spec only changes what happens after an event has already been selected for echoing.
  • The Round Rollup / collapsing logic (repl_rollup.c) and sim_print_decision_gate() (sim_loop.c) — both unmodified.
  • Every REPL command's parsing, dispatch, or output other than this one preamble line.

Allowed Dependencies

  • xce_sched_repl_state_s (repl_internal.h, existing) — the two new cache fields live here, alongside this file's other REPL-session-scoped state.
  • repl_format_ts_human() (repl_fmt.c, existing, from scheduler-sim-repl-verbosity) — reused as-is to render the human-readable timestamp string used for the dedup comparison; not modified.

Revalidation Triggers

  • If repl_format_ts_human()'s rendered granularity or format ever changes, re-verify the dedup key still reflects what an operator actually sees as "the same displayed context."
  • If repl_print_event_summary() ever gains a second call site, revisit whether a single "last printed" cache still correctly models "immediately preceding echoed event" across both sites.

Architecture

Existing Architecture Analysis

repl_print_event_summary() is static and has exactly one caller, xce_repl_on_event() (repl_break.c), itself reached only when sim->interactive and sim->repl_state != NULL — both already guaranteed by the time this function runs, so no new NULL-handling is introduced. The function currently: (1) unconditionally builds and prints the preamble, then (2) switches on ev->type to print the event's own content. This design touches only step (1); step (2) and the surrounding gate in xce_repl_on_event() are unchanged.

xce_sched_repl_state_s already carries several REPL-session-scoped caches added by prior tasks (the Round Rollup's collapse-state fields, units_mode) — the two new fields here follow that same established pattern: session-lifetime state, zero-initialized by repl_state_ensure()'s existing calloc, with no additional lifecycle code required (an empty string and a 0 session number can never equal a real echoed event's rendered values, so the "no preceding echoed event" case, AC 1.2, is satisfied by zero-initialization alone — the same convention every field in this struct except units_mode already relies on).

Architecture Integration:

  • Selected pattern: extend one existing function's own early logic; no new component, no new file.
  • Domain/feature boundaries: strictly inside the REPL Output domain (repl_break.c/repl_internal.h) scheduler-sim-repl-verbosity already established; no other domain (Round Rollup, Resource Formatter, Help/Breakpoint) is touched.
  • Existing patterns preserved: xce_sched_repl_state_s as the single home for REPL-session-scoped display state; repl_format_ts_human() as the sole human-timestamp renderer.
  • New components rationale: none — this is a localized behavior change to one existing function plus two state fields, not a new component.
  • Steering compliance: src/scheduler/CLAUDE.md's 800-line-per-file cap applies to repl_break.c, which is already at 949 lines (an accepted residual from scheduler-sim-repl-verbosity task 9.2). This spec's addition is small (a handful of lines inside one existing function), but implementation must re-check the file's line count after landing it and, per this file family's established practice, empirically test extracting repl_print_event_summary() (and its Event Echo Gate neighbors) into a new file if the total meaningfully exceeds the residual already accepted — not a decision to make speculatively before the actual diff size is known.

File Structure Plan

Modified Files

  • src/scheduler/src/repl_break.c — repl_print_event_summary() gains a preamble-print decision at its top: render the candidate human timestamp and displayed session number, compare against rs->last_echo_ts_human/rs->last_echo_session; print the preamble and update both cache fields only when either differs (or the cache is still at its zero-initialized default), otherwise skip straight to the event's own content switch.
  • src/scheduler/src/repl_internal.h — xce_sched_repl_state_s gains last_echo_ts_human (fixed-size char buffer, same size as the existing repl_format_ts_human() output buffers elsewhere in this file family) and last_echo_session (uint64_t), both doc-commented as this feature's cache, zero-initialized by the existing repl_state_ensure() allocation path with no additional lifecycle code.

New/Modified Test Files

  • src/scheduler/testsuite/test_repl_event_echo.c (extend, existing home for Event Echo Gate behavior this feature builds directly on top of) — the new preamble-dedup tests (see Testing Strategy). This file is at 705 lines going into this spec; re-check its line count after landing these tests and split into a new test_repl_step_verbosity.c (following this file family's established "duplicate fixture helpers, don't share" convention — see scheduler-sim-repl-verbosity design.md's own Corrections for the precedent) if it approaches this project's ~1000-line split trigger, rather than growing past it.

Requirements Traceability

Requirement Summary Components Interfaces Flows
1.1 Omit preamble when rendered timestamp+session unchanged Event Echo Preamble Deduplicator repl_print_event_summary() n/a
1.2 Print preamble when rendered timestamp+session changed, or no prior echo Event Echo Preamble Deduplicator repl_print_event_summary() n/a
1.3 Dedup key is rendered (second-granularity) timestamp + session, not raw ns Event Echo Preamble Deduplicator repl_print_event_summary() n/a
1.4 Event content/ordering/echo-selection unaffected Event Echo Preamble Deduplicator repl_print_event_summary() n/a
2.1 No event newly suppressed or added Out of Boundary (Event Echo Gate unmodified) n/a n/a
2.2 Ordering preserved Event Echo Preamble Deduplicator repl_print_event_summary() n/a
2.3 Every other command's behavior unchanged Out of Boundary n/a n/a
2.4 No change to scheduling decisions/state Out of Boundary (display-only change) n/a n/a

Components and Interfaces

Component Domain/Layer Intent Req Coverage Key Dependencies (P0/P1) Contracts
Event Echo Preamble Deduplicator REPL / repl_break.c Print the timestamp/session preamble once per distinct rendered context instead of once per event 1.1-1.4, 2.2 repl_format_ts_human() (P0), xce_sched_repl_state_s (P0) State

REPL Output (repl_break.c)

Event Echo Preamble Deduplicator

Field Detail
Intent Suppress the timestamp/session preamble on an echoed event when it would exactly restate the immediately preceding echoed event's rendered context
Requirements 1.1, 1.2, 1.3, 1.4, 2.2

Responsibilities & Constraints

  • Computes the candidate human-readable timestamp via the existing repl_format_ts_human(xce_core_now(&sim->core), ...) call already present in repl_print_event_summary(), and the candidate displayed session number (rs->session_count + 1, the existing expression already used) — no new value sources.
  • Compares the candidate pair against rs->last_echo_ts_human/rs->last_echo_session. Prints the preamble and updates both cache fields when they differ, or when the cache is still at its zero-initialized "never printed" default (empty string / session 0, values no real echoed event can legitimately produce). Skips the preamble entirely, with no cache update, when they match (Requirement 1.1).
  • The comparison is on the RENDERED values only — the underlying raw nanosecond xce_core_now() return value is never part of the dedup key, since it changes on every event and two events sharing the same displayed second still have different raw values (Requirement 1.3).
  • The event's own content line (the existing switch (ev->type) block) is printed unconditionally regardless of the preamble decision — this component only ever suppresses the preamble, never the content (Requirement 1.4, 2.2).

Dependencies

  • Inbound: repl_print_event_summary() (repl_break.c, existing) (P0)
  • Outbound: repl_format_ts_human() (repl_fmt.c, existing) (P0)

Contracts: Service [ ] / API [ ] / Event [ ] / Batch [ ] / State [x]

State Management
  • State model: two new fields on xce_sched_repl_state_s — last_echo_ts_human (the last rendered human timestamp actually printed in a preamble) and last_echo_session (the last displayed session number actually printed).
  • Persistence & consistency: in-memory, scoped to one REPL session, written only by this component, read only by this component. Zero-initialized by repl_state_ensure()'s existing calloc — no dedicated default-assignment step is needed (unlike units_mode's documented exception in scheduler-sim-repl-verbosity), because the zero defaults (empty string, session 0) can never collide with a real echoed event's rendered values.
  • Concurrency strategy: none required — single-threaded sim driver, same as every other REPL state field.

Implementation Notes

  • Integration: no change to repl_print_event_summary()'s call site or signature — purely internal to the function body.
  • Validation: covered entirely by the child-process stdout-capture technique test_repl_event_echo.c already establishes for Requirement 1 (Event Echo Gate) — no new test harness needed.
  • Risks: repl_break.c's existing 949-line accepted residual (see Architecture Integration above) — watch, don't pre-split.

Data Models

Domain Model

This feature adds no new domain concept — it extends the existing "REPL session-scoped display state" already modeled on xce_sched_repl_state_s (repl_internal.h), the same struct the Round Rollup and Resource Value Formatter components added fields to in scheduler-sim-repl-verbosity.

Logical Data Model

Field Type Purpose
last_echo_ts_human char[32] The human-readable timestamp last actually printed in an event's preamble (same buffer size repl_format_ts_human()'s other call sites already use)
last_echo_session uint64_t The displayed session number last actually printed in an event's preamble

Consistency & Integrity: both fields reset together only at REPL session start, via repl_state_ensure()'s existing calloc zero-initialization — no explicit reset code path exists or is needed, since no other event in this struct's lifecycle should cause "what was last displayed" to become stale mid-session.

Error Handling

Error Strategy

No new failure modes: this feature performs only in-memory string/integer comparisons and a fprintf that already exists at this call site — no allocation, no I/O beyond the pre-existing stdout write.

Monitoring

No new logging — the existing [sim] ... stdout convention is the only output surface, and this feature only changes how often one of its existing lines appears.

Testing Strategy

Integration Tests (extend test_repl_event_echo.c, child-process output capture — see File Structure Plan for the split-if-needed note)

  • Two consecutive echoed events with identical rendered timestamp and session: the second event's preamble line is absent, its content line still appears (1.1, 1.4).
  • Two consecutive echoed events whose session differs (a session boundary occurs between them): both events print their own full preamble (1.2).
  • Two consecutive echoed events whose raw high-resolution timestamps differ but whose rendered (rounded) timestamp and session are identical: the second event's preamble is still omitted — the critical case distinguishing this feature's actual dedup key from a naive raw-timestamp comparison (1.3).
  • The very first echoed event in a fresh REPL session prints its preamble (no prior echo exists to compare against) (1.2).
  • A structural event echoed under continue mode after a stretch of suppressed routine events: its preamble prints or is suppressed based on the same rendered-context rule, exercising the dedup logic outside step mode too (1.1, 1.2).
  • step mode's full event/content ordering and count are unchanged versus this feature's baseline — regression check alongside this file's existing Event Echo Gate assertions (2.1, 2.2).

Regression (existing suites, re-run, no new tests)

  • test_repl_execution_control.c and test_repl_equivalence.c: confirm no other REPL command's output changed and the REPL/batch decision-equivalence guarantee still holds (2.3, 2.4) — the same spot-check discipline scheduler-sim-repl-verbosity's task 10.1/10.2 already established for this exact concern.