Repository navigation
refactor(breakdown): delete the dead and repeated code in two over-gate kernel-event and attribution-renderer functions - #2074
Conversation
Delete the second read of attribution.available: the "no per-source split" fact is now the elif of the "no ledger" fact, which is what the old `not has_any_split and available` test spelled out. Delete the `notes` list that was built up front only to be looped at the end; the notes are appended where they always landed, as the last facts. The kept decisions become a comprehension over the same rows and filter, and the markdown table is passed straight into the section instead of through a one-use local. Behaviour is identical: the facts, their order, the decisions and the table are unchanged, nothing between the old and new position of the notes read can raise, and an f-string formats every JSON value exactly as str() did. render: cyclomatic 11 -> 8, cognitive 28 -> 24, lines 85 -> 79. Co-authored-by: Cursor <cursoragent@cursor.com>
…of its sections Delete the eight hand-written read-and-sort blocks in assemble_kernel_ext: each section's sort fields are now one row of _ROW_ORDER, read by a single comprehension. Delete the second pass that patched an e2e block onto attempts after they were built: _lane_attempt now joins its integrate gate rows while it builds the row, which is the only place the join could fire (a GEAK or acceptance attempt never carries an integrate_ref). Delete _geak_settlement and its (ref, conflicts) tuple: _geak_rebench builds the wire rebench block directly, the attempts read settled_against and conflicting_decisions off it, and the GEAK engagement test reads its `required` field instead of re-deriving the same ledger-or-stated test. Two guards go as dead. `parts.get(section) or []`: every caller builds parts with event_parts(), which fills every requested section with a list (the recorder's own close, _republish_closed_event, event_finalize's kernel spec over EVENT_SECTIONS, and assembler.kernel_event_parts). The entry.route fallback for outcome.route: the header's only writer, KernelEventRecorder.__init__, has put `route` and `entry.route` in the same record with the same value since kernel_event.py was created (5085b93). What stays per wire block moves into _forge, _geak and _outcome, each returning its schema block, so the ext literal the schema contract test pins stays in assemble_kernel_ext. Block contents, key order and the order of the roofline and baseline sub-assemblies are unchanged; a seeded differential over 6000 random events is byte-identical except for a header whose route is blank while entry.route is set, which no writer produces. assemble_kernel_ext: cyclomatic 11 -> 3, cognitive 50 -> 11, lines 206 -> 77. Co-authored-by: Cursor <cursoragent@cursor.com>
…ork cleared Delete the three entries for functions now under the gate: kernel_event.py::assemble_kernel_ext (cognitive 50, lines 206) and attribution.py::render (lines 85). Lower kernel_event.py's module-lines entry from 2168 to its new length, 2149. No entry is raised or added. Co-authored-by: Cursor <cursoragent@cursor.com>
Code metrics gate: PASSEDJudged: the 3 files this change touches. Files it does not touch never fail it; anything found there is listed under Outside this change for information.
61 findings in files this change does not touchOutside this change (informational): 61
...and 36 more; the job log lists every row.
Thresholds and sources: |
…akdown-2-pr Co-authored-by: Cursor <cursoragent@cursor.com>
ZhengGong-amd
left a comment
There was a problem hiding this comment.
Reviewed: gate numbers re-measured (ruff C901, complexipy, function lines) and match the description; each removed guard / "producer always sets it" claim checked against its producers and call sites; base vs head differential runs show no undisclosed behaviour change; tests covering the touched modules pass.
LGTM.
…akdown-2-pr Co-authored-by: Cursor <cursoragent@cursor.com>
…akdown-2-pr Co-authored-by: Cursor <cursoragent@cursor.com>
What this does
Two session-breakdown functions were over the code-metrics gate:
assemble_kernel_ext, which builds a kernel event'sextfrom its recorded rows, and the attribution renderer'srender. This PR brings both under every limit they broke, mostly by deleting: eight hand-written read-and-sort blocks (now one table), a second pass that patched e2e results onto attempts after they were built, a helper whose tuple result was taken apart and rebuilt into the rebench block, nine guards on input every caller already fills, a fallback for a field its only writer always sets, and, in the renderer, a second read of the ledger state and three one-use accumulators.Production code: +152 / −177 (net −25) across 2 files. No test is added or changed. The code-metrics baseline loses 3 entries, lowers 1 module-length entry and gains none.
This continues the complexity cleanup series that started with #2024; #2052, an earlier breakdown PR in it, shares no source file with this one. The 3 commits read one at a time; each commit message lists what it deleted and why that is safe.
reporters/_renderers/attribution.pyrecorder/kernel_event.pyBoth production files are under
src/hyperloom/inference_optimizer/breakdown/.Gate numbers per function
Measured with the gate's own collectors (ruff C901, complexipy, function lines), origin/main → this branch. Limits are 20, 30 and 80; bold values were over the limit at base.
recorder/kernel_event.pyassemble_kernel_extreporters/_renderers/attribution.pyrenderAlso changed, never over at base:
_lane_attempt1 → 1 / 0 → 1 / 35 → 39.New functions in
kernel_event.py, cyclomatic / cognitive / lines:_forge3 / 6 / 29,_geak3 / 12 / 35,_geak_rebench2 / 8 / 25,_outcome1 / 2 / 18.Deleted function:
_geak_settlement(3 / 7 / 20), replaced by_geak_rebench.Across the 2 touched production files: C901 total 141 → 136, cognitive total 287 → 266, functions 51 → 54. Functions over a gate limit: cognitive 3 → 2, length 4 → 2. What is left is outside this work, all in
kernel_event.py:_merge_acceptances(cognitive 31),record_geak_attempts(cognitive 31, 102 lines; #2048 changes it) andrecord_integrate_verdict(89 lines).Module lengths:
kernel_event.py2,168 → 2,149,attribution.py102 → 96.What changes in each module
Kernel event assembly (
recorder/kernel_event.py)New names:
_ROW_ORDER: the fields each of the eight row sections is ordered by. One comprehension reads and orders all of them._geak_rebench: builds GEAK's wirerebenchblock (V6KernelGeakRebench), including the attempt GEAK's acceptances settle against and any conflicting decisions._forge: builds theforgeblock (V6KernelForge), orNonewhen forge did not run._geak: builds thegeakblock (V6KernelGeak), orNonewhen GEAK did not run._outcome: builds theoutcomeblock (V6KernelOutcome)._lane_attemptnow takes the integrate rows by id. A lane that states no e2e result takes its gate's result while the lane is built.The
extliteral and its field comments stay inassemble_kernel_ext, becausetest_sbd_v6_ext_schema_contract.pyreads the wire keys from that function's body (:31,:40-62).Removed:
_geak_settlementand its(ref, conflicts)tuple, and the second derivation of "a GEAK ledger exists or a rebench was stated" in the GEAK engagement test, which now readsrebench["required"].parts.get(section) or []guards.entry.routefallback foroutcome.route.Attribution renderer (
reporters/_renderers/attribution.py)Removed from
render: the second read ofattribution.available(the "no per-source split" fact is now theelifof the "no ledger" fact), thenoteslist built up front, the loop that accumulated decisions (now a comprehension over the same rows and filter), and the one-usemdlocal.Why the deletions are safe
Line numbers are on this branch unless marked "on main".
Row order table. Each row of
_ROW_ORDER(kernel_event.py:2037-2046) holds the sort fields of the block it replaces (kernel_event.py:1948-1989on main). The sections main passed throughwire_rowsstill go through it where they are read: trace runs and discovered kernels in_forge(:1966-1967), discovery runs in_geak(:2009), GEAK kernel rows before_geak_attempt(:2065).wire_rowsdrops only rows that are not mappings (event_rows.py:88), androws_for_eventalready kept only mappings (event_rows.py:35), so the GEAK engagement test, which now reads the unwired kernel rows (:1995), sees the same rows.E2E join in
_lane_attempt. On main, the second pass (kernel_event.py:1999-2003on main) fillede2eonly for an attempt whosee2ewas empty and whoseintegrate_refwas set. Only a lane setsintegrate_ref:_geak_attempt(:833-872) and_acceptance_attempt(:875-895) keep the template's""(:705), and acceptance attempts were appended after the pass anyway (:2004on main)._lane_attemptnow does the same join while it builds the lane (:802-803,:828). A lane without a reference calls_integrate_e2e([]), which returnsNone(:659-660), as before.GEAK rebench block.
_geak_rebench(:1921-1945) derives the settled attempt and the conflicting decisions from the same settled rows_geak_settlementread, and keeps the block's key order.assemble_kernel_extreadsrebench["settled_against"]for_merge_acceptances(:2066) and"conflicting_decisions" in rebenchfor_settle(:2073); that key is present exactly when the old tuple's conflict list was non-empty (:1943-1944).rebench["required"]isbool(ledger) or bool(stated)(:1935), the two facts the old engagement test read separately (kernel_event.py:2044-2046on main).Sections read without a guard. Every production caller builds
partswithevent_parts, which puts a list under every section it is asked for (assembler.py:297-300), and all three ask forEVENT_SECTIONS(sections.py:141-152). That includesKERNEL_EVENT_SECTIONS(sections.py:58-68), which is exactly the event section read atkernel_event.py:2055plus the eight_ROW_ORDERkeys. The callers:kernel_event.py:1601-1604);_republish_closed_event(kernel_event.py:641-642);event_finalize.py:62-63, with parts fromevent_parts(spec.sections)at:147, called at:162).Tests call it with
kernel_event_parts()(assembler.py:333-335), which isevent_partsoverKERNEL_EVENT_SECTIONS:test_sbd_v6_kernel_timeline.py:112,:984,:1076andtest_coordinator_gemm_promote_units.py:1578. Nothing inscripts/calls it.outcome.route. The only code that writesrouteorentry.routeinto the kernel event section isKernelEventRecorder.__init__(kernel_event.py:1098-1110), which writes both fromself._routein the same record; every version of the file since it was created (5085b93) does the same. Theentryfragmentbeginwrites later (:1131-1149) carries noroute, and theroutethatbeginhands toopen_event(:1154) goes into the timeline envelope, not into the section's rows (event_timeline.py:122-135). The recorder is built only bymake_kernel_recorder(kernel_event.py:2128, constructor call at:2144), called fromorchestrator/phases/kernel.py:480.Attribution facts.
attributionis a plain dict (attribution.py:35), so readingavailableonce and branching withelif(:62-64) adds the same facts as main's two separate tests. The breakdown'svalidation.notesis written by_validation_notes(collectors/v6.py:560, defined at:588), which returns strings; for a string, and for any JSON value read back from disk,f"{note}"andstr(note)give the same text.Observable effect
Nothing an operator sees changes. For every input the repo's own callers produce, kernel event
extblocks (contents and key order), the breakdown JSON and the attribution section stay the same. A seeded differential ofassemble_kernel_extbefore and after this change, over 6,000 generated events, matched byte for byte apart from the 292 events that hit the first case below.The differences below are reachable only by input that no caller in the repo produces:
routebut a non-blankentry.route.outcome.routeused to fall back toentry.route; it is now"". OnlyKernelEventRecorder.__init__writes either field, both from the same value in one record (see Why the deletions are safe).assemble_kernel_extgiven apartsmapping that lacks one of the nine kernel sections, or holdsNonefor one. Such a section used to read as empty; now a missing section raisesKeyErrorandNoneraisesTypeError. Every caller passesevent_partsoutput, which holds a list for each of them.attribution.render: no difference. The facts, their order, the decisions and the table are unchanged. Notes are formatted by an f-string instead ofstr(), which gives the same text for every JSON value.Checklist
test_sbd_v6_kernel_timeline.pyandtest_coordinator_gemm_promote_units.pycallassemble_kernel_extdirectly,test_sbd_v6_ext_schema_contract.pypins its top-level wire keys, andtest_reporters_smoke.pycovers the attribution section's table, shares, notes and decisions.test_sbd_v6_framework_wiring.py::test_source_attempt_records_its_pair_gate_and_lifecycle_step, a CRLF mismatch in the patch content on Windows); one collection error is intest_tracelens_csv.py, because TraceLens is not installed. None of the test files that reach these two modules changed on main since. Linux CI on this PR is the authority.render(79), 15 lines of which are its docstring, is one pass that builds the section's facts, decisions and table.assemble_kernel_ext(77) has 28 comment lines, 15 of them on theextliteral, which stays in this function because the schema contract test reads its keys there.kernel_event.py(2,149) stays over the 1,200-line module limit it was already over, and stays in the module-length baseline, 19 lines shorter.assemble_kernel_extkeeps its signature and now needs every kernel section inparts, which every caller already passes;_lane_attemptand_geak_settlementare private.Known merge interactions
Trial merges used
git merge-tree --write-treeagainst the current head of every open PR that shares a file with this branch, plus the five whose file list GitHub cuts off at 100 files. A conflict counts as this branch's only when the same merge onto main (931af8a) does not have it.kernel_event.py, and both merge theirkernel_event.pychanges cleanly with this branch.record_geak_attempts,reject_geak_attempts, the body of_integrate_e2eand one call inside_settle. This branch calls_integrate_e2eand_settlewith the same inputs as before, and_integrate_e2e([])is stillNonethere.module-linesentry ofkernel_event.py, which all three PRs lower: to 2,161 in fix(breakdown): drop never-populated 6.1 keys and report unmeasured figures as null #2047, 2,167 in fix(breakdown): record the GEAK candidate at close and kernel e2e gain from the rebench #2048 and 2,149 here. Whichever lands second records the merged file's length. That conflict does not exist against main alone; fix(breakdown): record the GEAK candidate at close and kernel e2e gain from the rebench #2048's two other conflicts (orchestrator/phases/close.py,orchestrator/state/_shared_state/render.py) do.rewrite_by_flydslfunction-linesentries just above thekernel_event.pymodule-linesentry lowered here, and refactor(breakdown, kernelforge): delete what eleven over-gate functions re-checked #2052 deletes the three entries just above theassemble_kernel_extfunction-linesentry deleted here. Keep both edits. Neither conflict exists against main alone.final.py,baseline.pyand more), notattribution.py; both trial merges are clean.attribution.pyamong them, and exactly the same conflicts with this branch.Gate
The code-metrics gate (
scripts/code_metrics.py --base-ref origin/main, run locally) passes on the 3 touched files: 0 new, 0 worse and 0 out-of-date entries in every dimension, and 0 findings from the comment, English-only, test-import, repeated-literal and A1–A12 checks. Baseline changes:cognitive-complexity …/kernel_event.py::assemble_kernel_ext 50;function-lines …/kernel_event.py::assemble_kernel_ext 206;function-lines …/_renderers/attribution.py::render 85;module-lines …/kernel_event.pyfrom 2168 to 2149.ruff checkandruff format --checkare clean on the touched files.