Skip to content

refactor(kernelforge): delete the re-checks and re-reads in the Analysis service's checkpoint, published-evidence and bundle paths - #2080

Merged
chaojhou merged 8 commits into
mainfrom
lean/shafeng/cc20-kf-orch-analysis-pr
Oct 22, 2026
Merged

chaojhou merged 8 commits into
mainfrom
lean/shafeng/cc20-kf-orch-analysis-pr

Conversation

@fengshaoyi-amd

@fengshaoyi-amd fengshaoyi-amd commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What this does

Three methods of AnalysisAgentService in src/kernelforge/orchestrator/analysis.py were over the code-metrics gate: apply_checkpoint, apply_published_evidence and ensure_bundle. This PR deletes what they re-checked or re-read: checks _validate_bundle already makes, second reads of manifest.json, workflow.json and request.json for values already in hand, guards on inputs no caller produces, and a case-tuple block written three times. The checkpoint path now reads bottleneck.json through the shared _case_bottleneck, which also accepts a file that is not UTF-8.

Production code: +222 / -350 lines (net -128) in 1 file. Tests: +13 / -0 in 1 file. Code-metrics baseline: 5 entries retired, 2 lowered, none added.

What changes

  • apply_published_evidence: the manifest read and the commit and digest checks _validate_bundle makes first are deleted, with a canonical-commit override _validate_bundle never reads and a trailing replace() of fields AnalysisBundle.apply already sets.
  • apply_checkpoint: is_file() checks before reads that fail with OSError anyway and a second identical handler around request.json are deleted; _checkpoint_case_evidence builds a case's evidence from the checkpoint and reads its bottleneck.json through _case_bottleneck.
  • ensure_bundle: the re-reads of manifest.json, workflow.json and request.json after publishing are deleted, since the values come from the validated bundle and the journal that wrote them, with duplicate CancelledError and AnalysisAttemptLimitError handlers and a hand-rebuilt AnalysisBundle. _stage_request, _stage_incremental_diff and _publish_session_bundle are its staging and publishing steps.
  • _analysis_cases builds the case tuple once, replacing three copies.

Functions brought under the gate

Baseline entries this PR retires, with their values at base:

  • analysis.py: AnalysisAgentService.apply_checkpoint (cognitive 39, lines 138); AnalysisAgentService.ensure_bundle (cognitive 39, lines 219); AnalysisAgentService.apply_published_evidence (lines 96)

Baseline entries this PR lowers:

  • AnalysisAgentService._run_analysis_session lines: 101 → 94
  • analysis.py module lines: 2,080 → 1,952

Observable effect

A malformed bottleneck.json in an Analysis case no longer fails the Analysis service:

  • On the checkpoint path, a file holding valid JSON that is not an object used to raise AttributeError out of apply_checkpoint; the case now keeps the bottleneck it had.
  • When a bundle is validated, a completed case's file that is not valid UTF-8 used to raise UnicodeDecodeError; it now reads as an empty bottleneck, as an unreadable or invalid one already did.

Bundles, generations, request, workflow and catalog files, recorded outcomes and log lines are otherwise the same for every input the repo's own callers produce. Inputs that no in-repo caller produces now behave differently:

  • apply_published_evidence with a padded or non-string evidence_commit. A padded value no longer matches a bundle, so the context comes back unchanged; a non-string value raises TypeError. The only production caller passes the bare commit hash stored in run_state.analysis.evidence_commit.
  • apply_published_evidence when source_map.md disappears after validation. The stale source-map reference is included instead of left out.
  • apply_checkpoint when workflow.json or artifact_catalog.json is a FIFO or a device. It reads the file, and a FIFO blocks; the framework writes both by atomic replace.
  • apply_checkpoint with a catalog path containing a NUL byte. It raises ValueError instead of skipping the entry.
  • ensure_bundle when a bundle file changes between validation and publication. The published status, attempt count and tier come from the values validation checked and the journal that wrote them, not from a re-read.

