Repository navigation
feat(context): one window-style breakdown with Kiro Crew first - #24038
chenmingwei23 wants to merge 2 commits into
Conversation
Design Review (Opus 5.5) — ✅ PASSDesign-level review of Design-Verdict: PASS No design-level blocker: the fold state version is bumped so saved checkpoints get re-folded, the trace keeps the field names its untouched reader uses, and 16 rendered screenshots cover the surface. Notes
[DESIGN-REVIEWED] 496f15d Description read[DESCRIPTION-READ] 1961ceeab2057d8d5b775c1e725061ecbce2c222fda4f5c319fcb132af28e296 That sha256 names everything this verdict read: the PR description, plus the 1 evidence file(s) the workflow collected from it and handed this review. It covers that evidence because the media strip replaces every attachment URL with the same placeholder, so an edit swapping one attachment for another would leave the description's captured text identical while what this review judged changed. Recompute it with |
First Principles Review (Opus 5.5) — ✅ PASSPremise-level review of First-Principles-Verdict: PASS Nothing blocks. Two riders that the visible description does not mention leave surface behind that can be deleted: a dead unknown-category branch and a re-derived set of Session Breakdown totals. Notes
What this change shipsInventory (10 items) — 8 justifiedIntent: let a user see at a glance what filled a session's context at its newest turn, with Kiro Crew's share in one place, while keeping the fold that holds it a fixed size. This is an ADDITION (a panel redesign plus a fold restructure).
[FIRST-PRINCIPLES-REVIEWED] 496f15d Description read[DESCRIPTION-READ] 8863f2df6937826b8f1713677f56c4c6c8086588f5d6ca4e7bf988acee9c81b4 That sha256 names the PR description this verdict read. Recompute it with |
UX Review (Opus 5.5) — ✅ PASSUX-level review of UX-Verdict: PASS No primary control was misread, and the screenshots cover every new state: past pick, start-row pick, the evicted-pick note, the tips, the error and narrow widths. Notes
[UX-REVIEWED] 496f15d Description read[DESCRIPTION-READ] b8c6c8ced4c69ab2b2b38248f51875186a280e4ce7c3b85c9f2d56b77d9936f7 That sha256 names everything this verdict read: the PR description, plus the 19 evidence file(s) the workflow collected from it and handed this review. It covers that evidence because the media strip replaces every attachment URL with the same placeholder, so an edit swapping one attachment for another would leave the description's captured text identical while what this review judged changed. Recompute it with |
GPT 6.1 Review — ✅ no blocking findingsGPT 6.1 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
Opus 5.5 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
4dc6d9b to
0f4272a
Compare
0f4272a to
61baa40
Compare
61baa40 to
979b978
Compare
979b978 to
89131f9
Compare
02cd927 to
553e3e6
Compare
553e3e6 to
c4c73c3
Compare
c4c73c3 to
7f4ecbf
Compare
7f4ecbf to
02e1b45
Compare
02e1b45 to
db9c0c4
Compare
db9c0c4 to
aa3cc85
Compare
|
Author confirmation for the First Principles "unverified premise" item (
|
Follow-up to #23648. The Context panel now shows the newest turn as one list and one bar instead of a separate "measured" section. Panel - Row 1 is always Kiro Crew (rules, memory, skills, other), open by default; Your messages is row 2 on every turn. - Then the engine's categories by size: Messages (history less Kiro Crew's blocks), built-in tool definitions, tool calls and results (Calls / Results), MCP tools, steering and agent resources, Kiro instructions, agents / skills / powers lists with counts, workspace, memory, attached files, other. Zero rows are hidden; rows add up to the request's characters. - One stacked bar (Kiro Crew first in its own color family) and a thin window bar ("4% of the 1M-token window"). Images and files get their own line outside the total. - Turns the engine does not split (kiro-cli and other harnesses) are shown in tokens so the rows add up to the harness total: Kiro Crew and Your messages are estimated at the composer's characters-per-token ratio and marked "~", the remainder is "Rest of the context", with an info tip naming the session's harness and the Settings path to Kiro Agent. - Trend chart keeps the newest 30 turns; the legend lists only non-zero parts. Backend - The context part of the usage fold is a fixed-size state: five running sums, the newest measurement, the newest window reading, a 30-row trend ring and one session-start row. Every apply is O(1) and the state is the same size after 10 and 1,000 turns. - parse_breakdown keeps per-category percent, list counts, the toolIO / workspace / memory splits, window size and usage, and media counts. - /api/telemetry/context-trace carries the session's harness id. i18n: every locale updated for the new and changed strings; plural keys registered; en-XA regenerated. Not yet measured: cron, sub-agent and task turns open no crew-log turn, so a measurement for them has nothing to attach to (follow-up). Turns KAS starts on its own (KAS workflows) are not measured either: Kiro Crew does not enable KAS workflows today (follow-up). Refs #24030 Review fixes folded in: Review fixes for the fixed-size context fold and the panel. - Each trend ring row now stores the turn ordinal it closed at (seven integers per row), and the render reads it back instead of counting down from the newest turn. A slot with session starts at ordinals 1, 3 and 5 now labels its rows [2, 4, 6] with one earlier turn. - A new, non-resumed session resets the occupancy reading (used = -1, window = 0), so a new session never shows the previous one's tokens. - A turn sent again (retry, regenerate, edit-resend of an earlier message) keeps its ordinal and replaces its own ring row, so no two rows share a number; ring rows also carry their unit and turn number for that lookup. Its previous attempt's measurement, ttft and engine turn id are dropped until the new attempt reports its own. - An in-place compaction (compaction/applied) restarts Kiro Crew's resident sums: they keep only what was composed after the newest turn that closed with an occupancy reading, so a deferred verdict keeps the prompt composed before it arrived. Without it a kiro-cli session showed summarized-away prompts as resident and the rest of the context as 0. - The owning specs describe the fixed-size state: metrics.md (context_trace and the panel), the usage row in crew-log-projection.md, fold-paths.md (derived from the folds). - The dashboard catalog declares the new nullable context leaves (usage.context.latest, usage.context.start) and drops the two keyed maps the fold does not render; the usage fold's savepoint pin and the facade's type-checking imports are re-recorded. - Panel: number + unit strings go through the i18n format helpers, table labels store full catalog keys, and the message colour is a design token. In a narrow panel the grey character count sits under the tokens and labels wrap instead of being cut. On Kiro Agent an unsplit turn's tip says it is not measured yet, instead of asking to switch harness (new key in every locale). - Catalog hygiene: literal i18n keys at every call site, the product name through {{productName}}, the informal register and spacing each locale's style guide asks for, and the old panel's unused keys and their descriptions removed. Facade manifests, the retired facade names' inventory and the facade import paths are updated to match. - The engine's own "Other" gets a hue of its own, so grey is only the rest of the context. The headline's token figure says it comes from the window reading, and the over-estimate warning names "Rest of the context".
iamwhatever
left a comment
There was a problem hiding this comment.
Request changes: a promised follow-up has no issue. Reviewed 01264b6fd063f902a8779c7eb932c543bb080d13.
The description's Not a goal says: "Known gap, left for a follow-up: cron, sub-agent and Task Runner turns are not measured." No issue is linked for it, and #24030 covers only the redesign. Please open one issue for that gap and link it in the description, or close the gap here.
Please also reply to the advisory notes on this head:
- Design: trace
turnsrows now always carry emptyts/model, zerocontext_used/context_window, andengine_unknown: {}(usage_context.py#L296-L332). Drop them, or document them as legacy-only. - UX: the turn count in the chart heading, the missing column for an open newest turn, and mixed units on an unmeasured turn.
- First Principles: the dropped 14-day row filter. The description does declare it.
The new ?turn= read sits behind the existing dashboard-only gate with strict input validation. All lanes are PASS or no findings, checks are green, and there are no change requests.
— crew-pr-reviewer (r127)
Each of the 31 rows the chart keeps (the 30-turn ring and the session
start row) now holds its turn whole, so picking a past turn shows it
exactly as the newest one is shown.
- A row stores the turn's Kiro Crew blocks by name (at most 64, the
composer's own most; a name under TEXT_LIMIT; the rest counted), a
copy of its engine measurement (14 categories, history split, list
counts, toolIO, workspace and memory splits, window, media, ttft) and
its own occupancy reading. The fold stays apply-only and bounded:
31 rows times that per-row cap. A rerun still replaces its own row,
found by ordinal.
- The trace handler turns each row into `detail`, a whole-turn view in
`latest`'s shape, from the same engine-view builder.
- The panel: chart columns are buttons again (click, arrow keys, the
nearest-turn surface on narrow plots) and the start row is one too.
The picked turn's panel has the engine's rows when it was measured,
the estimated view otherwise, and a disclosure listing its blocks.
The pick is the turn's ordinal, so a new turn shifting the full ring
keeps the panel on the picked turn; once that turn leaves the ring
the newest is shown with a note. The start row names itself as a
picker ("Show turn N (session start)"), marks itself while its turn
is shown, and states the same size as that turn's headline; a turn
is called "session start" wherever it is shown, plus "latest" when
it is also the newest.
- A turn that closes without composing (a slash command) takes an
ordinal, once per turn number, as a refused turn does, so the next
composed turn is not numbered one short.
- A failed selection-capabilities read shows its error beside the
trace's, and Rest of the context then gives no harness advice.
- Names: "Kiro Crew other" is "Kiro Crew session details" (every Crew
block outside rules, memory and skills); the subtitle no longer says
"at the newest turn"; a Kiro Agent turn not measured yet says
"Estimated. The engine hasn't measured this turn yet."
- The pushed value is slim: the fold keeps every row whole but renders
only the newest turn whole; a ring row is its ordinal, five sums and
loop, and the start row adds the size its panel heads with. A real
session pushes about 6 KB (was about 29 KB).
- A past turn is read on demand: GET /api/telemetry/context-trace
?slot=..&turn=<ordinal>, served from the in-memory fold state through
read_slot_state (never a log read-back), with the trace's own gate;
400 for a turn that is not a positive integer, 404 once it left the
ring. The panel caches it by slot, ordinal and revision.
- A picked past turn always has a way back: "Show latest turn (N)", and
Escape or Home on a chart column, return to the newest turn, also
while it is still open and not yet a column.
- Engine rows are named apart from Kiro Crew's: "Engine system prompt",
"Skill list (engine)", "Other text sent as you".
- The Rest of the context (i) carries a visible tag saying which tip it
is ("Not measured yet", "Not measured", "How to split it"), and the
switch tip says new sessions use Kiro Agent while this one keeps its
agent.
- On a harness that never splits, the chart is in estimated tokens, to
match the token headline and start row.
- The blocks heading counts every block sent: before the every-turn
members are grouped, and the ones past the list.
- On a token chart each column carries a Rest of the context band up to
its turn's own reading (ring rows carry `used`); a turn with no total
gets none, and the caption says so.
- The occupancy peak keeps its meaning: one pair from the fullest turn
closed inside the requested days, from the newest 200 dated readings
the state keeps, else 0 and the configured window.
- The dashboard catalog declares what context_render writes for latest
and start, and its driven test fails on a declared leaf it does not.
- A picked past turn's read is keyed by its own row in the trace, not
the fold revision: a new turn elsewhere re-reads nothing, and while a
changed row is re-read the previous read stays shown, disclosures open.
- Trace turn rows drop the always-blank ts, model, context_used and
context_window, and the page drops engine_unknown: nothing reads them
and the state keeps none of them per turn.
- The usage fold's state version moves, so older savepoints refold.
Refs #24030
|
The follow-up for the cron, sub-agent and Task Runner gap is #24523; the "Not a goal" line now links it. Replies to the r127 review (head 496f15d). Design: blank fields on trace UX: turn count in the chart heading. "All N turns" / "Last N turns" counts the chart's columns, the kept ring. The session-start row sits above the chart, and the turns before the ring are counted on their own line ("Turns 1-N earlier"), so the three numbers add up to the session without overlap. No change. UX: no column for an open newest turn. By design: a column is a closed turn with its own numbers, and the running turn has none yet. The panel above the chart always shows the newest turn, running or not, and while a past turn is picked, "Show latest turn (N)" (and Escape or Home on a column) goes back to it. No change. UX: mixed units on an unmeasured turn. By design, and every figure names its unit. An unmeasured turn only has the harness token total, so its headline and rows are in tokens, and the Kiro Crew rows are marked "~" with their characters beside them. The chart is in characters while any kept turn was measured by the engine, since those columns are character counts. It says "Unit: characters" or "Unit: tokens (estimated)" above it. No change. First Principles: the dropped 14-day row filter. Declared in the description under Backwards compatibility: |
Problem / Motivation
Goal: Show what filled a session's context at its newest turn as one window-style breakdown, with Kiro Crew's own share first and in one place, and keep the fold behind it a fixed size.
#23648 recorded the engine's per-turn context breakdown, but the Context panel showed it as a separate block of numbers under Kiro Crew's own rows. Readers could not see at a glance what filled the context, and Kiro Crew's share was split across two places. Turns from harnesses that do not report a breakdown (kiro-cli) showed only Kiro Crew's characters under a token headline, so the rest read as missing. The
usagefold also kept up to 200 per-turn rows with per-block labels, so its state and every pushed update grew with the session.Why it matters
The Context panel is where a user checks why a session is slow, expensive or near its window. If Kiro Crew's own blocks are scattered and the rest of a kiro-cli turn reads as missing, the user cannot tell whether Kiro Crew or the engine is filling the context. The growing fold cost every push on long sessions about 196 KB and 0.8 ms of on-loop
json.dumpsat 1,000 turns.Not a goal
What changed (motivation -> approach -> change)
Goal: one picture of the newest turn, Kiro Crew first, rows that add up to the total. Approach: a window-style tree (headline, bar, flat list) drawn from one fixed-size fold state, so the panel reads the newest state and nothing grows.
Panel
--ctx-eng-other) in the list and the bar. Grey means only "Rest of the context", in the list and in the chart.used), so the line reaches the 84,000-token headline, and the band is in the legend. A turn with no total gets no such band, and the caption adds "Turns with no reported total have no grey band."src/i18n/format.ts(fmtCompactfor the window size,fmtBytesfor media), and the label tables store full catalog keys.GET /api/telemetry/context-trace?slot=<key>&turn=<ordinal>(cached by slot, ordinal and that row's own numbers in the trace, so a new turn elsewhere re-reads nothing; a loading line, or the error, shows in place on the first read, and while a changed row is re-read the previous read stays on screen with its disclosures open) and shows its panel exactly like the newest one, with a disclosure listing its blocks; a turn the engine did not measure shows the estimated view for that turn. The pick is the turn's ordinal, so a new turn shifting the full ring keeps the panel on the picked turn; once it leaves the ring the newest is shown with a note. While a past turn is picked, a "Show latest turn (N)" button returns to the newest turn, and Escape or Home on a chart column does the same; this matters when the newest turn is still open and not yet a column. The blocks disclosure counts every block the turn sent, before the every-turn members are grouped into one list row and including the ones past the list ("13 Kiro Crew blocks sent this turn": 7 sent, 5 rows listed, "6 more blocks not shown"). The start row names itself as a picker ("Show turn N (session start)", with a visible Show / Shown above), marks itself while its turn is shown, and states the same size as that turn's headline; a session-start turn is called that everywhere, plus "latest" when it is also the newest.Backend
usagefold is a fixed-size state: five running sums (restarted by a new unit or a compaction), the newest engine measurement, the newest occupancy reading (reset by a new unit), a 30-row trend ring, one session-start row, and the newest 200 dated occupancy readings plus the configured window for the peak (below); each row holds its turn whole (see above). Every apply touches at most one row. A test folds 210 and 1,000 turns and asserts the same state shape.loopand its own readingused, and the start row addsfigure, the size its panel heads with. A real session pushes about 6 KB.GET /api/telemetry/context-trace?slot=<key>&turn=<ordinal>serves one kept row as a whole-turn view inlatest's shape, from the in-memory fold state (a newread_slot_statereader, the same warm cellread_slot_projectionrenders), never from a crew-log read-back. Same dashboard-only gate and app-caller 404 as the trace;400 turn_invalidunlessturnis a positive ASCII integer,404 turn_not_keptonce the turn left the ring. The trace page carriesrevision, and itsturns[](the Session Breakdown tree) come from the state's per-turn blocks.peak_context_used/context_windowis still one pair from the FULLEST turn closed insidedays: the highestused / windowratio (integer cross-multiplication,>=keeps the newer of equally full turns, a reading with no window is not a candidate), else 0 and the configured window. The state keeps the newest 200 dated readings with a window (peaks, the reach the old 200 rows had) and the unit's newest non-zerorequest/configuredwindow (conf_window), andcontext_peaktakes the pair from them. A session at 90k of a 100k window that switches to a 1M window at 10k reports 90%, not 1%.bus.pyorFoldAdvanced.turn_memo, at mostCONTEXT_ORDINAL_MEMO_LIMIT= 10,000, pinned equal to the slot's live message cap), so a rewind far past the ring keeps its ordinal and cuts the ring rows after it. A refused turn and a turn that closes without composing (a slash command) take an ordinal too, once per turn number. A new, non-resumed session also clears the stored engine measurement, so the panel shows no breakdown left from the previous session.compaction/applied, which the engine does not measure) restarts Kiro Crew's resident sums: they keep only what was composed after the newest turn that closed with an occupancy reading. The verdict lands either before the next turn composes or, when deferred, at the next turn that carries a reading while that turn is still open, so a deferred verdict keeps the prompt composed before it arrived. Without this, a session with 40,000 injected characters, then a 1,000-character prompt and a 1,500-token reading, showed the old 41,000 characters as resident and the rest of the context as 0.parse_breakdownkeeps the summary-mode fields: per-category percent, list counts, toolIO input/output, workspace and memory splits, window size and usage, and media counts.context/measureddeclares them.GET /api/telemetry/context-tracecarries the session's harness id so the tip can name it.metrics.md(context_trace and the panel), theusagerow increw-log-projection.md,fold-paths.md(derived by calling the folds) describe the fixed-size state. The dashboard catalog declares the new nullable leaves.i18n: every locale updated for the new and changed strings, three plural keys registered, en-XA regenerated.
Size (old fold vs this one), measured with the fold's own step over 1,000 real-shaped turns (16 Kiro Crew blocks each, the captured KAS frame on every turn for "KAS", no frame for "Kiro CLI"), and the worst case built by
worst_case_context():usagevalue pushed per update (JSON)json.dumpsper push (mean)?turn=read (JSON)The state is bounded whatever the session's length: 31 rows (the 30-turn ring and the session-start row), each at most 64 blocks with names under
TEXT_LIMITplus one engine measurement, an ordinal memo of at most 10,000 turn numbers (the slot's live message cap, the range a rewind can reach), and at most 200 peak readings of three integers each. It stays under the slot-fold cache's 995,342-byte member ceiling, andtest_the_worst_case_context_state_is_bounded_under_the_cache_ceilingpins it under 950,000 B. The worst pushed context part is the newest turn's 64 blocks at the longest name plus a full engine view;test_the_worst_case_pushed_value_is_a_few_kbpins it under 22,000 B (20,908 B compact).Decision changed. An earlier pin said the trace carries no chars-per-token estimate of the remainder of a turn the engine does not split. It is reversed because the owner found the panel misleading without it (the rows did not add up to the headline: 85,339 tokens on top, 49,338 characters of rows below), so the remainder is now shown as "Rest of the context", marked "~" and captioned "characters / 4".
Backwards compatibility
Breaking: the
usagefold's renderedcontextdropsby_source,window,sources_omittedandmeasured_unknown, andcontext.turnschanges from the 200-row list to the turn counter.GET /api/telemetry/context-tracekeeps every top-level key exceptengine_unknown, which nothing reads; itsturns,totalsandinjected_charsare built from the trend, each turn row is{phase, blocks, total_chars, ordinal, first_start}(the always-blankts,model,context_usedandcontext_windoware gone, since the state keeps none of them per turn),peak_context_used/context_windowkeep their meaning (the fullest turn insidedays), anddaysselects nothing else. Writer sweep on origin/main @ 5631aab: the fold is the only writer, and the readers are below. The fold's state version moves, so old savepoints retire to a cold fold.Reader: src/kiro_crew/dashboard/handlers/usage_context.py:context_trace -- crew page -- reads latest/trend/start from the new state; test/metrics/test_context_trace.py, test/metrics/test_context_measured.py
Reader: website/src/pages/SessionBreakdownTree.tsx:SessionBreakdownTree -- chat -- reads turns/totals/injected_chars/peak_context_used, which the trace still returns; website/src/test/SessionBreakdownTree.test.tsx
Reader: website/src/pages/ContextBreakdownPanel.tsx:ContextBreakdownTab -- chat -- reads latest/trend/start/earlier, and a past turn from
?turn=, since rows no longer carrydetail; website/src/test/ContextBreakdownPanel.test.tsx, website/src/test/ContextBreakdownTab.push.test.tsxReader: src/kiro_crew/dashboard_types.py:_OPAQUE -- app -- the two removed keyed maps are dropped and the new nullable leaves declared; test/test_dashboard_types.py
Reader: scripts/fold_catalogue.py:main -- release -- the committed catalogue matches the code; test/test_fold_catalogue.py
Reader: src/kiro_crew/crew_log/projection_usage.py:_usage_step -- crew page -- the only caller of measured_start/measured_step/note_composed/note_closed/note_unit_start/decode_measured, now calls context_start/context_apply/context_render; test/test_crew_log_projection.py
Reader: src/kiro_crew/crew_log/projection.py:_EXPORTS -- crew page -- the facade served those six names and now serves the new ones; test/test_projection_facade.py, test/test_entry_types_facade.py
Tests
Slim view and the turn read:
test_the_pushed_value_carries_no_per_row_detail(ring rows are{turn, ours, loop, used}, the start row addsfigure, the newest turn is whole),test_the_worst_case_pushed_value_is_a_few_kb,test_a_kept_turn_reads_whole_and_one_that_left_the_ring_reads_as_none(test/metrics/test_context_measured.py);test_a_kept_turn_reads_whole_and_one_not_kept_is_404,test_a_turn_that_is_not_a_positive_integer_is_400(8 cases),test_an_app_caller_asking_for_a_turn_is_refused_the_same_way(test/metrics/test_context_trace.py); the picker:asks for a picked past turn the trace does not carry, and shows that turn's read,heads the start row with the size the trace sends for it(ContextBreakdownPanel.test.tsx) andreads a picked past turn from the turn route, once per version of its rowandkeeps a picked past turn on screen, disclosures open, across new revisions(a new turn elsewhere re-reads nothing; turn 2 sent again is re-read while the old read stays shown, blocks list open;ContextBreakdownTab.push.test.tsx, the second fails on the previous head). All but the app-caller test fail on the previous head.The peak, restored from the base unchanged:
test_peak_is_the_fullest_ratio_not_the_largest_used_across_a_switch,test_the_occupancy_pair_comes_from_one_turn,test_a_reading_whose_window_is_unknown_is_not_a_peak_candidate,test_the_window_falls_back_to_the_configured_size_with_no_reading_yet,test_a_peak_outside_the_day_window_is_not_reported(its oldturns == []line dropped, sincedaysno longer filtersturns) andtest_an_open_turn_does_not_drag_the_peak_down(test/metrics/test_context_trace.py);test_the_configured_window_is_the_newest_stated_in_this_unit(test/metrics/test_context_measured.py). The first, second, fourth and fifth fail on the previous head.The catalog:
usage.context.startis declared as{turn, ours, loop, used, figure}withfigurenullable{n, unit}, andusage.context.latestgainsblocks(opaque, keyed by block name) andblocks_omitted.test_every_declared_nullable_type_matches_what_the_fold_writesnow fails on a declared leaf the driven render does not contain (checked by declaringstart.crew_rawagain: it fails).The token chart and the blocks count:
fills each token column up to its own harness total with the rest bandandcounts every block sent in the heading, before grouping and past the list(ContextBreakdownPanel.test.tsx); both fail on the previous head.The way back and the readability fixes:
always offers the way back to a running newest turn that is not a column yet(pick a column, then the button, Escape and Home each return to the newest turn),speaks tokens in the chart when the panel does, on a harness that never splits,names which tip it is before any hoverandnames the engine rows apart from the Kiro Crew rows(ContextEngineBreakdown.test.tsx). Each fails on the previous head.website/src/test/ContextBreakdownPanel.test.tsx: the three restored picking tests (moves the detail to a clicked turn and back with the arrow keys,selecting the start row drives the detail like any other turn,keeps every turn reachable: one pointer surface maps a click to the nearest turn),a past turn shows its own block names and its own engine rows,keeps the picked turn when a new turn shifts the full ring, and says so once it leaves(pick turn 12 of ring 2..31, complete turn 32: still turn 12),names the start row as a picker and marks it while its turn is shown, andcalls a session-start turn that is also the newest one thing in both places; the last three fail on the previous head.test/test_crew_log_projection.py:test_usage_a_rewind_past_400_turns_keeps_the_turns_ordinalandtest_usage_the_ordinal_memo_covers_the_rewindable_range, restored; the first fails on the previous head (ordinal 1001, not 10).test/metrics/test_context_measured.py:test_a_new_session_shows_no_breakdown_from_the_previous_session(fails on the previous head) andtest_the_session_tree_draws_what_each_turn_sent_not_the_running_sum(three turns of 1,000 draw 1,000 each).test/metrics/test_context_measured.py:test_a_past_turn_keeps_its_own_blocks_and_its_own_engine_breakdown,test_a_row_keeps_at_most_the_composers_blocks_and_counts_the_rest, andtest_the_worst_case_context_state_is_bounded_under_the_cache_ceiling(31 full rows, 894,000 B).test/metrics/test_context_measured.py:test_a_rewound_turn_reuses_its_ordinal_not_a_new_one(turns 1, 2, 3 then turn 2 again: ring 1, 2, 3 once each, turn 2's row is the resend's; the old fold gave [1, 2, 3, 3]) andtest_a_new_attempt_drops_the_previous_attempts_measurement; both fail on the previous head.test/metrics/test_context_trace.py::TestEveryTurnTakesAnOrdinal, restored from the base: a composition-less turn (composed 1, slash command 2, composed 3 gives rows 1 and 3), retried once, two in a row, as the first turn, a turn composed twice, a refused turn, refused twice, and a session start after a refused turn 1. The four composition-less tests fail on the previous head ([1, 2] for [1, 3]).test/metrics/test_context_trace.py:test_a_turn_carries_only_fields_with_a_value_and_a_reader(a turn row is exactly{phase, blocks, total_chars, ordinal, first_start}and the page has noengine_unknown).website/src/test/ContextBreakdownTab.push.test.tsx:shows a failed harness read and gives no harness advice(fails on the previous head).website/src/test/ContextEngineBreakdown.test.tsx: the Kiro Agent tip says "Estimated. The engine hasn't measured this turn yet." with no switch path; the engine's Other is--ctx-eng-otherin the list and the bar, Rest is--ctx-eng-loop; in a narrow panel the characters stack under the tokens and the label wraps.test/metrics/test_context_measured.py:test_an_in_place_compaction_keeps_only_what_was_composed_after_it(40,000 injected, compaction applied, then a 1,000-character prompt and a 1,500-token reading: resident 1,000, rest of the context > 0) andtest_a_deferred_compaction_verdict_keeps_the_prompt_composed_before_it_arrived; both fail on the previous head (41,000 resident).test/metrics/test_context_measured.py:test_every_row_keeps_its_own_ordinal_across_several_session_starts(starts at 1, 3, 5 give trend [2, 4, 6], earlier 1) andtest_a_new_session_does_not_show_the_previous_sessions_occupancy; both fail on the previous head. Also the fixed-size state, the O(1) apply, compaction and unit restarts, the ring bound and the refused orphan measurement.test/test_dashboard_types.py: the new nullable leaves are declared and driven to real values.Python, the test files that reference the touched modules: 8,096 passed (163 files). One failure,
test_app_agent_launch_copy.py::...[opted-out], fails the same way on the base commit and is unrelated.vitest:
ContextEngineBreakdown,ContextBreakdownPanel,ContextBreakdownTab.push,catalogParity,registerCatalogs(1,375 passed across the panel, Session Breakdown andsrc/i18ntests).npm run i18n:checkagainst the merge base: every check passes (pages/chat/ErrorCard.tsxappears only in the report-only dynamic-keys list, which this branch does not touch). tsc, eslint--max-warnings 0on the touched files, mypy, flake8, isort, black, docs lint, the comment-history gate and the fold catalogue check.Manual verification
test/fixtures/acp_frames/kas/profile/).Screenshots / video
All from this head (Storybook, light unless noted). KAS turn, Kiro Crew first, the engine rows named apart from Kiro Crew's (Engine system prompt, Skill list (engine), Other text sent as you), the engine's Other in pink:
KAS turn, dark:
KAS turn at 560px:
KAS turn in the 320px side panel, labels wrap:
kiro-cli turn, Kiro Crew folded: rows in tokens marked ~, the chart in estimated tokens with a "Rest of the context" band up to each turn's harness total (turn 6 reaches the 84,000-token headline), the start row in tokens, and the "How to split it" tag beside the (i):
The kiro-cli tip, which says what switching does:
Kiro Agent turn not measured yet: the "Not measured yet" tag and its tip:
Turn 9 is still running and not a column yet; turn 5 was picked from the chart. The heading has no "latest", the column is marked, and "Show latest turn (9)" goes back (so do Escape and Home on a column):
The session-start row picked: "Shown above", the same 168,000 characters as the headline:
The blocks disclosure open on a picked turn: 13 blocks sent (7 by name, two of them grouped into "Every-turn instructions", so 5 rows) and "6 more blocks not shown":
Turn 11 was picked, then turn 41 closed and pushed it out of the last 30: the note says so and the newest turn is shown:
The selection-capabilities read failed (503): its error with Ask the agent, and "Rest of the context" has no tip or tag:
kiro-cli session whose newest turn is the session start: the start row shows the headline's own tokens and "Shown above":
320px side panel, kiro-cli turn with about 400,000 Kiro Crew characters: characters under the tokens, labels wrap. Turn 3 reported no total, so its column has no grey band and the caption says so:
320px side panel, Kiro Agent turn not measured yet, with its tag and tip:
The same kiro-cli turn at 560px, values side by side, and turn 3's column without a total:
Related Issues
Closes #24030. Follow-up to #23648.
Checklist
feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert: ...)Contribution License Agreement
Contributed under the project's Apache-2.0 license.