docs(agent-handoff): Restore Root and Pendulum Handoffs to Current State - #4514
Merged
Conversation
Both documents had drifted far enough to actively misdirect the next agent, and the root document had also outgrown its own policy by 18x. CLAUDE.md requires handoff docs to be current-state only and at most 150 lines, with history in git. The root doc had instead accumulated 137 dated entries across 2,708 lines. Those entries are moved verbatim to docs/agent_handoff_archive/2026-08_tools_root_handoff_log.md, not deleted — the archived body is byte-identical to the original (165,356 chars, 137 entries), so no working-tree context is lost. The live doc is now 132 lines and carries an explicit do-not against appending dated entries again. Content corrections. The root doc presented PR #4119 as open with auto-merge armed and #4124/#4129 as open drafts stacked on it; in fact #4119 closed without merging and #4124/#4129 both merged. Epics #4142 and #4433 were absent entirely. Delivery has shifted from stacked PRs to scoped consolidations rebuilt onto current main. It now records the seven live epics, the four open consolidations (#4446, #4447, #4449, #4466) as the real queue, and the fact that 39 of 58 open PRs are codex/4142-* / codex/4433-* drafts superseded by merged #4473 — whose own description says so. Those should be triaged and closed, not rebased. The pendulum doc described issue #4406 as active on branch research/shoulder-velocity-drift-transfer. #4406 is closed and shipped via consolidation #4450. It now records what landed, keeps the fail-closed triple/golfer tier boundary as an explicit do-not, and points at the UpstreamDrift #8684 qualification state — including the finite-ground result where the preregistered screen admitted 0 of 384 cells, so a moving base is not a free upgrade for the higher tiers. Also recorded: the four pre-existing ruff format failures under src/data_processing/ that are on main and should not be absorbed into an unrelated PR, and the --regenerate-api-baseline trap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
dieterolson
pushed a commit
that referenced
this pull request
Aug 17, 2026
…e-base wall Repo policy is to update the handoff with every PR, and two things changed since #4514 landed. The 39 codex/4142-* / codex/4433-* drafts are now closed as superseded by merged #4473, which says so in its own description. Open PRs went 58 -> 21 and drafts 39 -> 0. Their work is verifiably on main: the Morris chain as application/morris/{host,client,contracts}.py, the #4433 chain as the flight, putting, plot, visual-state and tab-audit modules. Their branches are left intact, so the guidance is now reopen-rather-than-rebase — those branches have diverged far enough that merging one would remove current main content. #4466 turns out not to be mergeable at all. After #4473 squash-merged, the shared merge-base collapses to a commit predating src/rate_of_closure/, making every overlapping file a both-added conflict with no common ancestor (281 of them). #4517 is landing it as standalone slices instead, starting with swing_sim.ground. The other consolidations should expect the same wall, so the roadmap now says slice rather than merge. Also added a do-not against per-file Python version guards, pointing at the conftest floor guard that replaces them. Handoff remains within the 150-line policy at 144. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dieterolson
pushed a commit
that referenced
this pull request
Aug 17, 2026
…e-base wall Repo policy is to update the handoff with every PR, and two things changed since #4514 landed. The 39 codex/4142-* / codex/4433-* drafts are now closed as superseded by merged #4473, which says so in its own description. Open PRs went 58 -> 21 and drafts 39 -> 0. Their work is verifiably on main: the Morris chain as application/morris/{host,client,contracts}.py, the #4433 chain as the flight, putting, plot, visual-state and tab-audit modules. Their branches are left intact, so the guidance is now reopen-rather-than-rebase — those branches have diverged far enough that merging one would remove current main content. #4466 turns out not to be mergeable at all. After #4473 squash-merged, the shared merge-base collapses to a commit predating src/rate_of_closure/, making every overlapping file a both-added conflict with no common ancestor (281 of them). #4517 is landing it as standalone slices instead, starting with swing_sim.ground. The other consolidations should expect the same wall, so the roadmap now says slice rather than merge. Also added a do-not against per-file Python version guards, pointing at the conftest floor guard that replaces them. Handoff remains within the 150-line policy at 144. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dieterolson
pushed a commit
that referenced
this pull request
Aug 17, 2026
…e-base wall Repo policy is to update the handoff with every PR, and two things changed since #4514 landed. The 39 codex/4142-* / codex/4433-* drafts are now closed as superseded by merged #4473, which says so in its own description. Open PRs went 58 -> 21 and drafts 39 -> 0. Their work is verifiably on main: the Morris chain as application/morris/{host,client,contracts}.py, the #4433 chain as the flight, putting, plot, visual-state and tab-audit modules. Their branches are left intact, so the guidance is now reopen-rather-than-rebase — those branches have diverged far enough that merging one would remove current main content. #4466 turns out not to be mergeable at all. After #4473 squash-merged, the shared merge-base collapses to a commit predating src/rate_of_closure/, making every overlapping file a both-added conflict with no common ancestor (281 of them). #4517 is landing it as standalone slices instead, starting with swing_sim.ground. The other consolidations should expect the same wall, so the roadmap now says slice rather than merge. Also added a do-not against per-file Python version guards, pointing at the conftest floor guard that replaces them. Handoff remains within the 150-line policy at 144. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dieterolson
added a commit
that referenced
this pull request
Aug 17, 2026
… at It (#4516) * fix(ci, tests): enforce the two-tier Python floor instead of guessing at it The `tests (3.10)` lane was running code that requires 3.11, which produced failures that looked like defects and were not. This repo is deliberately two-tier. The root distribution declares requires-python = ">=3.11" (classifiers 3.11/3.12, mypy python_version 3.11), while ten sub-packages and Rust crates declare >=3.10 and ship 3.10 wheels from six maturin workflows. The 3.10 matrix lane exists to validate those sub-packages. But it ran the whole suite, including root-package code such as src/p1am_control_system and src/shared/python. Two failures came from exactly that mismatch: - test_deployment_hardening.py imported tomllib, stdlib only on 3.11+, aborting collection for the entire session (1,218 collected, zero executed). - test_estop_shutdown_safe_state.py timed out because asyncio.wait_for was reimplemented on asyncio.timeouts in 3.11 with different cancellation propagation. Neither is a 3.10 support bug. Both are 3.11-only code being run on 3.10. conftest.py now resolves the nearest pyproject.toml for any collection path, reads its declared requires-python floor, and skips collection when the running interpreter is below it. The floor is read from the declarations rather than hardcoded, so adding a sub-package or moving a floor needs no edit here. requires-python is regex-parsed on purpose: tomllib does not exist on the very interpreter the guard has to run on. It fails closed at (3, 11) when nothing parses. Verified as a strict no-op on 3.11+ — collection is identical at 10,382/10,414 with and without the guard. CLAUDE.md advertised a flat "Python 3.10+" that the root distribution rejects. It now states the real contract, names the ten 3.10 distributions, explains what the 3.10 lane is for, and says not to add per-file version guards because the conftest handles it. tests/test_python_version_contract.py locks the declarations together: requires-python against the mypy target and the classifiers, the CI matrix against the lowest declared floor, CLAUDE.md against the root floor, and a regression guard proving root-package tests are excluded below the floor while 3.10 sub-packages are still collected. The interpreter version is faked so those guards run on every lane, not only the one that cannot execute them. This supersedes the separate investigation into the e-stop shutdown timeout: that test should not run on 3.10 at all, and no shutdown-safety code needed to change. The pytest.importorskip added to test_deployment_hardening.py in #4515 is now redundant but retained deliberately as defense in depth — if this guard ever regresses, a bare import there takes down the whole session again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(agent-handoff): record the closed draft chain and the #4466 merge-base wall Repo policy is to update the handoff with every PR, and two things changed since #4514 landed. The 39 codex/4142-* / codex/4433-* drafts are now closed as superseded by merged #4473, which says so in its own description. Open PRs went 58 -> 21 and drafts 39 -> 0. Their work is verifiably on main: the Morris chain as application/morris/{host,client,contracts}.py, the #4433 chain as the flight, putting, plot, visual-state and tab-audit modules. Their branches are left intact, so the guidance is now reopen-rather-than-rebase — those branches have diverged far enough that merging one would remove current main content. #4466 turns out not to be mergeable at all. After #4473 squash-merged, the shared merge-base collapses to a commit predating src/rate_of_closure/, making every overlapping file a both-added conflict with no common ancestor (281 of them). #4517 is landing it as standalone slices instead, starting with swing_sim.ground. The other consolidations should expect the same wall, so the roadmap now says slice rather than merge. Also added a do-not against per-file Python version guards, pointing at the conftest floor guard that replaces them. Handoff remains within the 150-line policy at 144. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(tests): check each sub-package at its own floor, not the global minimum The 3.11 lane failed on the previous commit with "src/movement_optimizer declares 3.10 support but the guard would exclude it from the 3.10 lane". The guard was not the problem; the test was wrong by construction. test_sub_package_tests_still_run_on_the_lower_lane faked the interpreter to the *minimum* floor across every lower-floored package, then asserted that every one of them would still be collected. That only holds when they all declare the same floor. A single package declaring lower than the rest makes the assertion fail for packages that are being excluded entirely correctly — a 3.10 package is supposed to be excluded on 3.9. Each package is now checked at its own declared floor, which is the property actually worth guarding and is independent of what anything else declares. Two related changes: _below_declared_floor now takes the interpreter version as an optional parameter instead of the tests patching sys.version_info. That patch was process-global and read by unrelated library code, which under xdist meant a test could perturb workers running beside it. test_conftest_reads_each_package_declared_floor now checks every sub-package rather than two hand-picked ones, and reports all mismatches with their paths. Path resolution is the part most likely to differ across platforms, so a failure should name the package instead of surfacing as a confusing assertion further downstream. Also added test_nested_distributions_do_not_widen_their_parent_tree. The diagnostic turned up a real wrinkle: psa_package declares >=3.10 while living inside src/shared/python, which is root-package code. The guard handles it correctly — the nested distribution gets 3.10 and its parent tree stays at 3.11 — but nothing was pinning that, and a regression there would quietly let the lower lane start collecting root code again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ci: allow empty collection on lanes below the root Python floor The floor guard works, and that turned out to be the problem for this PR's own 3.10 lane: pytest exited 5, "no tests collected". On a sub-floor lane the guard excludes root-package code, including the top-level tests/ tree. A change that touches only root-package tests therefore has nothing to run there, and pytest treats an empty selection as an error. The lane failed while behaving exactly as designed. The tests step now tolerates exit code 5, but only on lanes below the root requires-python floor, which is read from pyproject.toml rather than hardcoded so it tracks the declaration. On the required lane exit 5 still fails, which is what keeps the issue #3324 vacuous-selection protection meaningful — that guard exists to catch typo'd or broken test selection, and blanket-tolerating exit 5 everywhere would defeat it. Verified before pushing, since this is a CI workflow change and the previous two rounds of surprises here were self-inflicted: - version comparison: 3.9 and 3.10 allow empty collection, 3.11 and 3.12 do not - tolerance: exit 5 returns 0 when allowed, and passes through unchanged when not - the workflow YAML parses and the extracted run block passes bash -n Deliberately avoided a python heredoc inside the indented YAML block; the floor is parsed with grep instead, because heredoc terminators in a YAML block scalar are sensitive to how the block is de-indented. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ci: drop the 3.10 lane from ci-standard instead of propping it up Replaces the exit-5 tolerance from the previous commit, which was treating a symptom. Two facts settle it. Every core_tests entry is root-package code — all of them are tests/** or src/shared/python/sidekick/tests/** — so once the floor guard correctly excludes root-package code, the 3.10 lane can never run a single core test. And 3.10 compatibility for the ten sub-packages that actually claim it is already proven elsewhere: each crate's maturin-*.yml runs a build + parity gate across 3.10/3.11/3.12 that builds the wheel, installs it, and asserts both that the extension imports and that the native backend is selected. So the lane was not testing 3.10 support. It was running root-package code on an interpreter that cannot execute it, and the only reason it ever looked meaningful was that a collection abort masked the emptiness. Tolerating empty collection would have institutionalised a lane that consumes a runner and reports nothing on every PR. ci-standard now runs ["3.11", "3.12"], starting at the root floor. The exit-5 tolerance is reverted, and the now-dead `!= "3.10"` sidekick guard is removed. Two contract tests replace the weaker matrix check: test_ci_matrix_starts_at_the_root_floor fails if a lane is ever added below the root floor, with an error that points at the maturin workflows as the correct home for lower interpreters. test_lower_floor_packages_keep_a_workflow_that_exercises_them fails if a sub-package declares a floor below the root and no workflow outside ci-standard actually runs that interpreter. This is the guard against the real risk in this change: dropping the lane must not leave a 3.10 claim with nothing behind it. It passes today, which is what makes the removal safe rather than assumed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(tests): select sub-package pyprojects by git tracking, not a denylist The 3.11 lane failed on a vendored dependency: .cargo-home/registry/src/.../pyo3-0.24.2/pyo3-runtime/pyproject.toml declares >=3.7 but no workflow outside ci-standard runs that interpreter That file is pyo3's own packaging metadata sitting in the cargo registry cache. It is a third-party artifact, not a claim this repository makes, and the directory does not exist locally — it is materialised only on CI runners, which is why the test passed here and failed there. The helper was enumerating pyproject.toml by rglob and filtering with a directory denylist (.venv, node_modules, target, build, dist, .git). A denylist is unbounded: every new tool cache is another entry nobody adds until it breaks a build. .cargo-home was simply the first one to appear. Selection is now by `git ls-files`, which answers "is this ours?" directly and cannot drift as new caches appear. It returns exactly the eleven real sub-package pyprojects and nothing else. If git is unavailable the tests skip rather than silently degrading to a weaker check. This fixes all four tests that share the helper, not just the one that failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: codex-scheduled <codex-scheduled@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
The root and
src/pendulum_simulatorhandoff docs had drifted far enough to actively misdirect the next agent. The root doc had also outgrown its own policy by 18x.The size problem — archived, not deleted
CLAUDE.mdrequires handoff docs to be current-state only and ≤150 lines, with history in git rather than a changelog inside the file. The root doc had instead accumulated 137 dated entries across 2,708 lines.Every entry is moved verbatim to
docs/agent_handoff_archive/2026-08_tools_root_handoff_log.md. The archived body is byte-identical to the original (165,356 characters, 137 entries — verified programmatically), so the large deletion in the diff is a move, not a loss. The live doc is now 132 lines and carries an explicit do-not against appending dated entries again.The accuracy problem
The root doc said PR #4119 was open with auto-merge armed, and #4124/#4129 were open drafts stacked on it. Actually:
Delivery has since shifted from long stacked PRs to scoped consolidations rebuilt onto current
main. The doc now records the seven live epics, and — most usefully for whoever picks this up — that 39 of the 58 open PRs arecodex/4142-*/codex/4433-*drafts superseded by merged #4473, whose own description states it supersedes that draft chain. They should be triaged and closed, not rebased. The four open consolidations (#4446, #4447, #4449, #4466) are the real queue.The pendulum doc described #4406 as active on
research/shoulder-velocity-drift-transfer. #4406 is closed, shipped via consolidation #4450. It now records what landed and keeps the scientific boundary as an explicit do-not: the Drift Transfer tab fails closed for the triple and golfer tiers, and the double model's proximal link rate must not be relabelled as an anatomical quantity. It also cross-references the UpstreamDrift #8684 qualification state — including the finite-ground result where the preregistered screen admitted 0 of 384 cells, so a moving base is not a free upgrade for those tiers.Also recorded
--regenerate-api-baselinetrap: it blesses existing drift rather than only your change.ruff format --checkfailures undersrc/data_processing/data_processor/python/tests/. They are onmain, are not caused by this diff (which is three markdown files plus a SPEC row), and should not be silently absorbed into an unrelated PR.Gates
ruff check: cleanruff format --check: only the four pre-existing failures noted above; this PR touches no Python🤖 Generated with Claude Code