Checklist

  • Linked issue(s): none.
  • Tests: in test_analysis_agent.py, the _SourceThenFailBackend fixture also writes a case's analysis.md and a bottleneck.json holding a JSON array, and test_partial_checkpoint_is_exposed_as_orchestration_evidence now asserts that such a checkpoint is still exposed, with the case's original bottleneck, its partial analysis and the interpretation-only flag. No other test changed. Linux CI is green at head 53d1339bb.
  • Size/complexity triggers crossed: 572 changed production lines in one file, over the 400-line review trigger and under the 1,000-line limit. The one changed function over a gate limit is _run_analysis_session: it was over the 80-line limit at base, changes only where its copy of the case tuple became _analysis_cases, and its baseline entry is lowered from 101 to 94 lines (cyclomatic 11, as at base). Over the 60-line review trigger and within the gate, each one ordered sequence: ensure_bundle (79 lines) and apply_checkpoint (77). analysis.py stays over the 1,200-line module limit it was already over; its baseline entry is lowered from 2,080 to 1,952 lines.
  • If this simplifies or refactors: the mechanisms removed are listed under What changes; bundles, generations, their files and every in-repo caller keep their contract, shown by the Analysis service suite and the checkpoint assertions above.
  • Observable effect: a malformed bottleneck.json no longer fails the Analysis service; nothing else changes for in-repo callers. See Observable effect.
  • Breaking changes: no. _bundle_from_published_checkpoint drops its requested_tier parameter and _protected_paths takes the AnalysisSources instead of separate paths; both are private.
  • PR addresses single concern: yes, bringing the Analysis service's three over-gate methods under the gate; the bottleneck.json change is in the shared read those methods now use.
  • Root cause is upstream: no.

Commits

Squash-merged as 421191de3 from head 53d1339bb.

  • 5ae575fbc refactor(analysis): restore published evidence through the bundle validator
  • 4f9aa18bc refactor(analysis): read checkpoint metadata in one pass
  • c842a5f76 refactor(analysis): stop ensure_bundle re-reading the bundle it validated
  • f0fa2d510 refactor(analysis): name the staged incremental diff file once
  • 124a9e1ad refactor(analysis): lower the analysis.py code-metrics baseline
  • 20ec02642 fix(kernelforge): share checkpoint bottleneck parsing
  • plus 2 merges of origin/main

fengshaoyi-amd and others added 5 commits October 21, 2026 11:48
…idator

apply_published_evidence re-checked the manifest commit and digests before
handing the same files to _validate_bundle, which already rejects every one
of those mismatches first, before it reads any case or writes provenance.
The pre-checks are gone, and the result is built by AnalysisBundle.apply,
which already sets canonical_commit, evidence_commit, evidence_stale and the
speedup and cumulative-diff fields the trailing replace() re-assigned to the
same values. Only the stale branch rebuilds anything now.

The canonical-commit override on the validation context is dropped:
_validate_bundle reads only its analysis_commit and cases.

The case-tuple construction repeated in ensure_bundle, _run_analysis_session
and apply_published_evidence becomes _analysis_cases().

evidence_commit is no longer stripped or coerced: every writer of
run_state.analysis.evidence_commit stores a bare commit hash.

Co-authored-by: Cursor <cursoragent@cursor.com>
apply_checkpoint checked that workflow.json and artifact_catalog.json were
regular files before reading them, then read request.json under a second,
identical handler. A missing or unreadable file already fails the read with
OSError, so the three reads share one handler and the shape checks become one
condition. TypeError and JSONDecodeError left the handlers: nothing in them
raises the first, and the second is a ValueError.

The per-case flagging moves to _checkpoint_case_evidence, beside the
_completed_ and _skipped_case_evidence helpers it mirrors. Its bottleneck read
suppresses the same errors and keeps the case's own bottleneck on failure, as
the reassignment in the old handler did.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ated

After publishing a generation, ensure_bundle read manifest.json,
workflow.json and request.json back from disk although every value it took
from them was already in hand: the manifest status is in the bundle
_validate_bundle returned for the staging root, the attempt count is in the
journal that just wrote workflow.json, and the request's profiling flag adds
nothing to completed_case_ids, which validation already rejects for a
static-only request. The final AnalysisBundle rebuild becomes
replace(validated, outcome=...).

The final_root.is_dir() guard before _published_generation_root goes: the
resolver returns None for a missing or non-directory commit root.
_bundle_from_published_checkpoint derives requested_tier from
profiling_enabled instead of taking it as a parameter, _protected_paths takes
the AnalysisSources it used to receive unpacked, the kernel path is resolved
once, and the CancelledError and AnalysisAttemptLimitError handlers, which did
the same thing, share one clause. The rebinding of request_payload to the
durable request was never read.

