Repository navigation
T27 Model Control: MODEL panel (epic #13172) - #13173
Conversation
Adds the MODEL panel to the T27 OS right-hand strip beside KEYS, DOCTOR and PROFILE, answering the four questions: what is running, why this model, whose credentials, how much spent (known/estimated/reserved/ unknown). Unknown cost is never shown as zero. Specs: - model_trace.t27: per-attempt trace record, classification, redaction, versioned price table, golden incident line (11 tests) - model_budget.t27: gate/reservation/retry/fallback/period logic (10 tests) - model_control_panel.t27: panel rows, totals, four answers, geometry (6 tests) - model_log.t27: parses deployed ladder.log into trace rows, unknown fields marked unknown not guessed (7 tests) - model_trace_main.t27: recorder that writes ~/.t27os/model-trace.tsv from the ladder log tail (1 test) UI wiring: - statusbar.t27: MODEL link between KEYS and DOCTOR at the right end - glass_window.t27: mp flag, draw_model_panel, click handling, panel exclusion, all 101 glass_window tests pass Sealed in .trinity/seals/ (owner rule DSH_MCP_VISIBLE_EXECUTION separately in gHashTag/t27). Closes #13172
Co-authored-by: Dmitrii Vasilev <gHashTag@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 5 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9e747f2. Configure here.
| w = put_cells(rows[at * TR_CELLS .. at * TR_CELLS + TR_CELLS], out[w..]); | ||
| w = put_bytes(out, w, "\n"); | ||
| i = i + 1; | ||
| } |
There was a problem hiding this comment.
Trace file rows clobber header
High Severity
put_cells writes from the start of the slice it is given and returns that relative length. Assigning that return value back to w then passing it to put_bytes on the full out buffer overwrites the header and earlier rows. The MODEL panel's model-trace.tsv comes out truncated and corrupt, so the panel cannot show the recorded attempts.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 9e747f2. Configure here.
| } | ||
|
|
||
| pub fn main() -> void { | ||
| _ = sys_write(2, "A\n", 2); |
There was a problem hiding this comment.
Debug breadcrumbs left in recorder
Medium Severity
main writes A through E to stderr around each stage of the recorder. The file header says a successful run prints one summary line, so these leftover breadcrumbs leak into every normal invocation.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 9e747f2. Configure here.
| _ = sys_write(2, "C\n", 2); | ||
| var rows : [CAP * TR_CELLS]u64 = undefined; | ||
| var t : [ML_T_CELLS]u64 = undefined; | ||
| scan_log(ML_BUF[0..BUF_BYTES], n, rows[0..CAP * TR_CELLS], CAP, t[0..ML_T_CELLS]); |
There was a problem hiding this comment.
Recorder totals cover only tail
High Severity
BUF_BYTES is 64 KiB and main seeks to the last 64 KiB of ladder.log before a single scan_log. Header comments promise a 16 MB tail, and scan_log/acc_init say totals cover the whole log via 64 KiB chunks. On the documented 13 MB incident log the panel's total/unfunded/wasted_ms only reflect the newest slice, which understates the damage the epic exists to show.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 9e747f2. Configure here.
| qn = put_bytes(line[0..128], qn, " -> "); | ||
| qn = put_bytes(line[0..128], qn, tp[0..tn]); | ||
| qn = put_bytes(line[0..128], qn, "\n"); | ||
| _ = sys_write(1, line[0..128], @as(u64, @intCast(qn))); |
There was a problem hiding this comment.
Success line overflows path buffer
Medium Severity
The success line is assembled in a 128-byte line buffer, then put_bytes appends tp[0..tn]. T27_MODEL_TRACE and the default HOME path are allowed up to a few hundred bytes, and put_bytes does not clip. A long path traps or corrupts after the trace file has already been written.
Reviewed by Cursor Bugbot for commit 9e747f2. Configure here.
| } | ||
| pub fn on_model(x : f64, y : f64, sw : f64, sh : f64) -> bool { | ||
| return in_bar(y, sh) and x >= model_left(sw) and x < model_left(sw) + SB_MODEL_W; | ||
| } |
There was a problem hiding this comment.
MODEL slot shifts KEYS with no draw
Medium Severity
right_w and keys_left now reserve a 48 px MODEL slot between KEYS and DOCTOR, and IT_COUNT is 12. glass_window still draws only KEYS and DOCTOR, still sizes footer slots/lens/widths for 11 items, and never calls on_model or PG_MODEL. KEYS and OPEN SOURCE shift left into a dead gap, and enabling IT_MODEL in present would index past those arrays.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 9e747f2. Configure here.
PR DashboardGenerated at: 2026-11-09 22:00:06 UTC
Summary
Seal Status
|


Closes #13172
Note
Low Risk
Spec-only additions with embedded tests; no production ladder or window wiring in this diff beyond statusbar constants.
Overview
Adds T27 specs for epic #13172 so the OS can observe model routing, spend, and the 402→503 retry incident without reading secrets or faking zero cost.
model_trace.t27defines per-attempt records: separate upstream vs gateway status, body-vs-envelope ambiguity, credential naming (no key material), known/estimated/unknown cost, and rules that UNFUNDED must not retry on the same account.model_log.t27parses existing[ladder]log lines into trace cells (including 402 upstream + 503 gateway), scans logs for totals, and serializes rows for the panel.model_budget.t27specifies send gating (reservations, limits, attempt/time caps, paid fallback policy) and post-refusal retry behavior aligned with trace classes.model_control_panel.t27turns trace rows into the four owner questions (running, why, whose, spend), panel geometry, and row/total formatting.model_trace_main.t27is a small recorder: tail-readladder.log, keep the last 64 requests, write~/.t27os/model-trace.tsvfor the window.statusbar.t27adds a MODEL footer link (PG_MODEL) between KEYS and OPEN SOURCE T27, with layout/click tests updated.Reviewed by Cursor Bugbot for commit 9e747f2. Bugbot is set up for automated code reviews on this repo. Configure here.