Skip to content

fix(report): count dispatches, kernel outcomes and critic passes once each - #2045

Merged
xiaofei-zheng merged 13 commits into
mainfrom
fix/report-counting-calibers
Oct 21, 2026
Merged

xiaofei-zheng merged 13 commits into
mainfrom
fix/report-counting-calibers

Conversation

@lishuoshuo-amd

@lishuoshuo-amd lishuoshuo-amd commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator
  • Description:
    The session report counted several things more than once or under the wrong name. All fixes are in the reporter layer plus the critic row ordering in the assembler; no schema change.
    1. Specialist rounds: a discovery/authoring dispatch appears as a phase row and as a framework run with the same id, and both were counted (ds-v4-pro printed 91 for 88 dispatches; all seven audited sessions were inflated). Rounds are now the distinct task_id/run_id set.
    2. Kernel table counters: one attempt was counted in reverts (any non-KEEP e2e decision) and again in rejected (its outcome); glm52 printed reverts=1 · rejected=3 for 0 and 3. Each attempt now lands in one bucket from its settled outcome; reverts counts only REVERT decisions, and a REVERT decision outranks an adopted outcome, so a revoked keep is counted as a revert (not a keep) and the funnel marks its kernel reverted rather than partial. An attempt whose e2e decision was KEEP but whose outcome is rejected is no longer counted as kept (custom: kept 2/2 becomes tried 2/0).
    3. Capability e2e_gain took the best gain over every attempt, reverted ones included; it now reads adopted attempts only.
    4. Kernel funnel: optimized counted kernels any lane tried, including all-rejected ones (glm52 optimized=4 with 3 rejected). It is renamed attempted in the funnel, the summary lines and GlobalFacts.kernel_pipeline_funnel.
    5. Critic: passes were sorted by (iter, ts), but iter restarts with the process on resume, so ds-v4-pro had 801 out-of-order rows and repeated iter values. The assembler now orders passes by ts; the report numbers them 1..N under a # column (and the last-pass heading uses the same number); the idle placeholder ok (critic) (DEFAULT_IDLE_BODY) renders as —. The recorder still stores the placeholder. The constant is defined once in inference_optimizer/protocol/intent.py (the layer both the critic runtime and the renderer may import) and intent_envelope.py re-exports it, so the layer contract holds.
  • Linked issue(s): Refs Serving throughput is labelled tok/s/GPU but is the aggregate over all TP GPUs #1932. fix(breakdown): rename throughput_tok_s_per_gpu to output_throughput (schema 6.1) and record per-GPU output on baseline and validation rows #2023 is merged; stacked on fix(report): render fields on the axis and scope they were recorded on #2043 (base branch fix/report-render-field-mismatch), retarget to main once fix(report): render fields on the axis and scope they were recorded on #2043 merges.
  • Tests: 8 new tests and one rewritten ordering test in test_breakdown_renderers.py, test_critic_renderer_unit.py, test_breakdown_assembler_compose.py, test_reporters_smoke.py, each failing on the base branch (exact counts, exact header rows); test_sbd_v6_critic_recording.py's ordering test now expects record-time order. test_breakdown_report_integrity.py::test_capability_table_shows_unadopted_outcomes asserted that a reverted candidate's gain is shown; it now pins the exact row without it. Ran those six files individually; ruff and scripts/code_metrics.py pass. Re-rendered the seven audited sessions: specialist rounds 91→88, 104→100, 31→27, 18→13, 61→56, 27→24, 38→32.
  • Size/complexity triggers crossed: 8 source files (+57/-38) and 6 test files; each source change is a few lines in the function that counts.
  • If this simplifies or refactors: n/a.
  • Observable effect: the report's specialist rounds, kernel table counters, funnel label and critic table read as described above.
  • Breaking changes: no persisted field changes. GlobalFacts.kernel_pipeline_funnel["optimized"] (in-process LLM fact pack) is renamed attempted; session_breakdown.json critic.iterations is ordered by ts instead of iter.
  • PR addresses single concern: yes, report counts and labels that did not match what was counted.
  • Root cause is upstream: no.

