feat(sbd-v6): declare and record the AgentX grading axis - #1380
Open
luochen-amd wants to merge 5 commits into
Open
feat(sbd-v6): declare and record the AgentX grading axis#1380luochen-amd wants to merge 5 commits into
luochen-amd wants to merge 5 commits into
Conversation
Resolving the axis reads `HYPERLOOM_PERF_METRIC` and `HYPERLOOM_PERF_NOISE_PCT` from the environment. The breakdown is exported from CLOSE, frequently a subprocess that never inherited them, so deriving it there can name an axis the session never graded on -- and an operator re-exporting an old session later would get whatever their shell happens to hold. The failure is silent: the block looks well-formed and states the wrong axis. `SharedState.grading` records the resolved objective and veto band at seed, next to `benchmark_mode` and `agentx_epoch`, which are in the state for the same reason: they describe the run, not the shell that happens to be exporting it. The collector now prefers what was recorded and only falls back to deriving for sessions seeded before the field existed. What stays a projection is the part that is genuinely derived from recorded facts: whether the session degraded to output because its baseline never carried the axis pair. That is read off `state.baseline_perf`, not off the environment, so it is stable at any export time. This moves one step toward recording evidence when it happens rather than reconstructing it at export. It adds no writer call site in `orchestrator/`: the write is at seed in `cli/bootstrap.py`, alongside the existing ones, so the collector contract in `breakdown/collectors/v6_stages.py` still holds. The seed test is skipped where `fcntl` is missing -- importing the CLI package pulls it in, and the rest of the module stays importable on any platform. Co-authored-by: Cursor <cursoragent@cursor.com>
An AgentX replay is ranked on total token throughput under an interactivity veto; a synthetic run is ranked on output throughput alone. On the canonical corpus the two differ by roughly two orders of magnitude -- a measured Kimi-K3 baseline read 25978 tok/s total against 183 tok/s output. Every throughput field in the breakdown is the output axis by construction, and nothing in the document said which axis the gains were on, so a consumer had no way to keep an AgentX session out of a synthetic leaderboard. It would sort one against the other and the numbers would look plausible. `metadata.grading` names the mode, the objective, the interactivity veto band, and why the total axis did not apply when it was asked for and could not be supplied. `objective` is what the gains in this document are actually on, not what was requested: a session that asked for the total axis but never measured it graded on output, and reads `output_throughput` here with `degrade_reason` naming the gap. Reading it any other way would let a degraded run pass as a comparable AgentX result. `outcome` carries the four AgentX axes at both ends (total and input throughput, interactivity p90, TPOT p90) plus `graded_on` on `final` and on `validation`. The reconciliation has to be single-axis: an attributed figure on one axis against an unattributed figure on another makes the gap meaningless. Unmeasured axes are explicit nulls -- absent would be indistinguishable from an axis the framework failed to report, and zero reads as "measured, and it was zero". Purely additive. `throughput_tok_s_per_gpu`, `output_throughput` and every other existing key keep their output-axis meaning, so no existing consumer changes. TPOT p90 was already parsed out of the benchmark report and discarded at five call sites; it now lands. `outcome` resolves the axis through the same helper `metadata.grading` uses, so the two blocks cannot drift into naming different axes for one session -- there is a test that locks it. Co-authored-by: Cursor <cursoragent@cursor.com>
…ession's axis
The collector fell back to deriving the grading axis from the environment when
a session carried no recorded one. That fallback reads HYPERLOOM_PERF_METRIC
and HYPERLOOM_PERF_NOISE_PCT, and an export can run days later from any shell:
honouring an override there relabels the axis of a run that already finished,
and the block still looks perfectly well-formed while saying the wrong thing.
The fallback now derives from recorded facts only -- benchmark_mode and the
framework, both persisted. The override still works in both directions; it is
resolved at seed, where the run can see it. The veto band is null rather than
today's default for such a session, because it was never recorded and the
current environment is not evidence of what the session applied.
This removes the last os.environ read from the V6 collectors.
Also adds docs/reference/session-breakdown-provenance.md: a per-block
inventory of where every V6 metric comes from, which ones are reconstructed at
export rather than recorded when the fact occurred, and a ranked backlog of
the ten worth moving. The three sharpest findings behind that list:
* metadata.langfuse degrades to an environment view in a subprocess CLOSE,
and the patch that repairs this rewrites only the V5 top-level langfuse,
never metadata.langfuse.
* kb_write_back.ext.queue counts the KB queues at CLOSE step 2, while the
ndjson_drain step that empties them runs afterwards and the timeline is
never re-patched -- the shipped depths describe nothing.
* outcome.validation.attribution re-buckets and re-sums a total the recorder
already computed; the ledger itself warns when the two disagree.
install and model_gate stay the reference pattern: written by
write_timeline_event when the fact happens, correct for a session that
finished last week.
Co-authored-by: Cursor <cursoragent@cursor.com>
The V6 provenance audit and the recorder-vs-collector fixes it listed are their own piece of work; keeping the page here would advertise a backlog this PR does not deliver. This PR stays scoped to the AgentX grading axes. Co-authored-by: Cursor <cursoragent@cursor.com>
… used Review found three ways the declared grading could disagree with the real decision. All three came from the same mistake: the axis was recorded but nothing downstream was made to use it. 1. The runtime comparator still resolved the objective from HYPERLOOM_PERF_METRIC and the veto band from HYPERLOOM_PERF_NOISE_PCT, so a resume was free to change the KEEP/REVERT rule mid-session. An AgentX session explicitly configured for output flipped back to total when the resuming process lacked the variable, and a 3.5% veto band silently widened to the 5% default. resolve_graded_comparison now reads state.grading and passes the recorded band into the interactivity gate; only sessions seeded before the field derive it. 2. outcome.final.graded_on was resolved from the session configuration, which describes the setting rather than any one decision. A promotion falls back to output whenever either side of its comparison cannot supply the axis pair -- candidate_axes_missing and current_best_axes_missing are both reachable, and cumulative_gain_validated is then an output figure with a total label on it. The axis is now recorded on the promotion itself and read back from the last one. metadata.grading keeps its old meaning as the configured axis, and the two are deliberately no longer resolved from a shared call -- the test that locked them together encoded the wrong invariant and is replaced by one that pins them apart. 3. final's axes were read off current_best while its gain came from cumulative_gain_validated. A full-stack revalidation updates the gain and explicitly skips re-lifting current_best, so one outcome.final could carry the newest gain beside the measurement taken when the recipe was first promoted. The promoted measurement's axes are recorded beside the gain they produced, and final reads that pair; current_best remains the fallback for a session that promoted nothing. record_session_validation carries graded_on, degrade_reason and perf because that is the one place where all three are known at once and none of them survives in state afterwards. Co-authored-by: Cursor <cursoragent@cursor.com>
CI E2E report — ❌ Timeout
|
luochen-amd
marked this pull request as draft
September 3, 2026 03:18
luochen-amd
marked this pull request as ready for review
September 3, 2026 10:31
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Makes an AgentX session's grading axis visible in
session_breakdown.json, and records it when the run resolves it rather than re-deriving it at export.Why
#1362 made an AgentX replay rank on total token throughput under an interactivity veto; a synthetic run still ranks on output throughput alone. On the canonical corpus the two differ by roughly two orders of magnitude — a measured Kimi-K3 baseline read 25978 tok/s total against 183 tok/s output.
Every throughput field in the breakdown is the output axis by construction, and nothing in the document said which axis the gains were on. A consumer had no way to keep an AgentX session out of a synthetic leaderboard: it would sort one against the other and every number would look plausible.
The block
objectiveis what the gains in this document are actually on, not what was requested. A session that asked for the total axis but never measured it graded on output, and readsoutput_throughputhere withdegrade_reasonnaming the gap. Reading it the other way would let a degraded run pass as a comparable AgentX result.outcomecarries the four AgentX axes at both ends — total and input throughput, interactivity p90, TPOT p90 — plusgraded_ononfinaland onvalidation. The reconciliation has to be single-axis: an attributed figure on one axis against an unattributed figure on another makes the gap meaningless.Two deliberate choices:
throughput_tok_s_per_gpu,output_throughputand every other existing key keep their output-axis meaning. No existing consumer changes.outcomeresolves the axis through the same helpermetadata.gradinguses, so the two blocks cannot drift into naming different axes for one session. There is a test that locks it.Recorded, not re-derived
Resolving the axis reads
HYPERLOOM_PERF_METRIC/HYPERLOOM_PERF_NOISE_PCT. The breakdown is exported from CLOSE — frequently a subprocess that never inherited them — so deriving it there can name an axis the session never graded on. An operator re-exporting an old session later would get whatever their shell happens to hold. The failure is silent: the block looks well-formed and states the wrong axis.So the axis is resolved once at seed and recorded in
SharedState.grading, next tobenchmark_modeandagentx_epoch, which live there for exactly the same reason. The collector prefers what was recorded. Its fallback for older sessions derives from recorded facts only —benchmark_modeand the framework — and reports anullveto band, because the band was never recorded and the current environment is not evidence of what that session applied. The override still works in both directions; it is resolved where the run can see it.This removes the last
os.environread from the V6 collectors.What stays a projection is the part genuinely derived from recorded facts: whether the session degraded because its baseline never carried the axis pair. That reads
state.baseline_perf, so it is stable at any export time.Test
14 cases in
test_sbd_v6_grading.py(13 pass, 1 skipped wherefcntlis missing — importing the CLI package pulls it in, and the rest of the module stays importable on any platform). They cover both axes, the scriptable-framework carve-out, the degrade path, recorded-wins-over-env, and the metadata/outcome agreement lock.Verified against the same suites on a clean tree: identical results, so the failures present locally are the pre-existing POSIX-only
fcntlimports rather than anything here.ruff check src/hyperloom/inference_optimizerandruff formatare clean.Rollout
Additive to the wire shape, so nothing downstream has to change to keep working. Cortex cannot store the new axes yet — there is no column for total throughput or interactivity anywhere — so the immediate value is that an AgentX session becomes identifiable, which is the prerequisite for keeping it out of a leaderboard it is not comparable on.