Skip to content

feat(kernelforge): export-runs reads AgentKernelArena campaign logs - #1951

Closed
amd-ama10002-2 wants to merge 4 commits into
feat/kernelforge-export-runs-arena-sessionfrom
feat/kernelforge-export-runs-arena-campaign
Closed

amd-ama10002-2 wants to merge 4 commits into
feat/kernelforge-export-runs-arena-sessionfrom
feat/kernelforge-export-runs-arena-campaign

Conversation

@amd-ama10002-2

@amd-ama10002-2 amd-ama10002-2 commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

We are building knowledge-base support for KernelForge runs (kernel writing): turning KernelForge's raw logs into structured Experiences in Hyperloom's Experience KB. We are also changing the logs KernelForge writes so they carry what the KB extracts: planner plans open with a Summary: line, and implementers keep a <plan>.reasoning.md work log that opens the same way. This PR teaches kernelforge export-runs the AgentKernelArena campaign log, after which AgentKernelArena logs can be collected.

Stack: merge in this order, one at a time. Each PR targets the branch of the PR above it in this list.

  1. feat(kernelforge): plans open with a Summary line; implementers keep <plan>.reasoning.md #1949 — Summary line in plans; implementer reasoning logs
  2. feat(kernelforge): collect plain forge-loop runs as Experiences with export-runs and kernelforge-v1 #1944 — export-runs and the kernelforge-v1 mapping, for plain forge-loop runs
  3. feat(kernelforge): export-runs reads AgentKernelArena driver.log sessions #1950 — export-runs reads AgentKernelArena driver.log sessions
  4. feat(kernelforge): export-runs reads AgentKernelArena campaign logs #1951 — export-runs reads AgentKernelArena campaign logs (this PR)