The session report mixed axes and scopes in several places: the headline
paired output tok/s with a p50 gain, elapsed showed one leg, the stop target
was printed as the objective, a zero TTFT or kernel speedup read as a
measurement, the final unit did not match its value, an unvalidated session
got a contradictory validation warning, failed roofline runs read as no data,
and the LLM prompt keyed not-validated on a value never emitted.
A re-anchored baseline no longer matches the ledger baseline the gain is
measured against, so the pair is dropped unless before*(1+gain) equals
after within 0.5%. The graded axis no longer falls back to the configured
axis, which is recorded as p90 while the verdict is taken on p50.
Before and after now come from the last stack event settled validation
row, the one that produced the gain, and only when it is on the graded
axis and reproduces the gain. Otherwise the headline states the gain and
the axis without throughput figures.
Specialist rounds counted a discovery/authoring dispatch twice (phase row and
run share one id), the kernel table put one attempt in both reverts and
rejected and took capability gains from reverted candidates, the funnel called
lane-tried kernels optimized, and the critic table ordered and numbered passes
by a per-process counter that restarts on resume.
@lishuoshuo-amd
lishuoshuo-amd requested a review from a team as a code owner October 20, 2026 03:36
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Code metrics gate: PASSED

Judged: the 14 files this change touches. Files it does not touch never fail it; anything found there is listed under Outside this change for information.

Dimension Limit New Worse Baseline out of date Baseline entries vs base
Cyclomatic complexity fails > 20 0 0 0 55 +0
Cognitive complexity fails > 30 0 0 0 203 +0
Function length (lines) fails > 80 0 0 0 346 +0
Nested block depth fails > 5 0 0 0 20 +0
Parameter count fails > 5 0 0 0 95 +0
Module length (lines) warns > 800, fails > 1200 0 0 0 49 +0
Duplicated lines per file fails > 0 0 0 0 96 +0
Dead code (vulture) fails > 0 0 0 0 2 +0
Check Findings Effect
Comments 0
English only 0
Production code imports test code 0
Repeated literals 0
A1 Private name of another package 0
A8 Flag argument 0
A9 Tuple return 0
A10 Raw vocabulary comparison 0
A11 Hidden global write 0
A12 Pure forwarder 0
A12 Single-implementation abstraction 0
108 findings in files this change does not touch

Outside this change (informational): 108

Unit Dimension Baseline Now
src/hyperloom/orchestrator/state/shared_state.py resolve_graded_comparison Cognitive complexity absent 34
src/hyperloom_kb/collect/mapping.py _experience Cognitive complexity absent 31
src/hyperloom_kb/schema.py FieldDeclaration.__post_init__ Cognitive complexity absent 32
src/kernelforge/cli/forge_loop_command.py _prepare_measurement_driver Cognitive complexity absent 36
src/kernelforge/cli/forge_loop_command.py _read_kb_warm_start Cognitive complexity absent 40
src/kernelforge/cli/forge_loop_command.py forge_loop Cognitive complexity absent 31
src/kernelforge/loop/runner.py IterationLoop._collect_session_candidate Cognitive complexity absent 44
src/kernelforge/loop/runner.py IterationLoop._rule_on_attempt Cognitive complexity absent 38
src/hyperloom/inference_optimizer/cli/__init__.py _reexport_session_environment Function length (lines) absent 111
src/hyperloom/inference_optimizer/cli/__init__.py _resolve_agent_lineup Function length (lines) absent 89
src/hyperloom/inference_optimizer/cli/__init__.py _resolve_run_topology Function length (lines) absent 92
src/hyperloom/inference_optimizer/cli/__init__.py _resume_session Function length (lines) absent 170
src/hyperloom/inference_optimizer/cli/__init__.py _seed_fresh_session Function length (lines) absent 164
src/hyperloom/inference_optimizer/multi_node/cli.py _restart_multinode Function length (lines) absent 107
src/hyperloom/inference_optimizer/multi_node/scripts/launch_multinode.py _build_parser Function length (lines) absent 84
src/hyperloom/inference_optimizer/multi_node/scripts/launch_multinode.py _spawn_rank_actors Function length (lines) absent 84
src/hyperloom_kb/sync.py GlobalSync.pull Function length (lines) absent 84
src/kernelforge/cli/forge_loop_command.py _RunReporter.build_result Function length (lines) absent 92
src/kernelforge/cli/forge_loop_command.py _prepare_measurement_driver Function length (lines) absent 136
src/kernelforge/cli/forge_loop_command.py _read_kb_warm_start Function length (lines) absent 149
src/kernelforge/loop/runner.py IterationLoop._close_iteration Function length (lines) absent 117
src/kernelforge/loop/runner.py IterationLoop._collect_session_candidate Function length (lines) absent 185
src/kernelforge/loop/runner.py IterationLoop._implementer_history Function length (lines) absent 112
src/kernelforge/loop/runner.py IterationLoop._rule_on_attempt Function length (lines) absent 102
src/kernelforge/loop/runner.py IterationLoop._source_attempt Function length (lines) absent 175

