feat(scheduler-sim-repl-verbosity): task 9.2 - discoverable help and break event types

Adds repl_bp_kind_names(char* buf, size_t bufsz) (repl_break.c),
comma-joining BP_KIND_TABLE's tokens in table order into a caller
buffer. repl_print_help() (repl.c) is rewritten into four labeled
sections (Execution Control, Breakpoints, State Inspection, Snapshot &
Parameters) with a single shared "  %-38s%s\n" column format, info
config moved into State Inspection next to its siblings, set units
added to Snapshot & Parameters, and the break line's description now
built from repl_bp_kind_names() so it enumerates the complete event
type set. repl_cmd_break()'s unrecognized-event-type error calls the
same accessor, so help and the error message can never disagree with
each other or with BP_KIND_TABLE (Requirements 7.1-7.6). No command's
existence, argument parsing, or other output changed.

repl_break.c grew from 905 to 949 lines (18.6% over the 800-line cap,
up from task 3.2's already-accepted 13%-over residual). Review
empirically tested extracting the BP_KIND_TABLE lookup-table domain
into a new repl_bp_kind.c: it built and passed, but only reached 838
lines (still 4.75% over cap) while requiring 22 white-box test files'
#include lines to be updated - the same disproportionate-churn,
doesn't-achieve-compliance outcome already accepted at tasks 6.2/8.2.
Reverted; 949 lines accepted in place.

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 20:30:45 +00:00
parent bd77eea0a8
commit bd97397373
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
5 changed files with 137 additions and 24 deletions

View file

@ -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 `<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). - `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. - 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** **Dependencies**
- Inbound: `repl_print_help()` (repl.c) (P0), `repl_cmd_break()`'s error path (repl_break.c) (P0) - 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) - Outbound: `BP_KIND_TABLE` (repl_break.c, existing) (P0)

View file

@ -104,7 +104,7 @@
- _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6_ - _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6_
- _Boundary: Help & Breakpoint Discoverability_ - _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 - 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 - 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_ - _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6_

View file

@ -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), * with one-line descriptions." Covers execution control (task 12.1),
* breakpoints and state inspection (task 12.2), and snapshot capture plus * breakpoints and state inspection (task 12.2), and snapshot capture plus
* simulation parameters (task 12.3) -- every AC 22 command is now listed. * 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 <EVENT_TYPE> [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 `<EVENT_TYPE>` 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 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, "[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, "\nExecution Control:\n");
fprintf(stdout, " quit Exit the scheduler immediately.\n"); fprintf(stdout, FIELD_FMT, "step [N]",
fprintf(stdout, " help Print this help listing.\n"); "Advance N sessions (default 1), pause after.");
fprintf(stdout, " break <EVENT_TYPE> [key=value ...] Set a breakpoint.\n"); fprintf(stdout, FIELD_FMT, "continue",
fprintf(stdout, " info break List breakpoints.\n"); "Run until next breakpoint hit or EOF.");
fprintf(stdout, " delete <id>|all Delete breakpoint(s).\n"); fprintf(stdout, FIELD_FMT, "quit", "Exit the scheduler immediately.");
fprintf(stdout, " info session Simulation position.\n"); fprintf(stdout, FIELD_FMT, "help", "Print this help listing.");
fprintf(stdout, " info job <jobid> Dump one job.\n");
fprintf(stdout, " info jobs List all job IDs.\n"); fprintf(stdout, "\nBreakpoints:\n");
fprintf(stdout, " info queue <name>|all Dump queue(s).\n"); fprintf(stdout, FIELD_FMT, "break <EVENT_TYPE> [key=value ...]",
fprintf(stdout, " info worker <name>|all Dump worker(s).\n"); break_desc);
fprintf(stdout, " info resource <name>|all Dump resource(s).\n"); fprintf(stdout, FIELD_FMT, "info break", "List breakpoints.");
fprintf(stdout, " info summary Quick overview.\n"); fprintf(stdout, FIELD_FMT, "delete <id>|all", "Delete breakpoint(s).");
fprintf(stdout, " snapshot [FILE] Write a standalone "
"snapshot.\n"); fprintf(stdout, "\nState Inspection:\n");
fprintf(stdout, " set speed <N> Set simulation speed.\n"); fprintf(stdout, FIELD_FMT, "info session", "Simulation position.");
fprintf(stdout, " set output <FILE>|off Start/stop writing " fprintf(stdout, FIELD_FMT, "info job <jobid>", "Dump one job.");
"decisions.\n"); fprintf(stdout, FIELD_FMT, "info jobs", "List all job IDs.");
fprintf(stdout, " set verify on|off Toggle decision " fprintf(stdout, FIELD_FMT, "info queue <name>|all", "Dump queue(s).");
"verification.\n"); fprintf(stdout, FIELD_FMT, "info worker <name>|all", "Dump worker(s).");
fprintf(stdout, " info config Show sim parameters.\n"); fprintf(stdout, FIELD_FMT, "info resource <name>|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 <N>", "Set simulation speed.");
fprintf(stdout, FIELD_FMT, "set output <FILE>|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).");
} }
/* /*

View file

@ -84,6 +84,46 @@ static bool repl_bp_kind_from_token(const char* token, xce_repl_bp_kind_t* out)
return false; 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 /* 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_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 * 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; return false;
} }
if (!repl_bp_kind_from_token(tokens[1], &kind)) { 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; return false;
} }

View file

@ -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_delete(xce_sched_sim_driver_t* sim, const char* line);
extern bool repl_cmd_info(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 <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() (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 /* 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 * 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 * "returns false, re-prompt" contract every other repl_cmd_* above already