What changes

  • kernelforge export-runs reads an AgentKernelArena campaign log (the launcher's log under logs/ that names one KernelForge artifacts directory): each forge-loop iteration is one entry under the launcher's run name, after the PORT step when the campaign ran forge-rewrite. Before, the artifacts directory was read as a plain forge-loop run under the config's campaign_id.
  • An iteration also takes fields from KernelForge's archive of it and from the transcript of the implementer session that produced its candidate; the round's planner transcripts join its raw logs.
  • A forge-rewrite campaign's PORT step and iterations report forge-rewrite's logged source baseline, the original kernel's time, as source_ms. Read as a plain run, the same iterations reported the pristine baseline run_state.json records or, without one, the time of the port the forge-loop started from. A campaign without forge-rewrite keeps the archive's value.
  • Provenance records the pipeline when the campaign ran forge-rewrite, and the Implementer's backend and model from the forge-loop's own lines. It also records the image, the arena config and KernelForge's commit when the log carries a Docker runtime: … image=, config_ok= or forge_engine=<branch> <commit> line; AgentKernelArena's launcher script prints the first two to its console, and none of them reaches the log file AgentKernelArena writes under logs/. Identity records the operator from the evaluator's --model-class.
  • Refactor-only parts: none.

Known limitations

  • The log root must hold the run's artifacts directory under the launcher's run name (<run>/<task>-forge-<id>); without it the campaign is one entry saying why.
  • A log that names more than one KernelForge artifacts directory, as AgentKernelArena writes for a run of several tasks or for a resumed run that launched KernelForge again, is one entry saying so, and each directory it names is read as a plain forge-loop run.
  • A log whose only run line is RESUME RUN:, as every parallel worker's is, is one entry saying the run was not logged, and its artifacts directory is read as a plain forge-loop run.
  • Campaign log times are naive local times, read as UTC.

  • Tests: campaign tests added to test_run_export_arena.py.
  • Size/complexity triggers crossed: none
  • Observable effect: see What changes and Known limitations.
  • Breaking changes: no
  • PR addresses single concern: yes

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Code metrics gate: PASSED

Judged: the 6 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 68 +0
Cognitive complexity fails > 30 0 0 0 274 +0
Function length (lines) fails > 80 0 0 0 412 +0
Nested block depth fails > 5 0 0 0 25 +0
Parameter count fails > 5 0 0 0 95 +0
Module length (lines) warns > 800, fails > 1200 0 0 0 51 +0
Duplicated lines per file fails > 0 0 0 0 97 +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
105 findings in files this change does not touch

Outside this change (informational): 105

Unit Dimension Baseline Now
src/hyperloom/orchestrator/enablement/recipe/projections.py project_launch_evidence Cognitive complexity absent 36
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/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 170
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 91
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 184
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 169

...and 80 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.

@amd-ama10002-2 amd-ama10002-2 added the run-forge-e2e Run the single-GPU Forge e2e smoke on this PR (again on every new commit while set) label Oct 16, 2026
@amd-ama10002-2
amd-ama10002-2 requested a balanced review from Copilot October 16, 2026 23:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Campaign exports can overwrite original source timings and omit valid implementer and planner transcripts.

4 open issues
What changed in this PR

Extends kernelforge export-runs to collect AgentKernelArena campaigns for Hyperloom’s Experience KB under the launcher’s run identity.

Changes:

  • Discovers campaign logs before plain forge-loop artifacts.
  • Enriches iterations with archives, agent transcripts, identity, and provenance.
  • Adds campaign tests and updates exporter documentation.
File Description
src/​kernelforge/​tests/​test_run_export_arena.py Adds campaign export coverage.
src/​kernelforge/​run_export/​document.py Integrates campaign discovery.
src/​kernelforge/​run_export/​command.py Updates CLI help.
src/​kernelforge/​run_export/​arena.py Implements campaign parsing and enrichment.
docs/​reference/​experience-kb-collect.md Documents campaign planner transcripts.
docs/​kernelforge/​reference/​cli.md Documents campaign export support.

Review effort: Balanced

Comment thread src/kernelforge/run_export/arena.py Outdated
Comment thread src/kernelforge/run_export/arena.py Outdated
Comment thread src/kernelforge/run_export/arena.py Outdated
Comment thread src/kernelforge/run_export/arena.py Outdated
@amd-ama10002-2

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions

Copy link
Copy Markdown

Automated review started for head 7c09f21. Progress: https://github.com/AMD-AGI/Hyperloom/actions/runs/38980864196

@github-actions

Copy link
Copy Markdown

Automated review: no verdict applied -- the review job ended with result 'failure'. Comment /review to retry. Run: https://github.com/AMD-AGI/Hyperloom/actions/runs/38980864196

@amd-ama10002-2
amd-ama10002-2 force-pushed the feat/kernelforge-export-runs-arena-campaign branch from 7c09f21 to f9e237b Compare October 16, 2026 23:35
@amd-ama10002-2
amd-ama10002-2 force-pushed the feat/kernelforge-export-runs-arena-campaign branch 2 times, most recently from ab6ac35 to 2e6b440 Compare October 17, 2026 01:00
@amd-ama10002-2
amd-ama10002-2 force-pushed the feat/kernelforge-export-runs-arena-campaign branch from b87fc25 to 13c3c72 Compare October 17, 2026 02:31
@amd-ama10002-2

Copy link
Copy Markdown
Collaborator Author

PR #1951 -- feat(kernelforge): export-runs reads AgentKernelArena campaign logs

What it does: kernelforge export-runs used to export an AgentKernelArena campaign's artifacts directory as a plain forge-loop run under its campaign_id, without the launcher's run name, the PORT step or most of its agents' transcripts. A campaign-log layout in src/kernelforge/run_export/arena.py, which document._root_runs runs before the plain reader, now exports the PORT step and each iteration under the launcher's run name, with fields from KernelForge's archive and the implementer's transcript and with the round's planner transcripts as raw logs, and claims the campaign's log, artifacts directory and transcripts so no other layout reads them again.

Blocking issues: none

SKIPPED: V4 -- # PARTIAL: #1032 changes 1075 files, only its first 100 were compared, overlap there unchecked
SKIPPED: V4 -- # PARTIAL: #1154 changes 1232 files, only its first 100 were compared, overlap there unchecked
SKIPPED: V4 -- # PARTIAL: #1276 changes 1311 files, only its first 100 were compared, overlap there unchecked
SKIPPED: V4 -- # PARTIAL: #1675 changes 161 files, only its first 100 were compared, overlap there unchecked
SKIPPED: V4 -- # PARTIAL: #1869 changes 336 files, only its first 100 were compared, overlap there unchecked
SKIPPED: V4 -- # PARTIAL: #1922 changes 130 files, only its first 100 were compared, overlap there unchecked

Checked: src/kernelforge/run_export/ (arena, archive, document, forge_loop, session_log, units, files, command), orchestrator/agent.py, orchestrator/summary_line.py, loop/runner.py (_lane_prompt, _implementer_history), hyperloom_kb mapping kernelforge-v1 and declaration kernelforge-run-v1, hyperloom_kb/collect/engine.py; tree-wide sweep for every non-test writer and reader of the claimed set and of read_transcript/is_transcript | Ran: fetch.sh; pytest test_run_export_arena.py, test_run_export.py, test_collect_kernelforge.py at head (83 passed); the new transcript-claim test at 13c3c72 (2 failed) and at head (passed); normalize on a campaign beside one and two log-less campaigns at head; ruff check and format, lint-imports (7 kept), code-metrics gate against the base (passed), pr_hygiene size (306 lines); ruff C901 (10, 20) and PLR0913 (5) at head and base; CI at head: 31 check runs success, 2 skipped (main-only), docs build success | Base: 78558a9 | Head: 8c0e9c5

LGTM

@amd-ama10002-2
amd-ama10002-2 marked this pull request as ready for review October 17, 2026 03:17
@amd-ama10002-2
amd-ama10002-2 requested a review from a team as a code owner October 17, 2026 03:17
amd-ama10002-2 and others added 4 commits October 19, 2026 17:28
An AgentKernelArena campaign keeps its launcher's log under logs/, next
to the run's KernelForge artifacts directory
(<workspace>/<run>/<task>-forge-<id>/engine/forge_experiments) and the
Claude Code transcripts of its agents. export-runs read that artifacts
directory as a plain forge-loop run, under the config's campaign_id and
the engine/ path instead of the launcher's run name.

A campaign log that names a KernelForge artifacts directory is now one
run, every unit under the launcher's run name. An iteration's fields
also come from KernelForge's archive of it, from the implementer's
messages in the transcript of the session that produced its candidate,
linked by its path under the log root, and from the reasoning log that
session kept beside its plan. The transcripts of the round's planners
are raw logs of the run. The artifacts directory a campaign log claims
is not read again as a plain forge-loop run.

Observable effect: `kernelforge export-runs` on AgentKernelArena
campaign logs writes each iteration under the launcher's run name with
its implementer's transcript and the round's planner transcripts as raw
logs; before, the same iterations came out as a plain forge-loop run
under the campaign_id, with no planner transcripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
…implementer, planners and source time

Four ways the AgentKernelArena campaign reader dropped or replaced
evidence KernelForge had written for an iteration.

An implementer runs in its kernel's directory, so the implementer of a
kernel at the workspace root shares the planners' working directory, and
the reader filed it as a planner: its iteration lost the transcript's
reasoning, PLAN headline and reasoning_file. A session in the workspace
itself is now an implementer when its prompt names a reasoning log or
ends with the line KernelForge ends every implementer's prompt with. An
iteration first takes the sessions told to keep the reasoning log beside
its plan, the link a plain forge-loop run already uses, and only then
the plan marker and time window that runs made before reasoning logs
need.

A lane's transcript was matched by its plan's first heading, and a lane
plan is free Markdown, so a plan without a heading matched nothing. Such
a plan is now matched whole; the lane's prompt holds it verbatim.

For a forge-rewrite campaign, source_ms took the archive's baseline over
the original kernel's time that forge-rewrite logged as its source
baseline; for a run state that records no pristine baseline, the
archive's is the time of the port the forge-loop started from. The
logged source baseline now wins, and the archive's is the fallback.

A fan-out round plans its lanes together and measures them in later
iterations, but planner transcripts were taken from the measuring
iteration's time window, so every lane after the first lost its round's
planners. They now come from the round whose orchestration/iter_NNN
holds the candidate's plan, shared by every candidate of that round.

Observable effect: `kernelforge export-runs` on an AgentKernelArena
campaign gives the implementer of a kernel at the workspace root, and
the lane that ran a plan without a heading, their transcript's
reasoning, PLAN headline and rationale.reasoning_file again; such a lane
from a run that kept no reasoning log had no reasoning at all, so
collection skipped it. A forge-rewrite campaign's iterations report the
original kernel's logged time as source_ms instead of the port's. Every
lane of a fan-out round lists that round's planner transcripts in its
raw logs, in place of whichever planners ran while it was measured.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ut of the plain runs beside it

The AgentKernelArena campaign reader claimed its log and its KernelForge
artifacts directory but not the Claude Code transcripts of its agents,
so the plain forge-loop reader read them again. That reader gives a
transcript whose prompt names a reasoning log to the plain run whose
workspace path ends most like the log's, and an arena workspace always
ends in engine: another campaign whose log is missing, or a plain run
made in a directory named engine, took the campaign implementer's
transcript, and two such runs made the transcript fit both equally
well. The campaign now claims the transcripts it read, as the document
promises for every file a layout reads.

Observable effect: `kernelforge export-runs` on a log root that holds
an AgentKernelArena campaign log beside another KernelForge run read as
a plain forge-loop run (another campaign without its log, or a plain run
in a directory named engine) no longer gives that run's Experience the
campaign implementer's transcript, PLAN headline, reasoning and
rationale.reasoning_file, and no longer stops with "fits the runs in ...
equally well" when two such runs are there; each transcript stays with
the campaign that ran it.

Co-authored-by: Cursor <cursoragent@cursor.com>
… launches as one campaign

AgentKernelArena writes one launcher log for every task of a run, and a
resumed run appends to the same log: its runner launches each task
under the same logger, the forge adapter logs "Forge artifacts: <dir>"
at every launch, and each engine's output comes through as [FORGE]
lines. The campaign reader took the first artifacts line and read the
whole log as that launch's, while the session log reader keeps the last
source baseline and PORT lines it sees, so the first launch's PORT unit
took a later launch's decision, and every one of its units took a later
launch's source baseline as source_ms, which also wins over the
archive's value.

A campaign log that names more than one artifacts directory is now one
unit saying so, and each of those directories is read as a plain
forge-loop run, as it is without the campaign layer.

Observable effect: `kernelforge export-runs` on the log of an
AgentKernelArena run of several tasks, or of a resumed run that
launched KernelForge again, writes one entry naming the artifacts
directories, which collection skips with that reason, and each
launch's iterations as a plain forge-loop run under its campaign_id;
before, the first launch's PORT step and iterations came out under the
launcher's run name with another launch's source_ms and PORT decision.

Co-authored-by: Cursor <cursoragent@cursor.com>
@amd-ama10002-2
amd-ama10002-2 force-pushed the feat/kernelforge-export-runs-arena-campaign branch from b312a44 to 18d8a9f Compare October 19, 2026 17:35
@amd-ama10002-2
amd-ama10002-2 added this pull request to stack #2031 October 19, 2026 17:57
@amd-ama10002-2

Copy link
Copy Markdown
Collaborator Author

Superseded by #2037: the four stacked PRs were combined into one PR at the reviewer's request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-forge-e2e Run the single-GPU Forge e2e smoke on this PR (again on every new commit while set)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants