docs(scheduler-sim-repl-verbosity): expand spec with Requirements 5.5, 6, 7

Extends the original continue-mode-noise-reduction spec (Requirements
1-5, 4 tasks) with three more requirements surfaced during a cli-ux
review of the live REPL:

- Req 5.5: REPL prompt shows current session/timestamp (step+continue)
- Req 6: human-readable byte/megabyte resource value formatting, table
  layout for info worker/info resource, and a new `set units` option
- Req 7: help listing reorganized into labeled sections, and break's
  valid event types made discoverable in both help and its error text

design.md gains three matching components (REPL Prompt Context,
Resource Value Formatter, Help & Breakpoint Discoverability), each
grounded in direct source verification (node_information.c's mem/tmp/
swp unit docstrings, test.c's is_bytes_valued_resource()/
format_bytes_human() precedent, BP_KIND_TABLE's actual contents).
Went through a full self-review pass fixing 7 internal-consistency
issues (stale System Flows section, a factual error in the claimed
timestamp format, a missing Requirements Traceability row, an
enum-zero-init assumption, a session_count off-by-one trap, and
incomplete Domain Model prose) before design/tasks approval.

tasks.md's own expansion (task groups 6-10) is committed alongside
each task's implementation, not here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YAWMhfRJFnmmnG8h97yUDd
This commit is contained in:
Rongsong Shen 2026-09-02 08:40:43 +00:00
parent 140f0900b5
commit e6c670194f
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
3 changed files with 201 additions and 27 deletions

View file

@ -5,44 +5,58 @@
**Users**: XCE scheduler engineers and operators debugging scheduling behavior via `xce_scheduler -i -s <replay>`, a capability shipped by the `scheduler-core` spec. **Users**: XCE scheduler engineers and operators debugging scheduling behavior via `xce_scheduler -i -s <replay>`, a capability shipped by the `scheduler-core` spec.
**Impact**: Changes only the text `xce_repl_on_event()` (repl_break.c) and `sim_print_decision()` (sim_loop.c) print while `sim->repl_state->mode == XCE_REPL_MODE_CONTINUE`. No change to scheduling decisions, replay determinism, `step`-mode output, or any other REPL command. **Impact**: Changes the text `xce_repl_on_event()` (repl_break.c) and `sim_print_decision()` (sim_loop.c) print while `sim->repl_state->mode == XCE_REPL_MODE_CONTINUE`; the REPL's command prompt string (`repl_command_loop()`, repl.c); `info worker`'s/`info resource`'s resource-value rendering and the `set` command (repl_info.c, repl_params.c); and `help`'s listing plus `break`'s unrecognized-event-type error text (repl.c, repl_break.c). No change to scheduling decisions, replay determinism, or `step` mode's per-event/per-decision detail; every other aspect of every REPL command's parsing and behavior is unchanged.
### Goals ### Goals
- Suppress routine per-event echo during `continue` execution, while still surfacing structural changes (Requirement 1). - Suppress routine per-event echo during `continue` execution, while still surfacing structural changes (Requirement 1).
- Replace unconditional per-decision echo with one summary line per round during `continue` (Requirement 2). - Replace unconditional per-decision echo with one summary line per round during `continue` (Requirement 2).
- Collapse consecutive idle or unchanged rounds into a single range notification (Requirement 3). - Collapse consecutive idle or unchanged rounds into a single range notification (Requirement 3).
- Compress array-job identifier lists into index ranges everywhere the REPL displays multiple job identifiers together (Requirement 4). - Compress array-job identifier lists into index ranges everywhere the REPL displays multiple job identifiers together, including `info worker`'s assigned-job listing (Requirement 4).
- Leave `step` mode and every other existing REPL command byte-for-byte unchanged (Requirement 5). - Leave `step` mode's per-event/per-decision detail, and every other aspect of the REPL's existing commands, unchanged except where this feature's own requirements explicitly say otherwise (Requirement 5).
- Show the current session and timestamp in the REPL's command prompt, in both `step` and `continue` modes (Requirement 5.5).
- Render byte/megabyte-denominated resource values in a human-readable unit under operator control (`set units`), and lay out `info worker`'s/`info resource`'s listings as a grouped table (Requirement 6).
- Reorganize `help`'s command listing into labeled, consistently-aligned sections, and make `break`'s valid event types discoverable in both `help` and its error message (Requirement 7).
### Non-Goals ### Non-Goals
- New REPL commands or newly inspectable data (limit usage, pend-reason detail) — tracked separately under the `scheduler-sim-diagnostics` brief. - New REPL commands or newly inspectable data (limit usage, pend-reason detail) — tracked separately under the `scheduler-sim-diagnostics` brief.
- Any change to scheduling/allocation logic or to the deterministic outcome of a replay. - Any change to scheduling/allocation logic or to the deterministic outcome of a replay.
- Non-interactive (headless, no `-i`) scheduler output. - Non-interactive (headless, no `-i`) scheduler output.
- Resolving bug-1611 (whether `DISPATCH` decisions are structurally invisible in replay mode) — this spec only guarantees Requirement 2.4 holds regardless of that investigation's outcome (see Design Decisions, `research.md`). - Resolving bug-1611 (whether `DISPATCH` decisions are structurally invisible in replay mode) — this spec only guarantees Requirement 2.4 holds regardless of that investigation's outcome (see Design Decisions, `research.md`).
- Unit-aware formatting for any resource outside the confirmed canonical-bytes list (`mem`, `tmp`, `maxmem`, `maxtmp`, `maxswap`) and the confirmed canonical-megabytes `swp` — `xce_resource_t` (`src/include/xce/types.h`) carries no units metadata at all, so an arbitrary operator-defined or plugin resource is displayed as a plain unitless number, exactly as today.
## Boundary Commitments ## Boundary Commitments
### This Spec Owns ### This Spec Owns
- Console output formatting/verbosity logic inside `xce_repl_on_event()` (repl_break.c), the `continue`-mode gate on `sim_print_decision()`'s call site (sim_loop.c), and the new round-boundary rollup/collapse logic added at `xce_repl_post_session_check()` (repl.c). - Console output formatting/verbosity logic inside `xce_repl_on_event()` (repl_break.c), the `continue`-mode gate on `sim_print_decision()`'s call site (sim_loop.c), and the new round-boundary rollup/collapse logic added at `xce_repl_post_session_check()` (repl.c).
- The new jobid-range-compression helper and every call site that adopts it. - The new jobid-range-compression helper and every call site that adopts it, including `info worker`'s assigned-job listing (repl_info.c).
- New `xce_sched_repl_state_s` fields required to track collapse state across rounds. - New `xce_sched_repl_state_s` fields required to track collapse state across rounds.
- The REPL prompt string construction in `repl_command_loop()` (repl.c).
- Resource-value unit classification/scaling helpers, the `units_mode` display setting, and the table/grouping layout of `info worker`'s and `info resource`'s resource listings (repl_info.c, repl_params.c).
- `repl_print_help()`'s listing structure (repl.c) and `repl_cmd_break()`'s unrecognized-event-type error text (repl_break.c).
### Out of Boundary ### Out of Boundary
- Any new `info`/`break`/`set` subcommand or newly inspectable scheduler data. - Any new `info`/`break`/`set` top-level subcommand or newly inspectable scheduler data (`set units` is a new *option* of the existing `set` command, not a new command).
- Scheduling/allocation/decision logic itself (`scheduler.c`, `src/plugins/`). - Scheduling/allocation/decision logic itself (`scheduler.c`, `src/plugins/`).
- `sim_print_decision()`'s behavior when `sim->interactive` is false (headless mode) — unchanged. - `sim_print_decision()`'s behavior when `sim->interactive` is false (headless mode) — unchanged.
- Root-causing bug-1611 — a separate investigation; this spec only ensures its own requirements hold regardless of the answer. - Root-causing bug-1611 — a separate investigation; this spec only ensures its own requirements hold regardless of the answer.
- Unit-aware formatting for resources outside the confirmed bytes/megabytes list (see Non-Goals) — no generic units-metadata system is added to `xce_resource_t` or the wire protocol.
### Allowed Dependencies ### Allowed Dependencies
- Existing `xce_sched_repl_state_s` fields (`mode`, `last_n_dispatch`/`last_n_pend`/`last_n_preempt`, `session_count`) — repl_internal.h. - Existing `xce_sched_repl_state_s` fields (`mode`, `last_n_dispatch`/`last_n_pend`/`last_n_preempt`, `session_count`) — repl_internal.h.
- The existing `core->jobs` iteration idiom (`iter_make`/`iter_next`, `JOB_IS_PEND`) already used by `repl_info_jobs()`. - The existing `core->jobs` iteration idiom (`iter_make`/`iter_next`, `JOB_IS_PEND`) already used by `repl_info_jobs()`.
- Existing helpers `fmt_jobid_ex()` (lib/utils.c) and `repl_format_ts_human()` (repl.c). - Existing helpers `fmt_jobid_ex()` (lib/utils.c) and `repl_format_ts_human()` (repl.c).
- Must not add a new call site to `sim_loop.c`'s main loop beyond gating the two calls that already exist there (`sim_print_decision`, the `xce_repl_check_event` wrapper) — that file is documented at its line-budget ceiling (repl.h's own header comment). - Must not add a new call site to `sim_loop.c`'s main loop beyond gating the two calls that already exist there (`sim_print_decision`, the `xce_repl_check_event` wrapper) — that file is documented at its line-budget ceiling (repl.h's own header comment).
- `xce_sched_repl_state_s.session_count` and `xce_core_now()`/`repl_format_ts_human()` (repl.c) for the prompt's session/timestamp content — no new state needed for that part.
- `repl_break.c`'s existing `BP_KIND_TABLE` (currently `static`/file-local) — exposed via one new shared accessor declared in `repl_internal.h`, rather than duplicated as a second hardcoded list, so `help` and the unrecognized-event-type error can never drift out of sync with each other or with the table itself.
- The existing `repl_command_loop()` call site's `readline(XCE_REPL_PROMPT)` (repl.c:439) — this feature makes the prompt argument dynamic in place; no new call site.
- `src/controller/testsuite/test.c`'s `is_bytes_valued_resource()`/`format_bytes_human()` as a design *precedent* only (same classification list, same adaptive B/KB/MB/GB/TB/PB algorithm) — not a shared symbol, since `xce_test` and `xce_scheduler` are separate binaries; the scheduler gets its own `repl_*`-named port of the same logic.
### Revalidation Triggers ### Revalidation Triggers
- If `scheduler-sim-diagnostics` adds pend-reason data, the round-rollup collapse fingerprint (Design Decisions, `research.md`) may need to incorporate it — revisit Requirement 3.2's implementation then. - If `scheduler-sim-diagnostics` adds pend-reason data, the round-rollup collapse fingerprint (Design Decisions, `research.md`) may need to incorporate it — revisit Requirement 3.2's implementation then.
- If bug-1611 is confirmed a real dispatch-visibility gap and separately fixed, the rollup's dispatch *count* source should switch from the decision tally to the same state-derived approach already used for the pend-jobid set. - If bug-1611 is confirmed a real dispatch-visibility gap and separately fixed, the rollup's dispatch *count* source should switch from the decision tally to the same state-derived approach already used for the pend-jobid set.
- Any change to `xce_sched_repl_state_s`'s existing `mode`/tally fields by another spec should re-check this feature's rollup logic. - Any change to `xce_sched_repl_state_s`'s existing `mode`/tally fields by another spec should re-check this feature's rollup logic.
- If a future spec adds real units metadata to `xce_resource_t` (see Non-Goals), the hardcoded bytes/megabytes classification lists added here should be replaced by reading that metadata instead of the name-match lists.
- If `repl_break.c`'s `BP_KIND_TABLE` gains or loses an entry (e.g. a new breakpoint-able event type), `help` and `break`'s error message pick it up automatically via the shared accessor — no separate list to update, by construction.
## Architecture ## Architecture
@ -87,18 +101,23 @@ flowchart TD
## File Structure Plan ## File Structure Plan
### Modified Files ### Modified Files
- `src/scheduler/src/repl_internal.h` — extend `xce_sched_repl_state_s` with round-collapse state fields (see Data Models) and declare the new shared jobid-range-compression helper. - `src/scheduler/src/repl_internal.h` — extend `xce_sched_repl_state_s` with round-collapse state fields (see Data Models), a new `units_mode` field (Requirement 6), and declare the new shared jobid-range-compression helper, resource-formatting helpers, and the `BP_KIND_TABLE` accessor (Requirement 7).
- `src/scheduler/src/repl_break.c` — `xce_repl_on_event()` gains routine-vs-structural event classification gated on `rs->mode` (Requirement 1); `repl_print_event_summary()`'s `JOB_PUSH`-style cases adopt the jobid-range-compression helper (Requirement 4); `xce_repl_on_event()`, `xce_repl_on_begin_round()`, and `xce_repl_on_decision()` each call the Round Rollup's flush entry point before printing a structural-event line or before re-entering `repl_command_loop()` on a breakpoint hit (Requirement 3.5, 3.6). - `src/scheduler/src/repl_break.c` — `xce_repl_on_event()` gains routine-vs-structural event classification gated on `rs->mode` (Requirement 1); `repl_print_event_summary()`'s `JOB_PUSH`-style cases adopt the jobid-range-compression helper (Requirement 4); `xce_repl_on_event()`, `xce_repl_on_begin_round()`, and `xce_repl_on_decision()` each call the Round Rollup's flush entry point before printing a structural-event line or before re-entering `repl_command_loop()` on a breakpoint hit (Requirement 3.5, 3.6); `repl_cmd_break()`'s unrecognized-event-type error gains the full valid-event-type listing, rendered via a new shared accessor over the existing `BP_KIND_TABLE` (Requirement 7.5); `repl_cmd_delete()` already fixed independently (bug-1761, `strtol`+endptr validation) — no further change needed here for this spec.
- `src/scheduler/src/repl.c` — `xce_repl_post_session_check()` gains the round-boundary fingerprint/collapse logic (Requirements 2, 3); implements the new shared jobid-range-compression helper (Requirement 4) and the Round Rollup's flush entry point (Requirement 3.5, 3.6), following the file's existing shared-helper convention; `xce_repl_on_replay_complete()` calls the same flush entry point before printing the existing replay-complete banner. - `src/scheduler/src/repl.c` — `xce_repl_post_session_check()` gains the round-boundary fingerprint/collapse logic (Requirements 2, 3); implements the new shared jobid-range-compression helper (Requirement 4) and the Round Rollup's flush entry point (Requirement 3.5, 3.6), following the file's existing shared-helper convention; `xce_repl_on_replay_complete()` calls the same flush entry point before printing the existing replay-complete banner; `repl_command_loop()`'s `readline(XCE_REPL_PROMPT)` call gains a per-iteration dynamically-built prompt (Requirement 5.5); `repl_print_help()` is rewritten into labeled, consistently-aligned sections, `info config` moves next to the other `info` lines, and the `break` line grows the same `BP_KIND_TABLE`-derived event-type listing `repl_break.c`'s error message uses (Requirement 7).
- `src/scheduler/src/repl_info.c` — new resource-value classification/scaling helpers (byte-denominated list, `swp`'s megabyte special case, whole-number formatting) and a table/grouping rewrite of `repl_info_worker()`'s and `repl_info_resource()`'s resource-listing loops, both reading `rs->units_mode` (Requirement 6); the assigned-job listing in `repl_info_worker()` adopts the jobid-range-compression helper (Requirement 4.5).
- `src/scheduler/src/repl_params.c` — `repl_cmd_set()` gains a `units raw|human|both` branch alongside the existing `speed`/`output`/`verify` branches, storing the selection on the new `rs->units_mode` field (Requirement 6.2, 6.3).
- `src/scheduler/src/sim_loop.c` — the existing call site invoking `sim_print_decision()` gains a `continue`-mode gate, mirroring `repl.h`'s inline-wrapper convention (Requirements 2, 5). - `src/scheduler/src/sim_loop.c` — the existing call site invoking `sim_print_decision()` gains a `continue`-mode gate, mirroring `repl.h`'s inline-wrapper convention (Requirements 2, 5).
- `src/scheduler/include/repl.h` — no functional change expected; existing inline wrappers already cover the gating points this feature needs. - `src/scheduler/include/repl.h` — no functional change expected; existing inline wrappers already cover the gating points this feature needs.
### New/Modified Test Files ### New/Modified Test Files
- `src/scheduler/testsuite/test_repl_execution_control.c` — extended with child-process output-capture tests covering Requirements 1, 2, 3, and the Requirement 5 no-regression checks (this file already drives `sched_sim_driver_run()` end-to-end and captures real process output via `child_continue_then_inspect`-style helpers). - `src/scheduler/testsuite/test_repl_execution_control.c` — extended with child-process output-capture tests covering Requirements 1, 2, 3, and the Requirement 5 no-regression checks (this file already drives `sched_sim_driver_run()` end-to-end and captures real process output via `child_continue_then_inspect`-style helpers); also gains the new prompt-content tests (Requirement 5.5) and `help`-listing structure tests (Requirement 7.1-7.4) — the natural home given it already exercises `readline()`/prompt-adjacent behavior and no `help` test exists anywhere today.
- `src/scheduler/testsuite/test_repl_output_compression.c` (new) — focused unit tests for the jobid-range-compression helper (Requirement 4): a pure function, tested without the process harness. - `src/scheduler/testsuite/test_repl_output_compression.c` (new) — focused unit tests for the jobid-range-compression helper (Requirement 4): a pure function, tested without the process harness.
- `src/scheduler/testsuite/test_repl_resource_formatting.c` (new) — focused unit tests for the byte/megabyte classification and adaptive human-scaling helpers (Requirement 6.1, 6.2, 6.5): pure functions, tested without the process harness, mirroring `test_repl_output_compression.c`'s pattern.
- `src/scheduler/testsuite/test_repl_breakpoints_inspection.c` — extended with `info worker`/`info resource` table-layout and units-mode-display tests (Requirement 6.6, alongside its existing `info worker`/`info resource` tests) and `break`'s enriched unrecognized-event-type error test (Requirement 7.5, alongside the existing `test_break_unrecognized_event_type_rejected`).
- `src/scheduler/testsuite/test_repl_snapshot_params.c` — extended with `set units raw|human|both` parsing/validation tests (Requirement 6.2, 6.3), alongside its existing `set speed`/`set output`/`set verify` tests.
## System Flows ## System Flows
See the Architecture Pattern & Boundary Map diagram above — it is the only non-trivial flow this feature introduces (a per-round branching decision with two exit points: silent extension, or flush-and-restart). Per-event classification (Requirement 1) is a simple, non-branching gate and does not warrant a separate diagram. See the Architecture Pattern & Boundary Map diagram above — it is the only non-trivial flow this feature introduces (a per-round branching decision with two exit points: silent extension, or flush-and-restart). Per-event classification (Requirement 1) is a simple, non-branching gate and does not warrant a separate diagram. The three later-added components (REPL Prompt Context, Resource Value Formatter, Help & Breakpoint Discoverability) are likewise simple, single-purpose lookups/formatters with no multi-step state machine of their own — a name-list check, an adaptive-unit loop, and a table lookup, respectively — so none of them warrant a separate diagram either.
## Requirements Traceability ## Requirements Traceability
@ -109,7 +128,12 @@ See the Architecture Pattern & Boundary Map diagram above — it is the only non
| 3.1, 3.2, 3.3, 3.4 | Collapsing repetitive rounds (idle/unchanged detection, range content) | Round Rollup (collapse state) | fingerprint compare / flush | Round-boundary flow | | 3.1, 3.2, 3.3, 3.4 | Collapsing repetitive rounds (idle/unchanged detection, range content) | Round Rollup (collapse state) | fingerprint compare / flush | Round-boundary flow |
| 3.5, 3.6 | Ending an active collapsed range on outcome change, structural event, breakpoint hit, or replay completion | Round Rollup (flush entry point, and its own call from `xce_repl_on_replay_complete`), Event Echo Gate (calls it on structural events/breakpoint hits) | `repl_round_collapse_flush` | Round-boundary flow | | 3.5, 3.6 | Ending an active collapsed range on outcome change, structural event, breakpoint hit, or replay completion | Round Rollup (flush entry point, and its own call from `xce_repl_on_replay_complete`), Event Echo Gate (calls it on structural events/breakpoint hits) | `repl_round_collapse_flush` | Round-boundary flow |
| 4.1, 4.2, 4.3, 4.4, 4.5 | Job identifier range compression | Jobid Range Compressor | `repl_fmt_jobid_range` | n/a (pure formatting) | | 4.1, 4.2, 4.3, 4.4, 4.5 | Job identifier range compression | Jobid Range Compressor | `repl_fmt_jobid_range` | n/a (pure formatting) |
| 5.1, 5.2, 5.3, 5.4 | No regression to step mode / other commands | Event Echo Gate, `sim_print_decision` gate | mode checks | n/a | | 5.1, 5.2, 5.3, 5.4 | No regression to step mode / other commands, outside this feature's explicit exceptions | Event Echo Gate, `sim_print_decision` gate | mode checks | n/a |
| 5.5 | REPL prompt shows session/timestamp | REPL Prompt Context | `repl_build_prompt` | n/a (per-iteration, upstream of dispatch) |
| 6.1, 6.2, 6.3, 6.4, 6.5 | Human-readable resource value formatting, `set units` option | Resource Value Formatter | `repl_is_bytes_valued_resource`, `repl_format_bytes_human`, `repl_cmd_set`'s `units` branch | n/a (pure formatting + state) |
| 6.6 | `info worker`/`info resource` table/grouping layout | Resource Value Formatter | `repl_info_worker`, `repl_info_resource` | n/a (rendering only) |
| 7.1, 7.2, 7.3 | `help` listing reorganized into labeled, aligned sections | Help & Breakpoint Discoverability | `repl_print_help` | n/a (rendering only) |
| 7.4, 7.5, 7.6 | `break` event types discoverable in `help` and its error message; no other command's existence, parsing, or output changes | Help & Breakpoint Discoverability | `repl_bp_kind_names` (shared accessor over `BP_KIND_TABLE`) | n/a (pure formatting) |
## Components and Interfaces ## Components and Interfaces
@ -119,8 +143,11 @@ See the Architecture Pattern & Boundary Map diagram above — it is the only non
| Round Rollup | REPL / repl.c | Build a per-round fingerprint, print it, or extend/flush a collapsed range; expose a flush entry point callable from breakpoint/structural-event/replay-complete sites | 2.1-2.4, 3.1-3.6 | `core->jobs` query (P0), existing decision tally (P0) | State, Service | | Round Rollup | REPL / repl.c | Build a per-round fingerprint, print it, or extend/flush a collapsed range; expose a flush entry point callable from breakpoint/structural-event/replay-complete sites | 2.1-2.4, 3.1-3.6 | `core->jobs` query (P0), existing decision tally (P0) | State, Service |
| Jobid Range Compressor | REPL / repl.c (shared helper) | Compress array-job identifier lists into index ranges | 4.1-4.5 | `fmt_jobid_ex` decomposition (P0) | Service | | Jobid Range Compressor | REPL / repl.c (shared helper) | Compress array-job identifier lists into index ranges | 4.1-4.5 | `fmt_jobid_ex` decomposition (P0) | Service |
| `sim_print_decision` gate | Sim driver / sim_loop.c | Suppress the direct per-decision print when the Round Rollup will report it instead | 2.3, 5.1 | REPL mode state (P0) | State | | `sim_print_decision` gate | Sim driver / sim_loop.c | Suppress the direct per-decision print when the Round Rollup will report it instead | 2.3, 5.1 | REPL mode state (P0) | State |
| REPL Prompt Context | REPL / repl.c | Build the `readline()` prompt string from the current session and timestamp, falling back to the plain prompt before any session begins | 5.5 | `rs->session_count` (P0), `xce_core_now`/`repl_format_ts_human` (P0) | Service |
| Resource Value Formatter | REPL / repl_info.c, repl_params.c | Classify a resource's canonical wire unit (bytes/megabytes/unitless), render it per the operator's `units_mode`, and lay out `info worker`/`info resource`'s listings as a grouped table | 6.1-6.6 | `is_bytes_valued_resource`/`format_bytes_human` (test.c) as design precedent (P0), `rs->units_mode` (P0) | Service, State |
| Help & Breakpoint Discoverability | REPL / repl.c, repl_break.c | Group and align `help`'s listing, and expose `BP_KIND_TABLE`'s full valid-event-type set to both `help` and `break`'s error message via one shared accessor | 7.1-7.6 | `BP_KIND_TABLE` (P0) | Service |
### REPL Output (repl.c / repl_break.c / sim_loop.c) ### REPL Output (repl.c / repl_break.c / repl_info.c / repl_params.c / sim_loop.c)
#### Event Echo Gate #### Event Echo Gate
| Field | Detail | | Field | Detail |
@ -191,10 +218,10 @@ void repl_round_collapse_flush(xce_sched_sim_driver_t* sim);
**Responsibilities & Constraints** **Responsibilities & Constraints**
- Pure, read-only formatting function — never mutates its input list or any scheduler/job state. - Pure, read-only formatting function — never mutates its input list or any scheduler/job state.
- Shared by `repl_print_event_summary()`'s job-arrival listings and the Round Rollup's pend-jobid display (Requirement 4.5). - Shared by `repl_print_event_summary()`'s job-arrival listings, the Round Rollup's pend-jobid display, and `repl_info_worker()`'s assigned-job listing (Requirement 4.5) — the same helper, no per-caller variant.
**Dependencies** **Dependencies**
- Inbound: `repl_print_event_summary` (P0), Round Rollup (P0) - Inbound: `repl_print_event_summary` (P0), Round Rollup (P0), `repl_info_worker` (repl_info.c) (P0)
- Outbound: `fmt_jobid_ex` (lib/utils.c) — reuses its existing `(cluster, apiserver, timestamp, job[, idx])` decomposition (P0) - Outbound: `fmt_jobid_ex` (lib/utils.c) — reuses its existing `(cluster, apiserver, timestamp, job[, idx])` decomposition (P0)
**Contracts**: Service [x] / API [ ] / Event [ ] / Batch [ ] / State [ ] **Contracts**: Service [x] / API [ ] / Event [ ] / Batch [ ] / State [ ]
@ -231,10 +258,119 @@ int repl_fmt_jobid_range(char* buf, size_t bufsz,
##### State Management ##### State Management
- State model: reads `sim->interactive` and `sim->repl_state->mode` (both existing fields); owns no new state. - State model: reads `sim->interactive` and `sim->repl_state->mode` (both existing fields); owns no new state.
#### REPL Prompt Context
| Field | Detail |
|-------|--------|
| Intent | Build the string passed to `readline()` each loop iteration so it shows the current session and timestamp instead of the static `"(sim) "` prompt |
| Requirements | 5.5 |
**Responsibilities & Constraints**
- Applies in both `step` and `continue` modes — it changes the prompt, not any command's output, so it sits outside Requirement 5's "leave unchanged" boundary by design (Requirement 5.5 is one of that requirement's own named exceptions).
- Before any session has begun (`rs->session_count == 0`, the same zero-initialized value `repl_state_ensure()`'s `calloc` already guarantees), falls back to the original plain `"(sim) "` prompt — there is no session/timestamp to show yet, and a fabricated placeholder value would be misleading.
- Once at least one session has begun, renders `"(sim session=<N> t=<human-ts>) "` using `rs->session_count` and `xce_core_now(&sim->core)` formatted through the existing `repl_format_ts_human()` — no new timestamp source, no raw-epoch-nanosecond component (unlike the four existing `t=%llu (...)` print sites elsewhere in this file family, which are out of this feature's scope per Boundary Commitments). `repl_format_ts_human()`'s existing output is the full ISO8601 form (`strftime`'s `"%Y-%m-%dT%H:%M:%SZ"`, e.g. `2026-09-02T03:29:38Z`), not a time-only string — the prompt reuses that format exactly rather than inventing a shorter one, since Allowed Dependencies commits to no new timestamp source.
- Uses **bare** `rs->session_count`, matching `info session`'s/`info config`'s existing convention (`repl_info.c:848,898`) — **not** `session_count + 1`. That `+1` exists only in `repl_print_event_summary()` (repl_break.c:611) to label events echoed *mid-stream*, before the session containing them has finished and incremented the count; the prompt, by contrast, is only ever shown *after* a `step`/`continue` has returned control (i.e. after `xce_repl_on_begin_round()` for the just-finished session has already run), so the bare count is the session that just completed — the same number `info session` would report if queried at that exact prompt. Copying the `+1` convention here would make the prompt disagree with `info session` by one.
- Built fresh on every `repl_command_loop()` iteration, immediately before the `readline()` call it feeds — never cached across iterations, since the session/timestamp can change between prompts.
**Dependencies**
- Inbound: `repl_command_loop()` (repl.c) — calls this immediately before its existing `readline(XCE_REPL_PROMPT)` line
- Outbound: `repl_format_ts_human()` (repl.c, existing), `xce_core_now()` (core_clock.c, existing)
**Contracts**: Service [x] / API [ ] / Event [ ] / Batch [ ] / State [ ]
##### Service Interface
```c
/*
* Builds this iteration's REPL prompt into `buf` (bufsz-bounded):
* "(sim) " if no session has begun yet (rs->session_count == 0), else
* "(sim session=<N> t=<ISO8601-ts>) " using the bare current session
* count (NOT +1 -- see repl_print_event_summary()'s different mid-stream
* convention) and xce_core_now()/repl_format_ts_human() (same
* "%Y-%m-%dT%H:%M:%SZ" form used elsewhere, not a shortened one). Called
* fresh from repl_command_loop() before every readline() -- never cached.
*/
void repl_build_prompt(xce_sched_sim_driver_t* sim, char* buf, size_t bufsz);
```
- Preconditions: `sim`/`sim->repl_state` non-NULL (same discipline every other REPL hook in this file family follows); `buf`/`bufsz` describe a valid, writable buffer sized for the longest possible rendering (session count width + fixed-width human timestamp).
- Postconditions: `buf` holds a NUL-terminated prompt string; identical across repeated calls within the same session/timestamp (a pure function of `sim`'s current state).
- Invariants: never blocks, never reads input, never mutates `sim`/`sim->repl_state` — a read-only formatter, same class as the Jobid Range Compressor.
#### Resource Value Formatter
| Field | Detail |
|-------|--------|
| Intent | Classify a resource's canonical wire unit, render its value per the operator's selected display mode, and lay out `info worker`'s/`info resource`'s listings as a grouped table instead of a flat line-per-resource dump |
| Requirements | 6.1, 6.2, 6.3, 6.4, 6.5, 6.6 |
**Responsibilities & Constraints**
- Classification is a small, explicit, hardcoded name list — `repl_is_bytes_valued_resource(name)` returns true for exactly `mem`, `tmp`, `maxmem`, `maxtmp`, `maxswap` (confirmed canonical-bytes on the wire: `node_information.c`'s `node_info_get_mem()`/`node_info_get_tmp()` docstrings, `xcecd.c`'s `init_host_attrs()` bug-1554 comment). This mirrors `src/controller/testsuite/test.c`'s `is_bytes_valued_resource()` exactly (same 5 names, same rationale: "a small, explicit, client-side list rather than a wire field").
- `swp` is a confirmed special case, deliberately **not** added to the bytes list: `node_info_get_swap()`'s own docstring states its canonical wire unit is megabytes, not bytes (unlike its `maxswap` counterpart, which the bug-1554 comment confirms IS bytes). Before formatting, `swp`'s value is converted MB→bytes (`× 1024.0 × 1024.0`) and then passed through the same human-scaling formatter as the bytes-native resources, so it renders on the same adaptive B/KB/MB/GB/TB/PB scale rather than staying a raw MB float.
- `repl_format_bytes_human(bytes, buf, bufsz)` adaptively scales to the smallest unit the value fits (B/KB/MB/GB/TB/PB), mirroring `test.c`'s `format_bytes_human()` algorithm exactly (divide by 1024 while `>= 1024.0`, cap at PB).
- Display mode (`raw`/`human`/`both`) is a new `xce_sched_repl_state_s` field, `units_mode`, defaulting to `both` (Requirement 6.3) and settable via `set units raw|human|both` (repl_params.c, alongside the existing `speed`/`output`/`verify` branches) — `both` renders `"<raw> (<human>)"`, matching `xce_test`'s own `cmd_resval` display convention exactly (`test.c`'s `"%f (%s)\n"`).
- Numeric resources with no canonical unit (load averages, factors, counts — everything not in the bytes list and not `swp`) print without a unit suffix, and without a trailing `.00` when the value has no fractional part — replaces the current unconditional `"%.2f"` in `repl_info.c`'s `Value_u_fvalue` branch with a conditional format.
- `info worker`'s and `info resource`'s resource-listing loops are rewritten from an unstructured per-resource `fprintf` into an aligned table, grouped into labeled sections where applicable to that listing (consumable/capacity resources with a `used=` split; load/utilization metrics; static hardware attributes such as `type`/`model`/`cpuf`/`maxcpus`/`ndisks` — `info resource`'s cluster-wide GLOBAL/SHARED scope, per bug-1593, may not populate every section). Column widths are computed once (a shared field-width format), not hand-padded per line.
- Never alters the underlying stored/wire value or the deterministic outcome of a replay (Requirement 6.4) — display-only, same discipline `test.c`'s own `format_bytes_human()` doc comment states ("the stored/wire value stays raw bytes always, this never feeds back into anything").
**Dependencies**
- Inbound: `repl_info_worker()`, `repl_info_resource()` (repl_info.c) (P0); `repl_cmd_set()` (repl_params.c) (P0)
- Outbound: none beyond standard C formatting — a self-contained classification/formatting pair, same shape as the Jobid Range Compressor
**Contracts**: Service [x] / API [ ] / Event [ ] / Batch [ ] / State [x]
##### Service Interface
```c
/* Returns true iff `name`'s canonical wire unit is bytes (mem, tmp,
* maxmem, maxtmp, maxswap only -- swp is handled separately, see above). */
bool repl_is_bytes_valued_resource(const char* name);
/* Adaptively scales `bytes` to the smallest unit it fits (B/KB/MB/GB/TB/
* PB), writing e.g. "20.56 GB" into `buf` (bufsz-bounded). Display-only;
* never touches the underlying stored value. */
void repl_format_bytes_human(double bytes, char* buf, size_t bufsz);
```
- Preconditions: `name` non-NULL for the classifier; `buf`/`bufsz` describe a valid, writable buffer for the formatter.
- Postconditions: the classifier returns a stable, name-only-dependent boolean; the formatter writes a NUL-terminated, human-readable string.
- Invariants: both are pure functions — no side effects, no dependency on REPL session state.
##### State Management
- State model: new `units_mode` field (enum `raw`/`human`/`both`) on `xce_sched_repl_state_s`, defaulting to `both`; read by the table-rendering code, written only by `set units`.
- Persistence & consistency: in-memory, scoped to one REPL session. Unless the `both` enumerator is deliberately assigned value 0 in its `enum` declaration, `calloc`'s zero-initialization will *not* select it — `repl_state_ensure()` must explicitly set `units_mode = XCE_REPL_UNITS_BOTH` after allocation regardless of member order, the one field in this struct that cannot rely on zero-initialization alone (called out explicitly since every other field in this struct today deliberately relies on `calloc`'s zero value being the correct default).
- Concurrency strategy: none required — single-threaded sim driver.
#### Help & Breakpoint Discoverability
| Field | Detail |
|-------|--------|
| Intent | Reorganize `help`'s listing into labeled, aligned sections, and expose `break`'s complete valid-event-type set to both `help` and its own error message from one shared source |
| Requirements | 7.1, 7.2, 7.3, 7.4, 7.5, 7.6 |
**Responsibilities & Constraints**
- `repl_print_help()` (repl.c) is rewritten into four labeled sections — Execution Control (`step`/`continue`/`quit`/`help`), Breakpoints (`break`/`info break`/`delete`), State Inspection (`info session`/`job`/`jobs`/`queue`/`worker`/`resource`/`summary`/`config` — `info config` moved here, next to its siblings, per Requirement 7.3), Snapshot & Parameters (`snapshot`/`set speed`/`set output`/`set verify`/`set units`) — each section using one shared field-width `fprintf` format (e.g. `" %-38s%s\n"`) instead of independently hand-counted spaces per line, so a future command addition can't silently break alignment the way `info config`'s append did.
- `BP_KIND_TABLE` (repl_break.c, `static`/file-local today) is exposed through one new shared accessor, `repl_bp_kind_names()`, that renders the complete comma-joined list of valid `<EVENT_TYPE>` tokens once. Both `repl_print_help()`'s `break` line (repl.c) and `repl_cmd_break()`'s unrecognized-event-type error (repl_break.c, same file as the table — a trivial local call) use this accessor rather than each hardcoding the list — the two can never drift out of sync with each other or with `BP_KIND_TABLE` itself (Revalidation Triggers).
- No change to which commands exist, how any command parses its arguments, or any other command's output (Requirement 7.6) — this component only touches `help`'s rendering and the two places that now surface `BP_KIND_TABLE`'s contents.
**Dependencies**
- Inbound: `repl_print_help()` (repl.c) (P0), `repl_cmd_break()`'s error path (repl_break.c) (P0)
- Outbound: `BP_KIND_TABLE` (repl_break.c, existing) (P0)
**Contracts**: Service [x] / API [ ] / Event [ ] / Batch [ ] / State [ ]
##### Service Interface
```c
/*
* Renders BP_KIND_TABLE's complete set of valid break <EVENT_TYPE> tokens
* as one comma-joined, NUL-terminated string into `buf` (bufsz-bounded) --
* e.g. "CONFIG_PUSH, JOB_PUSH, ..., DECISION". Used by both
* repl_print_help() and repl_cmd_break()'s unrecognized-event-type error
* so the two can never disagree with each other or with BP_KIND_TABLE.
*/
void repl_bp_kind_names(char* buf, size_t bufsz);
```
- Preconditions: `buf`/`bufsz` describe a valid, writable buffer sized for the full table (12 entries at the time of writing).
- Postconditions: `buf` holds every `BP_KIND_TABLE` token, comma-joined, in table order.
- Invariants: pure function of `BP_KIND_TABLE`'s current contents — adding/removing a table entry changes this function's output with no other code change required.
## Data Models ## Data Models
### Domain Model ### Domain Model
This feature adds a "round collapse state" concept to the REPL's existing session-scoped state (`xce_sched_repl_state_s`, repl_internal.h) — not a new top-level entity. It follows the same pattern prior REPL task revisions used to add `output_path`/`replay_complete` to that struct. This feature adds two concepts to the REPL's existing session-scoped state (`xce_sched_repl_state_s`, repl_internal.h) — not a new top-level entity: a "round collapse state" (Requirements 2, 3) and an independent "resource display preference" (`units_mode`, Requirement 6). It follows the same pattern prior REPL task revisions used to add `output_path`/`replay_complete` to that struct.
### Logical Data Model ### Logical Data Model
New fields on `xce_sched_repl_state_s` (illustrative — exact types finalized at implementation time): New fields on `xce_sched_repl_state_s` (illustrative — exact types finalized at implementation time):
@ -246,8 +382,9 @@ New fields on `xce_sched_repl_state_s` (illustrative — exact types finalized a
| `collapse_start_ts` / `collapse_end_ts` | `uint64_t` | Sim-time bounds, for the collapsed range's time span (Requirement 3.4) | | `collapse_start_ts` / `collapse_end_ts` | `uint64_t` | Sim-time bounds, for the collapsed range's time span (Requirement 3.4) |
| `collapse_dispatch_count` / `collapse_preempt_count` | `int` | Cached fingerprint counts | | `collapse_dispatch_count` / `collapse_preempt_count` | `int` | Cached fingerprint counts |
| `collapse_pend_jobids` / `collapse_n_pend_jobids` | pointer + count | Cached fingerprint pend-jobid set, in whatever list form the Jobid Range Compressor consumes | | `collapse_pend_jobids` / `collapse_n_pend_jobids` | pointer + count | Cached fingerprint pend-jobid set, in whatever list form the Jobid Range Compressor consumes |
| `units_mode` | enum (`raw`/`human`/`both`) | Requirement 6's resource-value display mode, settable via `set units`; defaults to `both` |
**Consistency & Integrity**: all fields reset together whenever a range flushes (print, then clear) or a new REPL session begins — `repl_state_ensure()`'s existing `calloc` zero-initializes new fields with no additional lifecycle code required. **Consistency & Integrity**: all fields reset together whenever a range flushes (print, then clear) or a new REPL session begins — `repl_state_ensure()`'s existing `calloc` zero-initializes new fields with no additional lifecycle code required, **except** `units_mode`: unless `both` is deliberately given `enum` value 0, `calloc`'s zero-initialization will not select it, so `repl_state_ensure()` must explicitly set it to `both` after allocation regardless of the enum's member order — the one field in this struct where zero-initialization alone cannot be relied upon to be the correct default.
No Physical Data Model, API Data Transfer, or Event Schema subsections apply: this feature has no persistent storage, no network wire format, and adds no new wire-level contract — it stays inside `scheduler-core`'s existing "simulation isolation" boundary (repl.h's own header comment: no `scheduler.h`, no `client.h`, no capnp types). No Physical Data Model, API Data Transfer, or Event Schema subsections apply: this feature has no persistent storage, no network wire format, and adds no new wire-level contract — it stays inside `scheduler-core`'s existing "simulation isolation" boundary (repl.h's own header comment: no `scheduler.h`, no `client.h`, no capnp types).
@ -272,6 +409,18 @@ No new logging framework is introduced — the existing `[sim] ...` stdout conve
- A mixed array + non-array listing shows non-array ids individually and compresses only the array ids (Requirement 4.4). - A mixed array + non-array listing shows non-array ids individually and compresses only the array ids (Requirement 4.4).
- A buffer too small to hold the full listing returns a negative value and writes nothing past `bufsz` (Error Handling). - A buffer too small to hold the full listing returns a negative value and writes nothing past `bufsz` (Error Handling).
### Unit Tests (new `test_repl_resource_formatting.c`)
- `repl_is_bytes_valued_resource()` returns true for exactly `mem`, `tmp`, `maxmem`, `maxtmp`, `maxswap`, and false for `swp`, unitless resources (e.g. `r1m`), and an unknown/custom name (Requirement 6.1).
- `repl_format_bytes_human()` adaptively scales across the full B/KB/MB/GB/TB unit range, including exact boundary values (e.g. exactly 1024 bytes renders as `1.00 KB`, not `1024.00 B`) (Requirement 6.2).
- `swp`'s value is converted MB→bytes before formatting, so a raw `swp` value renders on the same adaptive scale as a byte-native resource of equivalent magnitude (Requirement 6.1).
- A whole-number unitless value (e.g. `22.0`) renders with no trailing `.00`; a fractional one (e.g. `0.57`) still renders with its decimal places (Requirement 6.5).
### Integration Tests (extend `test_repl_breakpoints_inspection.c`, `test_repl_snapshot_params.c`)
- `set units raw`/`set units human`/`set units both` each select the corresponding rendering for a subsequent `info worker`/`info resource` call; an unrecognized `set units` value is rejected with the existing `set: unrecognized parameter` error shape (Requirement 6.2, 6.3).
- `info worker`'s resource listing renders as a grouped, aligned table with `used=` shown only for consumable/capacity resources, matching the hand-validated shape against a real captured worker's resource dump (Requirement 6.6).
- `info worker`'s assigned-job listing, given a job array's worth of contiguous indices, renders as a single compressed range via the same helper Requirement 4 already covers (Requirement 4.5).
- `break`'s unrecognized-event-type error message lists the complete, current `BP_KIND_TABLE` token set (Requirement 7.5).
### Integration Tests (extend `test_repl_execution_control.c`, child-process output capture) ### Integration Tests (extend `test_repl_execution_control.c`, child-process output capture)
- `continue` across multiple idle rounds (zero decisions) produces one collapsed range line, not one line per round (Requirement 3.1). - `continue` across multiple idle rounds (zero decisions) produces one collapsed range line, not one line per round (Requirement 3.1).
- `continue` across rounds sharing an identical nonzero pend set produces one collapsed "unchanged" range line — the exact shape hand-validated against the real 108-round replay that motivated this spec (Requirement 3.2). - `continue` across rounds sharing an identical nonzero pend set produces one collapsed "unchanged" range line — the exact shape hand-validated against the real 108-round replay that motivated this spec (Requirement 3.2).
@ -280,6 +429,8 @@ No new logging framework is introduced — the existing `[sim] ...` stdout conve
- Replay completion (EOF) flushes any active collapsed range before the existing "replay complete" banner (Requirement 3.6). - Replay completion (EOF) flushes any active collapsed range before the existing "replay complete" banner (Requirement 3.6).
- `step`-mode output is unchanged versus this feature's pre-implementation baseline — regression check alongside the existing `test_should_pause_fires_on_exactly_the_nth_session`-style fixtures (Requirement 5.1, 5.3). - `step`-mode output is unchanged versus this feature's pre-implementation baseline — regression check alongside the existing `test_should_pause_fires_on_exactly_the_nth_session`-style fixtures (Requirement 5.1, 5.3).
- A job's tracked status changing between rounds is reflected in the next round summary even under a fixture that never emits a synthetic `DISPATCH` decision — exercises the state-derived-pend-set design decision independent of bug-1611's resolution (Requirement 2.4). - A job's tracked status changing between rounds is reflected in the next round summary even under a fixture that never emits a synthetic `DISPATCH` decision — exercises the state-derived-pend-set design decision independent of bug-1611's resolution (Requirement 2.4).
- The REPL prompt is the plain `"(sim) "` before any session begins, then includes the current session count and a human-readable timestamp once at least one session has run, in both `step` and `continue` modes (Requirement 5.5).
- `help`'s output groups commands into the four labeled sections, uses one consistent column width throughout, lists `info config` alongside the other `info` subcommands, and includes the complete `break` event-type list (Requirement 7.1-7.4).
### E2E ### E2E
Not applicable beyond the integration tests above — this feature has no HTTP/API surface; the child-process harness already exercises the real `xce_scheduler` binary end-to-end at the process level. Not applicable beyond the integration tests above — this feature has no HTTP/API surface; the child-process harness already exercises the real `xce_scheduler` binary end-to-end at the process level.

View file

@ -1,11 +1,11 @@
# Requirements Document # Requirements Document
## Introduction ## Introduction
xce_scheduler's `--interactive` simulation REPL (shipped by the `scheduler-core` spec) lets an operator step or continue through a recorded replay while inspecting scheduler state. Under `continue`, the REPL currently prints the same volume of output as single-stepping every round — a real 108-round replay produced roughly 2,700 lines, most of it either routine per-event chatter that carries no new information under `continue`, or an unchanged pending-job decision repeated identically round after round. This feature reorganizes REPL output during `continue` execution so an operator can track a long replay's progress without wading through repetitive, low-information lines, while leaving `step` mode and every other REPL command unchanged. xce_scheduler's `--interactive` simulation REPL (shipped by the `scheduler-core` spec) lets an operator step or continue through a recorded replay while inspecting scheduler state. Under `continue`, the REPL currently prints the same volume of output as single-stepping every round — a real 108-round replay produced roughly 2,700 lines, most of it either routine per-event chatter that carries no new information under `continue`, or an unchanged pending-job decision repeated identically round after round. This feature reorganizes REPL output during `continue` execution so an operator can track a long replay's progress without wading through repetitive, low-information lines. It also extends a small number of specific, explicitly-scoped improvements to other parts of the REPL surfaced during this effort — the command prompt, `info`'s job-identifier and resource-value listings, and `help`/`break`'s discoverability — while leaving `step` mode's per-event and per-decision detail, and every other aspect of the REPL's existing commands, unchanged.
## Boundary Context ## Boundary Context
- **In scope**: console output shown by the `--interactive` simulation REPL during `continue` execution — which events are echoed, how scheduling-decision outcomes are summarized per round, how repetitive rounds are collapsed, and how multi-job identifier lists are displayed. - **In scope**: console output shown by the `--interactive` simulation REPL during `continue` execution — which events are echoed, how scheduling-decision outcomes are summarized per round, how repetitive rounds are collapsed, and how multi-job identifier lists are displayed; the REPL prompt's display of current session/timestamp context, applicable in both `step` and `continue` modes; job-identifier range compression (Requirement 4) applied to the `info` command's job-listing output (for example `info worker`'s assigned-job list); human-readable resource value formatting, table layout, and the new `set units` display-mode option (Requirement 6) applied to the `info` command's resource listings; and the organization/completeness of `help`'s command listing and `break`'s event-type discoverability (Requirement 7).
- **Out of scope**: any new REPL command or newly inspectable data (for example limit usage or pend-reason detail — tracked separately under `scheduler-sim-diagnostics`); any change to scheduling/allocation behavior or to the deterministic outcome of a replay; any change to `step` mode's existing output; non-interactive (headless, no `-i`) scheduler output. - **Out of scope**: any new REPL command or newly inspectable data (for example limit usage or pend-reason detail — tracked separately under `scheduler-sim-diagnostics`); any change to scheduling/allocation behavior or to the deterministic outcome of a replay; any change to `step` mode's existing output, other than the prompt string itself; non-interactive (headless, no `-i`) scheduler output.
- **Adjacent expectations**: this feature extends the existing REPL shipped by `scheduler-core` (implementation-complete) without changing its command surface. `scheduler-sim-diagnostics` (currently a discovery brief, not yet a formal spec) is expected to separately add pend-reason and limit-usage inspection; this feature's round summaries should remain compatible with, and not duplicate, that future work. - **Adjacent expectations**: this feature extends the existing REPL shipped by `scheduler-core` (implementation-complete) without changing its command surface. `scheduler-sim-diagnostics` (currently a discovery brief, not yet a formal spec) is expected to separately add pend-reason and limit-usage inspection; this feature's round summaries should remain compatible with, and not duplicate, that future work.
## Requirements ## Requirements
@ -14,9 +14,9 @@ xce_scheduler's `--interactive` simulation REPL (shipped by the `scheduler-core`
**Objective:** As an operator running a simulation replay, I want `continue` to suppress routine per-event chatter while still alerting me to major state changes, so that I can watch a long replay without being flooded by lines carrying no new information. **Objective:** As an operator running a simulation replay, I want `continue` to suppress routine per-event chatter while still alerting me to major state changes, so that I can watch a long replay without being flooded by lines carrying no new information.
#### Acceptance Criteria #### Acceptance Criteria
1. While the REPL is executing in continue mode, when a routine per-event notification (a job progress update, a job resource-usage update, or a resource value update) occurs, the REPL shall not print an individual line for that event. 1. While the REPL is executing in continue mode, when a routine per-event notification (a job status change, a job progress update, a job resource-usage update, a queue update, or a partial/delta resource-value update) occurs, the REPL shall not print an individual line for that event.
2. While the REPL is executing in step mode, when any event occurs, the REPL shall print an individual line for that event. 2. While the REPL is executing in step mode, when any event occurs, the REPL shall print an individual line for that event.
3. When a structural change occurs (new jobs submitted, new workers added, new resources added, or configuration pushed), the REPL shall print a line describing that change regardless of execution mode. 3. When a structural change occurs (new jobs submitted, new workers added, new resources added, a full resource-value snapshot arriving, or configuration pushed), the REPL shall print a line describing that change regardless of execution mode.
4. When an event matches a defined breakpoint, the REPL shall interrupt continue-mode execution and enter the interactive command loop, regardless of whether the event is routine or structural. 4. When an event matches a defined breakpoint, the REPL shall interrupt continue-mode execution and enter the interactive command loop, regardless of whether the event is routine or structural.
### Requirement 2: Per-Round Decision Summary ### Requirement 2: Per-Round Decision Summary
@ -47,13 +47,36 @@ xce_scheduler's `--interactive` simulation REPL (shipped by the `scheduler-core`
2. When job identifiers from the same job array submission have non-contiguous indices, the REPL shall display each contiguous sub-range separately within the same listing. 2. When job identifiers from the same job array submission have non-contiguous indices, the REPL shall display each contiguous sub-range separately within the same listing.
3. When a listing contains job identifiers from more than one job array submission, the REPL shall group and compress each job array submission's identifiers independently. 3. When a listing contains job identifiers from more than one job array submission, the REPL shall group and compress each job array submission's identifiers independently.
4. When a listing mixes job-array and non-array job identifiers, the REPL shall display the non-array job identifiers individually while compressing the job-array identifiers as described above. 4. When a listing mixes job-array and non-array job identifiers, the REPL shall display the non-array job identifiers individually while compressing the job-array identifiers as described above.
5. The REPL shall apply job identifier range compression consistently everywhere it displays multiple job identifiers together, including job-arrival notifications and round decision summaries. 5. The REPL shall apply job identifier range compression consistently everywhere it displays multiple job identifiers together, including job-arrival notifications, round decision summaries, and the `info` command's job-identifier listings (for example `info worker`'s assigned-job list).
### Requirement 5: No Change to Step-Mode Detail or Existing Commands ### Requirement 5: Preservation of Existing REPL Behavior Outside This Feature's Explicit Changes
**Objective:** As an operator relying on today's `step` behavior and `info`/`break`/`delete`/`set`/`snapshot` commands, I want this feature to leave them unchanged, so that existing debugging workflows keep working exactly as before. **Objective:** As an operator relying on today's `step` behavior and `info`/`break`/`delete`/`set`/`snapshot`/`help` commands, I want everything this feature does not explicitly call out as changing (Requirements 4, 6, and 7, plus this requirement's own AC 5) to keep working exactly as before, so that existing debugging workflows aren't disrupted by scope creep.
#### Acceptance Criteria #### Acceptance Criteria
1. The REPL shall preserve existing `step` command output exactly as before this feature, with no reduction in per-event or per-decision detail. 1. The REPL shall preserve existing `step` command output exactly as before this feature, with no reduction in per-event or per-decision detail.
2. The REPL shall preserve existing `info`, `break`, `delete`, `set`, and `snapshot` command behavior and output format unchanged. 2. The REPL shall preserve existing `info`, `break`, `delete`, `set`, `snapshot`, and `help` command behavior and output format unchanged, except where Requirement 4, 6, or 7 explicitly specifies a change. (This AC is intentionally a cross-reference, not a restated list, so a future requirement's own scoping ACs remain the single source of truth for what it changes.)
3. The REPL shall introduce no new command as part of this feature. 3. The REPL shall introduce no new top-level command as part of this feature; `set units` is a new option of the existing `set` command, following the same `set <key> <value>` form as today's `set speed`/`set output`/`set verify`.
4. The REPL shall not alter the scheduling decisions or final simulation state produced by a replay — only the console output describing them. 4. The REPL shall not alter the scheduling decisions or final simulation state produced by a replay — only the console output describing them.
5. When the REPL displays its command prompt, the REPL shall include the current session identifier and timestamp, without altering any other step-mode or continue-mode output.
### Requirement 6: Human-Readable Resource Value Formatting
**Objective:** As an operator reading `info worker`/`info resource` output, I want byte-denominated resource values shown in a readable unit and the listing laid out as a scannable table, with control over how much raw-vs-human detail I see, so I don't have to mentally parse 13-digit raw byte counts or hunt for one resource among 20 unstructured lines.
#### Acceptance Criteria
1. When the REPL displays a resource whose canonical wire unit is bytes (`mem`, `tmp`, `maxmem`, `maxtmp`, `maxswap`) or the `swp` resource (whose canonical wire unit is megabytes), the REPL shall render its value using the operator's selected units display mode.
2. The REPL shall support a `set units raw|human|both` option: `raw` shows only the numeric wire value, `human` shows only an adaptively-scaled unit (B/KB/MB/GB/TB/PB), and `both` shows the raw value with the human-readable form alongside.
3. Absent an explicit `set units` command, the REPL's units display mode shall default to `both`.
4. The REPL shall not alter the underlying stored/wire value of any resource, nor the deterministic outcome of a replay — only its console display.
5. The REPL shall display numeric resources with no canonical unit (for example load averages, factors, and counts) without a unit suffix, and without a trailing `.00` when the value is a whole number.
6. The REPL shall display `info worker`'s and `info resource`'s resource listings as an aligned table, grouping resources by category (consumable/capacity, load metrics, static hardware attributes) where applicable to that listing, rather than one flat list.
### Requirement 7: Discoverable Help and Breakpoint Event Types
**Objective:** As an operator learning or re-learning the REPL's command surface, I want `help`'s listing organized and complete, and every valid `break` event type discoverable without reading source, so I can find and use a command correctly on the first try instead of by trial-and-error.
#### Acceptance Criteria
1. The REPL's `help` output shall group commands into labeled sections by concern (execution control, breakpoints, state inspection, snapshot and parameters) instead of one flat list.
2. Within each section, the REPL shall align every command's description to a single column position computed consistently, rather than independently hand-padded per line.
3. The REPL's `help` output shall list `info config` together with the other `info` subcommands in the state-inspection section.
4. The REPL's `help` output shall enumerate the complete set of valid `<EVENT_TYPE>` values accepted by `break`.
5. When `break` is given an event type that matches none of its valid values, the REPL's error message shall list the complete set of valid values.
6. The REPL shall not alter which commands exist, their argument parsing, or any other command's output — only the organization of `help`'s listing and the completeness of `break`'s event-type discoverability.

View file

@ -1,7 +1,7 @@
{ {
"feature_name": "scheduler-sim-repl-verbosity", "feature_name": "scheduler-sim-repl-verbosity",
"created_at": "2026-08-21T06:50:37Z", "created_at": "2026-08-21T06:50:37Z",
"updated_at": "2026-08-21T07:10:00Z", "updated_at": "2026-09-02T07:15:00Z",
"language": "en", "language": "en",
"phase": "tasks-generated", "phase": "tasks-generated",
"approvals": { "approvals": {