...and 83 more; the job log lists every row.

Verdict computed by the gate scripts in /home/runner/work/_temp/code-metrics-gate, not by this tree's copy.

Thresholds and sources: [tool.hyperloom.code_metrics] in pyproject.toml. Tools: complexipy 8.0.1, jscpd 5.4.1, ruff 0.16.2, vulture 2.16.

The critic report renderer imported the placeholder from the agents layer,
which inference_optimizer may not depend on. The constant now lives in the
intent protocol module that both sides already import.
@lishuoshuo-amd

Copy link
Copy Markdown
Collaborator Author

PR #2045 -- fix(report): count dispatches, kernel outcomes and critic passes once each

What it does: The session report counted record views rather than the things they describe: a specialist dispatch recorded both as a phase action row and as a framework run with the same id was counted twice, one kernel attempt landed in both a decision bucket and an outcome bucket, and critic passes were ordered by iter, which restarts on resume. The reporter now counts distinct task_id/run_id, buckets each attempt once from the outcome that _settle already computed (with e2e_gain read from adopted attempts only), renames the funnel's optimized to attempted, numbers critic passes 1..N and shows the idle placeholder as an em dash. The assembler now orders critic.iterations by ts, and DEFAULT_IDLE_BODY moves down to protocol/intent.py so the renderer can import it.

Blocking issues: none

SKIPPED: V4 -- openprs.txt compared only the first 100 files of #1032, #1154, #1276, #1869, #1907 and #2004; overlap there is unchecked.

Checked: specialist_tally, source_counters, _kernel_funnel, compose funnel lines, critic renderer, _compose_critic, protocol/intent.py, intent_envelope.py, recorder/kernel_event.py::_settle and ::_merge_acceptances, framework_event.py::record_run, critic_out.py::record_critic_iteration, docs/reference/session-breakdown.md (critic section, compatibility rules, stability guarantee), AGENTS.md Clean design / Finish the replacement; sweep scoped to src/hyperloom/inference_optimizer, src/hyperloom/agents/critic and docs for every reader of kernel_pipeline_funnel, source_counters, specialist_tally, critic.iterations and DEFAULT_IDLE_BODY; outcome x e2e.decision combinations and task_id/run_id overlap surveyed across 9 real sessions | Ran: the six changed test files plus test_intent_envelope.py at head (144 passed); the same test files against a git-archived base (11 failed: every new or changed test); real-session reports rendered at head and base (rounds 91/104/31/18/61/27/38 -> 88/100/27/13/56/24/32, glm52 reverts=1 · rejected=3 -> rejected=3, custom geak kept 2/2 -> tried 2/0); ruff C901 head vs base; PYTHONPATH=src lint-imports (7 kept, 0 broken) | Base: d6ff195 | Head: e0b7c0b

LGTM

@lishuoshuo-amd

Copy link
Copy Markdown
Collaborator Author

PR #2045 -- fix(report): count dispatches, kernel outcomes and critic passes once each

What it does: The session report counted record views rather than the things they describe: a specialist dispatch recorded both as a phase action row and as a framework run with the same id was counted twice, one kernel attempt landed in both a decision bucket and an outcome bucket, and critic passes were ordered by iter, which restarts on resume. The reporter now counts distinct task_id/run_id, buckets each attempt once from the outcome that _settle already computed (with e2e_gain read from adopted attempts only), renames the funnel's optimized to attempted, numbers critic passes 1..N and shows the idle placeholder as an em dash. The assembler now orders critic.iterations by ts, and DEFAULT_IDLE_BODY moves down to protocol/intent.py so the renderer can import it.

Blocking issues: none

SKIPPED: V4 -- openprs.txt compared only the first 100 files of #1869 and #2055, and only the newest 100 of 103 open PRs; overlap there is unchecked.

