Skip to content

feat(lvs): add compare_timeout_s deadline and stderr heartbeat for large compares - #4166

Merged
loom-fleet-dispatch[bot] merged 1 commit into
mainfrom
feature/issue-4165
Oct 25, 2026
Merged

loom-fleet-dispatch[bot] merged 1 commit into
mainfrom
feature/issue-4165

Conversation

@loom-fleet-dispatch

@loom-fleet-dispatch loom-fleet-dispatch Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

klt lvs on very large flat compares could run for tens of minutes with no output. This adds an opt-in deadline (options.compare_timeout_s) that yields a structured inconclusive report (exit 4), plus a stderr heartbeat. Native hierarchical compare and ambiguity stats stay out of scope, as the issue specified.

Changes

  • lvs_timeout.py (new): option parsing, forked-child deadline runner, heartbeat.
  • lvs.py: _compare_netlists takes a timeout and context; on expiry the report is status: "inconclusive" with one compare.timeout entry (details.code: "compare_timeout", elapsed time, device/net/pin counts). The option is echoed and replayed by --rerun only when set.
  • Docs ("Large flat designs" section with the manual per-cell recipe, option row), response schema, CHANGELOG, import-boundaries entry.

Acceptance Criteria Verification

  • Timeout gives inconclusive, compare_timeout diagnostic, exit 4, no leftover child: test_compare_timeout_reports_inconclusive_issue_4165 (asserts multiprocessing.active_children() == []).
  • Option omitted leaves output unchanged; value not reached matches the untimed run: test_compare_timeout_not_reached_matches_untimed_issue_4165.
  • Invalid values (0, -1, string, bool, NaN) are request errors: test_compare_timeout_invalid_value_rejected_issue_4165.
  • Heartbeat goes to stderr only; stdout is valid JSON: test_compare_heartbeat_goes_to_stderr_only_issue_4165.

Test Plan

TDD: tests written alongside the implementation, not before it. Ran the new tests and the existing inconclusive/rerun/internal-error tests in tests/test_lvs.py, plus ruff, check_complexity_baseline.py and check_import_boundaries.py. Full suite left to CI.

Live verification NOT performed. The ~50k-device repro was not run; tests use a patched slow compare. Known trade-offs:

  • A compare that finishes inside the budget is repeated in-process, because the comparer's logger holds native objects that can't cross a process boundary. A run near the limit can take up to 2x its compare time, which is why the option is opt-in.
  • Without the timeout option the heartbeat comes from a thread and is best effort. It depends on the native compare releasing the GIL, which I did not verify.

Closes #4165

🤖 Generated with Claude Code

loom dashboard

…rge compares

The klayout engine's NetlistComparer.compare() is one blocking native call, so
a ~50k-device flat compare could run for tens of minutes with no signal. The
opt-in options.compare_timeout_s runs the compare in a killable forked child
and reports status inconclusive (exit 4) with a compare.timeout entry on
expiry; a stderr heartbeat reports elapsed time and sizes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@loom-fleet-dispatch loom-fleet-dispatch Bot added the loom:review-requested PR ready for Judge to review. Applied by: Builder when opening PR. label Oct 25, 2026
@loom-fleet-dispatch

loom-fleet-dispatch Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor Author

PR #4166's loom:reviewing claim is held by the judge of sweep step-judge-4166-1792971733 on host host-d0749b00. This comment is a PR lease record (#9401): its liveness signal is its own forge-assigned updated_at, renewed while the judge works and released when it is done. Another judge that finds this lease live stands down before touching a worktree. See defaults/docs/lease-record.md § "PR-phase leases".

@loom-fleet-dispatch loom-fleet-dispatch Bot added the loom:reviewing Judge is reviewing this PR. Applied by: Judge only. Stale after LOOM_STALE_REVIEWING_MINUTES (30m). label Oct 25, 2026
@loom-fleet-dispatch

Copy link
Copy Markdown
Contributor Author

✅ Approved!

CI is green on this head (forge wait-checks: GREEN); merge state CLEAN; no formal reviews or inline threads outstanding (check-review-feedback.sh: CLEAR).

Reviewed

  • lvs_timeout.py: option parsing rejects 0/negative/NaN/inf/bool/string and non-klayout engines as request errors. The forked child is terminated, then killed, then joined on every exit path. Child failure or EOF becomes an LvsError, never a verdict.
  • lvs.py: _guarded_compare turns a timeout into a single compare.timeout mismatch and status inconclusive. In the parameter_tolerance path the logger is empty after a timeout, so no snaps are collected and the loop exits without a second compare. The option is echoed and replayed by --rerun only when set, so output without it is unchanged.
  • Docs, response schema, CHANGELOG and the import-boundaries entry are consistent with the code.

Test execution

  • pytest tests/test_lvs.py -k "4165 or 4134" → 11 passed (run locally in the builder worktree).
  • Full suite not run locally; relying on green CI.

Not verified (as the PR itself discloses)

  • The ~50k-device repro was not run live. The tests patch a slow compare, so the 2x cost of a compare that finishes inside the budget and the thread-heartbeat GIL behaviour of the native compare are untested. Neither blocks: the option is opt-in, the heartbeat is documented best-effort, and the fork-based timeout path does not depend on the GIL. This is not an issue-silent-omission shape, so the circular-fixture rule does not apply.

loom dashboard

@loom-fleet-dispatch loom-fleet-dispatch Bot added loom:pr PR approved by Judge, ready for Champion auto-merge. Applied by: Judge. and removed loom:review-requested PR ready for Judge to review. Applied by: Builder when opening PR. loom:reviewing Judge is reviewing this PR. Applied by: Judge only. Stale after LOOM_STALE_REVIEWING_MINUTES (30m). labels Oct 25, 2026
@loom-fleet-dispatch

loom-fleet-dispatch Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor Author

PR #4166's (no label: the lease is the claim) claim is held by the champion of sweep step-champion_merge-4166-1792971853 on host host-d0749b00. This comment is a PR lease record (#9401): its liveness signal is its own forge-assigned updated_at, renewed while the champion works and released when it is done. Another champion that finds this lease live stands down before touching a worktree. See defaults/docs/lease-record.md § "PR-phase leases".

@loom-fleet-dispatch

Copy link
Copy Markdown
Contributor Author

Champion: merging. All 6 safety criteria pass on head b3c6ebe: Judge approval fresh (verdict SHA matches head), merge-risk low (opt-in option, additive, tests cover timeout/invalid/stderr; no critical files), mergeable CLEAN, CI all green.


Automated by Champion role

loom dashboard

@loom-fleet-dispatch
loom-fleet-dispatch Bot merged commit 427dea1 into main Oct 25, 2026
24 checks passed
@loom-fleet-dispatch
loom-fleet-dispatch Bot deleted the feature/issue-4165 branch October 25, 2026 23:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

loom:pr PR approved by Judge, ready for Champion auto-merge. Applied by: Judge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

klt lvs: no progress, timeout or hierarchical option on ~50k-device flat compares

0 participants