What is left moves into three steps named for their job:
_stage_incremental_diff, _stage_request and _publish_session_bundle. The order
of every write, git call and raise is unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
Staging the incremental diff and writing the request are separate steps now,
and each built the diff path from its own copy of the file name, as
_session_outputs did. _INCREMENTAL_DIFF_FILE is the one spelling the three
share.

Co-authored-by: Cursor <cursoragent@cursor.com>
apply_checkpoint, apply_published_evidence and ensure_bundle are within the
cognitive and function-length limits, so their five entries go.
_run_analysis_session is 94 lines and the module 1953.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Code metrics gate: PASSED

Judged: 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.

Dimension Limit New Worse Baseline out of date Baseline entries vs base
Cyclomatic complexity fails > 20 0 0 0 45 +0
Cognitive complexity fails > 30 0 0 0 168 -2
Function length (lines) fails > 80 0 0 0 312 -3
Nested block depth fails > 5 0 0 0 19 +0
Parameter count fails > 5 0 0 0 89 +0
Module length (lines) warns > 800, fails > 1200 0 0 0 47 +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
90 findings in files this change does not touch

Outside this change (informational): 90

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/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 107
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/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/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
src/hyperloom_kb/http_service.py Module length (lines) absent 1525
src/kernelforge/cli/forge_loop_command.py Module length (lines) absent 2003
src/hyperloom/orchestrator/actions/executors/_geak_sweep.py sweep_via_geak Cognitive complexity 67 70
src/hyperloom/orchestrator/actions/executors/_grid_runner.py run_grid Cognitive complexity 177 180
src/hyperloom/orchestrator/actions/executors/explore.py ExploreExecutor.__call__ Cognitive complexity 369 383
src/hyperloom/orchestrator/kernel/request_handlers.py _run_forge_gemm_tuning Cognitive complexity 124 125
src/hyperloom/orchestrator/phases/kernel.py KernelPhase._run_geak_kernel_phase Cognitive complexity 122 130
src/hyperloom/orchestrator/phases/prelude.py PreludePhase.maybe_enqueue_warm_replay Cognitive complexity 190 191
src/hyperloom/orchestrator/actions/executors/_grid_runner.py run_grid Cyclomatic complexity 55 56

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

@fengshaoyi-amd fengshaoyi-amd changed the title refactor(forge-loop): delete the re-checks and re-reads in the Analysis service's checkpoint, published-evidence and bundle paths refactor(kernelforge): delete the re-checks and re-reads in the Analysis service's checkpoint, published-evidence and bundle paths Oct 21, 2026
@fengshaoyi-amd
fengshaoyi-amd marked this pull request as ready for review October 21, 2026 06:46
@fengshaoyi-amd
fengshaoyi-amd requested a review from a team as a code owner October 21, 2026 06:46

@ZhengGong-amd ZhengGong-amd 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.

Please reconsider one point before merge.

  1. The new _checkpoint_case_evidence (src/kernelforge/orchestrator/analysis.py:1830-1832) carries its own read of bottleneck.json (with a new contextlib.suppress and import contextlib), while the owner _case_bottleneck (:1856) sits next to it. The two already diverge: a JSON array in bottleneck.json makes this copy raise AttributeError and fails the whole apply_checkpoint, while _case_bottleneck returns {}. The inline copy predates this PR, but a PR whose goal is deleting repeated code should not wrap it into a new function. AGENTS.md Clean design.
    Action: bottleneck = str(self._case_bottleneck(bottleneck_path).get("classification") or original.bottleneck), drop contextlib, and note in the description that a non-object bottleneck.json no longer fails apply_checkpoint.

fengshaoyi-amd and others added 3 commits October 21, 2026 19:20
Co-authored-by: Cursor <cursoragent@cursor.com>
…orch-analysis-pr

Co-authored-by: Cursor <cursoragent@cursor.com>
…orch-analysis-pr

Co-authored-by: Cursor <cursoragent@cursor.com>
@fengshaoyi-amd

Copy link
Copy Markdown
Contributor Author

Addressed the review.

_checkpoint_case_evidence now calls AnalysisAgentService._case_bottleneck (class-qualified because the caller is a staticmethod). A non-object or unreadable checkpoint bottleneck.json no longer fails apply_checkpoint; the completed-case path also tolerates non-UTF-8 the same way. Covered by extending the partial-checkpoint test with a JSON-array payload. Gate passes.

@fengshaoyi-amd
fengshaoyi-amd requested review from ZhengGong-amd and removed request for ZhengGong-amd October 22, 2026 02:19