Checked: the PR diff at ab239fd against the previously reviewed d6ff195..e0b7c0b (identical modulo hunk offsets; the two new commits are merges of the base branch); compose.py after the auto-merge (both funnel lines read attempted, base added only logging); every reader of kernel_pipeline_funnel, source_counters, specialist_tally, critic.iterations and DEFAULT_IDLE_BODY, sweep scoped to src/hyperloom/inference_optimizer, src/hyperloom/agents/critic and docs; base drift since the last round in recorder/kernel_event.py::_settle, framework_event.py::record_run, critic_out.py and docs/reference/session-breakdown.md (only the schema 6.1 text moved; the critic section and compatibility rules are unchanged); stack state via gh (#2023 merged, #2043 open at the base tip) | Ran: the six changed test files plus test_intent_envelope.py at head (144 passed); the same test files against git-archived base a92a7f2 (11 failed: every new or changed test); real-session reports rendered at head and base (rounds 91/104/31/18/61/27/38 -> 88/100/27/13/56/24/32, glm52 reverts=1 · rejected=3 -> rejected=3, custom geak kept 2/2 -> tried 2/0); ruff C901 at a ceiling of 20 on changed source files (all passed); PYTHONPATH=src lint-imports (10 kept, 0 broken) | Base: a92a7f2 | Head: ab239fd

LGTM

@xiaofei-zheng xiaofei-zheng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #2045 -- fix(report): count dispatches, kernel outcomes and critic passes once each

What it does: the session report counted one logical event under two keys in four places -- a specialist dispatch recorded both as a phase action row and as a framework run, a kernel attempt added both to its outcome bucket and to reverts, e2e_gain taken over reverted attempts, and a funnel stage called optimized that counted every kernel any lane tried. Each counter is now keyed on the single identity or settled outcome that defines it (dispatches by task_id/run_id, attempts by outcome, gain over adopted attempts only, optimized renamed attempted), and the critic table is ordered by ts and numbered 1..N because iter restarts on resume. All of it sits in the reporter layer plus the critic row ordering in the assembler; no persisted field changes.

Blocking issues: 1

  1. [C2] An attempt settled adopted whose end-to-end decision is REVERT is counted as a keep, and its REVERT is dropped [verified]
    Problem: source_counters tests the outcome before the decision, so an attempt carrying outcome="adopted" together with e2e.decision="REVERT" takes the first branch, lands in keeps and never reaches the elif decision == "REVERT" below it. src/hyperloom/inference_optimizer/breakdown/reporters/_renderers/_kernels.py:113-123
    The shape is what the GEAK revalidation path produces: promote_geak_from_candidate lifts the candidate and then, when the overlay was not proven loaded, calls reject_geak_kernel_journey (orchestrator/phases/kernel.py:2275-2285), which rewrites every journey KEEP to decision="REVERT" (breakdown/recorder/kernel_event.py:358-400), while the rebench ledger row for the same visit carries decision="validated" (orchestrator/loop/writeback.py:2822-2833). _settle consults the rebench ledger before e2e (breakdown/recorder/kernel_event.py:1777-1790), so the attempt stays adopted.
    Impact: the capability summary reports a revoked GEAK keep as an adoption. On the same one-attempt document, base a92a7f2 renders | geak | tried | 1 | 0 | reverts=1 | and capabilities_kept = []; head ab239fd renders | geak | kept | 1 | 1 | | and capabilities_kept = ['geak'], while the kernel-pipeline funnel on the same page still says adopted=0, partial=1. reverts -- the counter this PR narrows to REVERT decisions -- shows 0 for a REVERT. The new test test_each_attempt_lands_in_exactly_one_outcome_bucket covers adopted+KEEP, adopted+<none> and rejected+REVERT, so CI stays green.
    Action: settle the conflict before bucketing -- let a REVERT decision win over an adopted outcome (or route the pair to reverts/micro_only_keeps explicitly) and add the adopted+REVERT case to the bucket test.

SKIPPED: V4 -- "#1869 changes 518 files, only its first 100 were compared", overlap there unchecked.
SKIPPED: V4 -- "#2055 changes 149 files, only its first 100 were compared", overlap there unchecked.
SKIPPED: V4 -- "AMD-AGI/Hyperloom has 107 open PRs, only the newest 100 were compared", overlap there unchecked.

Checked: _kernels.py source_counters, capability_summary._kernel_row/_status, _framework.specialist_tally against phase_event.py actions.rows/task_id and phases/framework.py record_run(task_id), critic.py row numbering and last-pass heading, assembler._compose_critic sort key, cross_section._kernel_funnel and compose.py funnel lines, kernel_event._settle / reject_geak_attempts / _merge_acceptances, tree-wide sweep for readers of the old funnel key and of DEFAULT_IDLE_BODY | Ran: source_counters, capability_rows, render_session_report and kernel_event._settle called directly on constructed documents in both trees; a full recorder-level replay in production call order | Base: a92a7f2 | Head: ab239fd

A REVERT end-to-end decision now outranks an adopted outcome, so a keep the
integrate path revoked is no longer counted as adopted. The funnel marks such
a kernel reverted instead of partial.
@lishuoshuo-amd

Copy link
Copy Markdown
Collaborator Author

Addressed [C2]. Reproduced it: a single attempt with outcome="adopted" and e2e.decision="REVERT" was counted as a keep in the capability row (kept 1/1, capabilities_kept == ['geak']) while the funnel said adopted=0, partial=1, reverted=0.

A REVERT decision now outranks an adopted outcome in source_counters: the attempt counts as a revert, not a keep, and adds nothing to e2e_gain. The funnel (_fold_attempts) records such a kernel as reverted instead of partial, so the table and the funnel agree. test_each_attempt_lands_in_exactly_one_outcome_bucket gained the adopted + REVERT case, and test_a_revoked_keep_is_a_revert_in_the_capability_row_and_the_funnel renders the single-attempt document and pins the exact row (| geak | tried | 1 | 0 | reverts=1 |), an empty capabilities_kept, and funnel (adopted, reverted, partial) == (0, 1, 0); both fail without the fix. #2043's current head (c65b158a7) is merged in at fc6c44a2c, and checks are green. Please take another look.

@xiaofei-zheng
xiaofei-zheng dismissed their stale review October 21, 2026 07:55

Addressed at fc6c44a: the revoked keep is now counted as a revert.

@xiaofei-zheng

Copy link
Copy Markdown
Collaborator

PR #2045 -- fix(report): count dispatches, kernel outcomes and critic passes once each (re-review at fc6c44a)

What it does: the session report counted one logical event under two keys in four places -- a specialist dispatch recorded both as a phase action row and as a framework run, a kernel attempt added both to its outcome bucket and to reverts, e2e_gain taken over reverted attempts, and a funnel stage called optimized that counted every kernel any lane tried. Each counter is now keyed on the single identity or settled outcome that defines it, with a REVERT decision outranking an adopted outcome, and the critic table is ordered by ts and numbered 1..N because iter restarts on resume. All of it sits in the reporter layer plus the critic row ordering in the assembler; no persisted field changes.

Blocking issues: none.

The finding from the previous round is fixed at fc6c44a. source_counters now tests decision == "REVERT" before the outcome (_kernels.py:116-118), and _fold_attempts marks a revoked attempt's kernel reverted rather than partial (_kernels.py:213-216). Re-ran the same case that regressed -- one geak_authored_kernel attempt with outcome="adopted" and e2e.decision="REVERT", the shape reject_geak_kernel_journey produces after a lift whose overlay was not proven loaded:

head fc6c44a2: {attempted 1, adopted 0, keeps 0, micro_only_keeps 0, reverts 1, rejected 0}
               | geak | tried | 1 | 0 | reverts=1 |   capabilities_kept = []
               Kernel pipeline: detected=1 -> recommended=1 -> attempted=1 -> adopted=0 (reverted=1, rejected=0, partial=0)
base c65b158a: | geak | tried | 1 | 0 | reverts=1 |   (funnel key still named optimized)

The capability row and the funnel now agree, and test_a_revoked_keep_is_a_revert_in_the_capability_row_and_the_funnel pins both.

Checked: source_counters bucket order and _fold_attempts / _fold_integrate / _fold_adopted_by verdict precedence in _kernels.py; capability_summary._kernel_row and _status; _framework.specialist_tally dedup against phase_event.py actions.rows[].task_id and phases/framework.py record_run(task_id) / specialists/dispatch.py:824; critic.py row numbering and the last-pass heading; assembler._compose_critic sort key including the missing-ts tail; cross_section._kernel_funnel and both funnel lines in compose.py; kernel_event._settle / reject_geak_attempts / _merge_acceptances; tree-wide sweep for readers of the old funnel key and of DEFAULT_IDLE_BODY (no doc, prompt or SKILL.md names either). Description re-checked against the head diff: 8 source files (+57/-38), 6 test files, 8 new tests -- all match numstat.
Ran: source_counters, capability_rows, render_session_report and kernel_event._settle called directly on constructed documents in both trees, plus a recorder-level replay in the production call order (record journey KEEP -> record acceptance -> reject_geak_attempts -> rebench ledger validated -> finish). No local suite run; CI is green at the head.
Base: c65b158 | Head: fc6c44a
SKIPPED: V4 -- "#1869 changes 526 files, only its first 100 were compared", overlap there unchecked.
SKIPPED: V4 -- "#2055 changes 149 files, only its first 100 were compared", overlap there unchecked.
SKIPPED: V4 -- "AMD-AGI/Hyperloom has 103 open PRs, only the newest 100 were compared", overlap there unchecked.

LGTM

@xiaofei-zheng xiaofei-zheng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues at fc6c44a. The revoked-keep finding from the previous round is fixed and verified: an attempt with outcome "adopted" and e2e.decision "REVERT" now lands in reverts, the capability row reads "| geak | tried | 1 | 0 | reverts=1 |" with capabilities_kept empty, and the funnel reports reverted=1, partial=0 on the same page. Details and the full checked/ran list are in the preceding comment.

Base automatically changed from fix/report-render-field-mismatch to main October 21, 2026 07:59
@xiaofei-zheng
xiaofei-zheng merged commit 9f7030a into main Oct 21, 2026
36 checks passed
@xiaofei-zheng
xiaofei-zheng deleted the fix/report-counting-calibers branch October 21, 2026 08:01
siliangchen-amd added a commit that referenced this pull request Oct 26, 2026
With prior.txt and the delta in hand, a re-review now settles the earlier one before its own
(references/re-review.md):

- It decides every finding of the latest card at this head into prior_verdicts.txt, FIXED, HOLDS or MOVED. A
  finding that holds goes back on the card under its earlier key, opening `held since round <n>.`
- It still reviews the whole diff, as a first review does, and reads the delta first: an earlier card can have
  missed anything, the PR author's own included. On #2045 the author's clean card and the head on which a second
  reviewer then found a blocking defect carry the same patch.
- A new finding on a line the earlier card already had says `(missed at <sha>)`, so a miss is named rather than
  presented as new, and two cards on one head no longer contradict each other in silence.
- From round 3, a finding of a class an earlier round raised names the shared cause in its Action and asks the
  author to reconsider the approach.

The card contract: a finding names one shape and lists every path:line it has in the diff; the Checked line adds
Round and, from round 2, Prior (`Prior: C1 fixed, T2 holds`), so the author reads what was fixed without inferring
it from a missing line. pr-review-publish.sh refuses a card for a PR with earlier cards when prior_verdicts.txt is
empty or Prior is missing, and the CI contract asks for both.

SKILL.md stays within its 350-line budget: the CI failure classification, read only when ci.txt or mergeable is
quoted, moves to references/ci.md unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
siliangchen-amd added a commit that referenced this pull request Oct 26, 2026
.claude/skills/review-pr/evals/cases.yaml holds 11 cases, each a PR at a head a reviewer once saw and what a review of
that head must report:

- 6 rules.md source PRs, at the head the finding was raised against and with the place it was raised at: D7 #1567,
  S1 #1564, P1 #1526, R4 #1563, X6 #1497 and M3 #1444. Each finding was fixed afterwards.
- #2045 at ab239fd, where two cards were clean and a third found the C2 the author then reproduced and fixed.
- 4 clean cases, #2048, #2044, #2039 and #2059: every card on them was clean, the head they reviewed is the head that
  merged, and no later commit on main names them.

A finding about the description is left out, since a replay reads today's description, which the author may have
corrected since; so is #2094, whose blocking card came after the merge and was never settled.

scripts/review_pr_eval.py score reads one eval-<case>-r<repeat> directory per replay and reports how many expected
findings were found (by key, or by a cited place within ten lines), how many clean replays blocked, whether the
replays of one case agree, and the time, turns and tokens from the run log. Replayed through fetch.sh, #1567 at
a143f8f and #1444 at 6767a77 cut their comments before the finding was raised and carry the expected file in their
diff.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants