diff --git a/.kiro/specs/scheduler-sim-repl-verbosity/design.md b/.kiro/specs/scheduler-sim-repl-verbosity/design.md index a3c70313..664cb85f 100644 --- a/.kiro/specs/scheduler-sim-repl-verbosity/design.md +++ b/.kiro/specs/scheduler-sim-repl-verbosity/design.md @@ -375,6 +375,8 @@ void repl_format_bytes_human(double bytes, char* buf, size_t bufsz); - `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 `` 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. +**Accepted residual (post-review, task 9.2)**: adding `repl_bp_kind_names()` and wiring it into `repl_cmd_break()`'s error message pushed `repl_break.c` from 905 to 949 lines — up from task 3.2's already-accepted 13%-over-cap residual to 18.6% over the 800-line cap. Review empirically tested extracting `BP_KIND_TABLE`/`repl_bp_kind_from_token()`/`repl_bp_kind_names()`/`repl_bp_kind_for_core_event()` (a self-contained lookup-table domain) into a new `repl_bp_kind.c`: it built and passed cleanly but only reduced `repl_break.c` to 838 lines — still 4.75% over cap — while requiring 22 white-box test files' `#include "../src/repl_break.c"` lines to gain a matching new include. Same "doesn't achieve compliance, disproportionate churn" outcome already accepted at tasks 6.2 and 8.2; the experiment was reverted and 949 lines is accepted in place. `repl.c`'s task 9.2 growth (587 → 634 lines) remains comfortably under cap and needs no note. + **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) diff --git a/.kiro/specs/scheduler-sim-repl-verbosity/tasks.md b/.kiro/specs/scheduler-sim-repl-verbosity/tasks.md index 619de266..155197d7 100644 --- a/.kiro/specs/scheduler-sim-repl-verbosity/tasks.md +++ b/.kiro/specs/scheduler-sim-repl-verbosity/tasks.md @@ -104,7 +104,7 @@ - _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6_ - _Boundary: Help & Breakpoint Discoverability_ -- [ ] 9.2 (P) Implement the shared event-type accessor, the reorganized `help`, and `break`'s enriched error message +- [x] 9.2 (P) Implement the shared event-type accessor, the reorganized `help`, and `break`'s enriched error message - Add one shared accessor rendering `BP_KIND_TABLE`'s complete token set; rewrite `repl_print_help()` into the four labeled, consistently-aligned sections with `info config` moved next to its siblings, `set units` listed alongside `set speed`/`set output`/`set verify`, and the accessor's output appended to the `break` line; call the same accessor from `repl_cmd_break()`'s unrecognized-event-type error - Observable: all tests from 9.1 pass; `help` and `break`'s error message can never disagree with each other or with `BP_KIND_TABLE`, since both read the same accessor - _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6_ diff --git a/src/scheduler/src/repl.c b/src/scheduler/src/repl.c index d57c1906..e6c05087 100644 --- a/src/scheduler/src/repl.c +++ b/src/scheduler/src/repl.c @@ -244,32 +244,79 @@ static void repl_print_banner(const xce_sched_sim_driver_t* sim) * with one-line descriptions." Covers execution control (task 12.1), * breakpoints and state inspection (task 12.2), and snapshot capture plus * simulation parameters (task 12.3) -- every AC 22 command is now listed. + * + * scheduler-sim-repl-verbosity spec, task 9.2, design.md's "Help & + * Breakpoint Discoverability" component (Req 7.1-7.4): rewritten from one + * flat, independently hand-padded list into four labeled sections -- + * Execution Control, Breakpoints, State Inspection (now including `info + * config`, moved here next to its `info` siblings per Req 7.3), and + * Snapshot & Parameters (now including `set units`, alongside `set speed`/ + * `set output`/`set verify`) -- each line rendered through the SAME + * `FIELD_FMT` fixed-field-width format, so a future command addition can't + * silently break alignment the way `info config`'s old hand-counted append + * did (Req 7.2). `FIELD_FMT`'s "%-38s" width is sized to the longest + * command/argument field below ("break [key=value ...]", 34 + * chars) plus a minimum separating gap. + * + * The `break` line's description is built dynamically via + * repl_bp_kind_names() (repl_break.c, over BP_KIND_TABLE) so it always + * enumerates the complete, current set of valid `` values (Req + * 7.4) -- the exact same accessor repl_cmd_break()'s own unrecognized-event- + * type error calls, so the two can never disagree with each other or with + * BP_KIND_TABLE itself. + * + * Req 7.6: no command's existence, argument parsing, or any other output + * changes here -- only this listing's organization/alignment and the + * `break` line's added event-type enumeration. */ static void repl_print_help(void) { + static const char* const FIELD_FMT = " %-38s%s\n"; + char kind_names[256]; + char break_desc[320]; + + repl_bp_kind_names(kind_names, sizeof(kind_names)); + snprintf(break_desc, sizeof(break_desc), + "Set a breakpoint. Valid event types: %s.", kind_names); + fprintf(stdout, "[sim] available commands:\n"); - fprintf(stdout, " step [N] Advance N sessions (default 1), pause after.\n"); - fprintf(stdout, " continue Run until next breakpoint hit or EOF.\n"); - fprintf(stdout, " quit Exit the scheduler immediately.\n"); - fprintf(stdout, " help Print this help listing.\n"); - fprintf(stdout, " break [key=value ...] Set a breakpoint.\n"); - fprintf(stdout, " info break List breakpoints.\n"); - fprintf(stdout, " delete |all Delete breakpoint(s).\n"); - fprintf(stdout, " info session Simulation position.\n"); - fprintf(stdout, " info job Dump one job.\n"); - fprintf(stdout, " info jobs List all job IDs.\n"); - fprintf(stdout, " info queue |all Dump queue(s).\n"); - fprintf(stdout, " info worker |all Dump worker(s).\n"); - fprintf(stdout, " info resource |all Dump resource(s).\n"); - fprintf(stdout, " info summary Quick overview.\n"); - fprintf(stdout, " snapshot [FILE] Write a standalone " - "snapshot.\n"); - fprintf(stdout, " set speed Set simulation speed.\n"); - fprintf(stdout, " set output |off Start/stop writing " - "decisions.\n"); - fprintf(stdout, " set verify on|off Toggle decision " - "verification.\n"); - fprintf(stdout, " info config Show sim parameters.\n"); + + fprintf(stdout, "\nExecution Control:\n"); + fprintf(stdout, FIELD_FMT, "step [N]", + "Advance N sessions (default 1), pause after."); + fprintf(stdout, FIELD_FMT, "continue", + "Run until next breakpoint hit or EOF."); + fprintf(stdout, FIELD_FMT, "quit", "Exit the scheduler immediately."); + fprintf(stdout, FIELD_FMT, "help", "Print this help listing."); + + fprintf(stdout, "\nBreakpoints:\n"); + fprintf(stdout, FIELD_FMT, "break [key=value ...]", + break_desc); + fprintf(stdout, FIELD_FMT, "info break", "List breakpoints."); + fprintf(stdout, FIELD_FMT, "delete |all", "Delete breakpoint(s)."); + + fprintf(stdout, "\nState Inspection:\n"); + fprintf(stdout, FIELD_FMT, "info session", "Simulation position."); + fprintf(stdout, FIELD_FMT, "info job ", "Dump one job."); + fprintf(stdout, FIELD_FMT, "info jobs", "List all job IDs."); + fprintf(stdout, FIELD_FMT, "info queue |all", "Dump queue(s)."); + fprintf(stdout, FIELD_FMT, "info worker |all", "Dump worker(s)."); + fprintf(stdout, FIELD_FMT, "info resource |all", + "Dump resource(s)."); + fprintf(stdout, FIELD_FMT, "info summary", "Quick overview."); + fprintf(stdout, FIELD_FMT, "info config", "Show sim parameters."); + + fprintf(stdout, "\nSnapshot & Parameters:\n"); + fprintf(stdout, FIELD_FMT, "snapshot [FILE]", + "Write a standalone snapshot."); + fprintf(stdout, FIELD_FMT, "set speed ", "Set simulation speed."); + fprintf(stdout, FIELD_FMT, "set output |off", + "Start/stop writing decisions."); + fprintf(stdout, FIELD_FMT, "set verify on|off", + "Toggle decision verification."); + fprintf(stdout, FIELD_FMT, "set units raw|human|both", + "Show resource values raw, human-scaled, or both (default: " + "both)."); } /* diff --git a/src/scheduler/src/repl_break.c b/src/scheduler/src/repl_break.c index 0bfeeb59..42c9c019 100644 --- a/src/scheduler/src/repl_break.c +++ b/src/scheduler/src/repl_break.c @@ -84,6 +84,46 @@ static bool repl_bp_kind_from_token(const char* token, xce_repl_bp_kind_t* out) return false; } +/* + * repl_bp_kind_names - scheduler-sim-repl-verbosity spec, task 9.2, + * design.md's "Help & Breakpoint Discoverability" component (Req 7.4/7.5, + * Service Interface). Renders BP_KIND_TABLE's complete token set as one + * comma-joined, NUL-terminated string into `buf` (bufsz-bounded) -- e.g. + * "CONFIG_PUSH, JOB_PUSH, ..., DECISION". Used by both repl_print_help() + * (repl.c) and repl_cmd_break()'s unrecognized-event-type error below, so + * the two can never disagree with each other or with BP_KIND_TABLE itself + * (repl_internal.h's own doc comment on this declaration). + * + * 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. A `buf`/`bufsz` too small to hold the full list truncates via + * snprintf()'s own bounded-write semantics rather than overflowing -- this + * is a discoverability aid, not a wire/persisted value, so silent + * truncation on a pathologically small buffer is an acceptable degrade, not + * a correctness bug. `buf == NULL`/`bufsz == 0` is a no-op. + */ +void repl_bp_kind_names(char* buf, size_t bufsz) +{ + size_t used = 0; + size_t i; + + if ((buf == NULL) || (bufsz == 0)) { + return; + } + + buf[0] = '\0'; + + for (i = 0; i < NUM_BP_KINDS; i++) { + int n = snprintf(buf + used, bufsz - used, "%s%s", + (i == 0) ? "" : ", ", BP_KIND_TABLE[i].token); + + if ((n < 0) || ((size_t)n >= (bufsz - used))) { + break; + } + used += (size_t)n; + } +} + /* repl_bp_kind_for_core_event - the reverse of BP_KIND_TABLE, keyed by * xce_core_event_type_t (core.h) instead of a user-typed token. Used by * xce_repl_on_event() (below) to find which breakpoints are even @@ -497,7 +537,11 @@ bool repl_cmd_break(xce_sched_sim_driver_t* sim, const char* line) return false; } if (!repl_bp_kind_from_token(tokens[1], &kind)) { - fprintf(stdout, "[sim] break: unrecognized event type '%s'\n", tokens[1]); + char kind_names[256]; + + repl_bp_kind_names(kind_names, sizeof(kind_names)); + fprintf(stdout, "[sim] break: unrecognized event type '%s' -- valid " + "event types: %s\n", tokens[1], kind_names); return false; } diff --git a/src/scheduler/src/repl_internal.h b/src/scheduler/src/repl_internal.h index f8894e9b..1b32d826 100644 --- a/src/scheduler/src/repl_internal.h +++ b/src/scheduler/src/repl_internal.h @@ -328,6 +328,26 @@ extern bool repl_cmd_break(xce_sched_sim_driver_t* sim, const char* line); extern bool repl_cmd_delete(xce_sched_sim_driver_t* sim, const char* line); extern bool repl_cmd_info(xce_sched_sim_driver_t* sim, const char* line); +/* + * repl_bp_kind_names (repl_break.c, scheduler-sim-repl-verbosity spec, task + * 9.2, design.md's "Help & Breakpoint Discoverability" component, Req 7.4/ + * 7.5) - Renders BP_KIND_TABLE's complete set of valid break + * 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() (repl.c) and repl_cmd_break()'s + * unrecognized-event-type error (repl_break.c) so the two can never disagree + * with each other or with BP_KIND_TABLE. + * + * 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 or + * removing a table entry changes this function's output with no other code + * change required. + */ +extern void repl_bp_kind_names(char* buf, size_t bufsz); + /* repl_cmd_snapshot/repl_cmd_set (repl_params.c, task 12.3) -- the two * task-12.3 command handlers repl.c's repl_dispatch() hands off to. Same * "returns false, re-prompt" contract every other repl_cmd_* above already