@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 #2080 -- refactor(kernelforge): delete the re-checks and re-reads in the Analysis service's checkpoint, published-evidence and bundle paths

What it does: Three AnalysisAgentService methods in src/kernelforge/orchestrator/analysis.py -- apply_checkpoint, apply_published_evidence and ensure_bundle -- were over the code-metrics cognitive-complexity and function-length gates because they re-ran checks _validate_bundle already makes and re-read manifest.json, workflow.json and request.json for values that were already in hand. The PR deletes those duplicates, extracts five single-call-site helpers (_analysis_cases, _checkpoint_case_evidence, _stage_incremental_diff, _stage_request, _publish_session_bundle), lets the validated bundle and the session journal supply the manifest status, attempt count and digests, and lowers the two remaining baseline entries. A follow-up commit routes the checkpoint path through the shared _case_bottleneck so a non-dict or non-UTF-8 bottleneck.json no longer escapes as an uncaught exception.

Blocking issues: 1

  1. [X2] The PR description is pinned to commit f0fa2d510, not to head 53d1339bb [verified]
    Problem: the Checklist states "No test is added, changed or deleted", but the head diff changes src/kernelforge/tests/test_analysis_agent.py (+13/-0): the _SourceThenFailBackend fixture now writes analysis.md and bottleneck.json, and test_partial_checkpoint_is_exposed_as_orchestration_evidence gained three assertions. Three stated counts belong to the earlier commit as well -- "Production code: +222 / -349 (net -127)" and "2,080 -> 1,953" (head is 222 350, net -128, and analysis.py is 1952 lines; it was 1953 at f0fa2d510 and 1952 after 20ec02642), the Gate section reports a pass "on the 2 touched files" when three files are touched, and the commit table lists five commits while the branch carries six. scripts/code_metrics_baseline.txt:762 already carries the correct 1952.
    Impact: a reviewer checking the "contract preserved, no test changed" claim against the diff finds a test change the description denies, and the release cut aggregates this description.
    Action: refresh the Checklist's Tests line, the production-line counts, the module-length figures, the touched-file count and the commit table against head 53d1339bb.

Checked: src/kernelforge/orchestrator/analysis.py (ensure_bundle, _stage_incremental_diff, _stage_request, _publish_session_bundle, _bundle_from_published_checkpoint, apply_checkpoint, apply_published_evidence, _checkpoint_case_evidence, _case_bottleneck, _completed_case_evidence, _validate_bundle, _validated_manifest, _validated_session_metadata, _published_generation_root, _tier_label, AnalysisBundle.apply), src/kernelforge/orchestrator/analysis_session.py (AnalysisSessionJournal.attempts, finalize), src/kernelforge/loop/analysis_runtime.py:80-100, scripts/code_metrics_baseline.txt, src/kernelforge/tests/test_analysis_agent.py | Ran: direct call of _checkpoint_case_evidence with bottleneck.json = "[]" and with a valid object; per-commit wc -l of analysis.py across bb2da63..53d1339; pathlib glob-over-missing-directory check; pytest -k partial_checkpoint_is_exposed (fails on this Windows host inside durable_io.fsync_directory, the platform limitation the body documents -- Linux CI is green at head) | Base: bb2da63 | Head: 53d1339
SKIPPED: Step 7 independent reader -- no second agent or person available; the finding was re-derived from the artifacts alone instead.

@chaojhou
chaojhou dismissed ZhengGong-amd’s stale review October 22, 2026 03:44

Verified at 53d1339: the checkpoint path reads bottleneck.json through _case_bottleneck (20ec026), contextlib is gone. CI green, merges cleanly with main. xiaofei-zheng's review on this head (description pinned to f0fa2d5) is a separate open item.

@chaojhou chaojhou 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.

Verified at 53d1339: the checkpoint path reads bottleneck.json through _case_bottleneck and contextlib is gone. Every review item on the code is fixed, CI is green and the branch merges cleanly with main.

Before or right after merge, please refresh the PR description against this head (line and module counts, commit table, and the statements xiaofei-zheng / ZhengGong-amd listed): the release notes are built from it.

LGTM

@chaojhou
chaojhou merged commit 421191d into main Oct 22, 2026
42 checks passed
@chaojhou
chaojhou deleted the lean/shafeng/cc20-kf-orch-analysis-pr branch October 22, 2026 05:02
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.

4 participants