CONS-A4: completist docs audit + pendulum drift-transfer diagnostics (supersedes #4080, #4411) - #4450
Conversation
Co-authored-by: dieterolson <198168927+dieterolson@users.noreply.github.com>
Co-authored-by: dieterolson <198168927+dieterolson@users.noreply.github.com>
…nsolidated/docs-pendulum-2026-08-13 Carries the additive completist output and reverts the branch's destructive deletions. Conflict: .jules/bolt.md — #4080's side removed the two Bolt learnings that main gained from #4071 and #4176 after this branch forked. Kept main's content; the removal was a stale-base artifact, not an intended edit. Reverted 90 file deletions the branch carried: - 19 dated historical Completist_Report_*.md (2026-03-08 .. 2026-07-23) - 7 hand-written docs/assessments/issues/ISSUE_*.md (security data leakage, test coverage, logging split, constants duplication, two thesis-defence reviews, duplicate file IO) - 57 generated Issue_NNNN_*.md The PR body claims only "collected markers / parsed codebase / generated issues / generated report" — no deletion is described. The generator itself does not delete: scripts/analyze_completist_data.py has no unlink/rmtree/remove and only globs ISSUES_DIR to deduplicate and count. So the deletions came from the agent, not the tool, and not from any retention policy — 19 months of dated reports were being kept on main, and the new report's own trend visualisation depends on that history. The regenerated issue set also restarts numbering at Issue_005 rather than continuing from Issue_2027, so it is not a superset of what it removed. Restored all 90 from main; pruning, if wanted, belongs in a deliberate PR. Kept from the branch: 5 .jules/completist_data/*.txt scan outputs, the new Completist_Report_2026-08-02.md, 12 new Issue_0NN_*.md, the COMPLETIST_LATEST.md refresh, and two genuine fleet-load fixes hoisting cheap `if:` pre-filters onto the pick-runner jobs of Jules-Issue-Mention-Handler.yml and PR-Comment-Responder.yml so a non-matching comment stops occupying two d-sorg-fleet runners.
…-transfer' into consolidated/docs-pendulum-2026-08-13
Six git-mode-160000 entries under .codex-worktrees/ (Codex agent scratch worktrees committed by accident), inherited by #4080 from a shared ancestor. origin/main has zero of them, no .gitmodules declares them, and the commits they point at exist only in one local clone and are on no remote branch — so a fresh clone after this merged would carry six gitlinks referencing objects the server does not have. .gitignore is deliberately not edited here — the .codex-worktrees/ ignore rule is owned by CONS-A1 (#4445) so it lands as a single change.
#4080's branch carried three repo-wide pre-commit commits (ba3730a "style: apply automated pre-commit formatting", 35bec2d "fix: pre-commit checks and main sync", c70755b "style/fix: pre-commit automated fixes") touching ~300 files that neither the completist docs task nor the pendulum work has anything to do with. That churn is not benign: * It was produced by a ruff build that disagrees with the CI-pinned ruff 0.14.10, so 281 of the 299 changed .py files FAILED `ruff format --check` under the pinned version — the same red-gate mode that blocked #4429/#4437/#4439. * Its line-wrapping displaced trailing `# noqa` comments onto closing-paren lines where they no longer suppress anything, producing 9 real F841 errors in tests/unit/sidekick/test_sidekick_ux_hardening.py, a UP017 in tests/unit/sidekick/agent/test_action_audit.py, and losing two SLF001 suppressions in test_sidekick_f4_collaborators.py. * It reformatted src/pendulum_simulator/, src/movement_optimizer/ and src/data_processing/ — trees the CI format gate explicitly excludes (ci-standard.yml) and repo policy says not to reformat. Reverted by path to origin/main, keeping only what the two PRs own: .jules/**, docs/assessments/**, the two workflow pre-filters, SPEC.md, AGENT_HANDOFF.md, and #4411's 10 files (taken from its own head, which forked from current main and so is churn-free). 280 of the 295 modified .py files were proven content-neutral first: HEAD's blob and main's blob normalise to identical bytes under one identical ruff 0.14.10 format pass, so reverting them drops nothing. The remaining 15 were reverted on provenance instead — none is owned by #4080 (a docs-only task) or #4411 (pendulum only) — and each was inspected to be reflow plus displaced-noqa only. Net effect: 299 changed .py files -> 5, and the diff drops from 323 files to 29. This also removes the pendulum/movement-optimizer churn that STATE.md predicted would collide with #4438.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b5791ae5d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| total_work = float(np.trapezoid(total_power, time)) | ||
| drift_work = float(np.trapezoid(drift_power, time)) | ||
| control_work = float(np.trapezoid(control_power, time)) |
There was a problem hiding this comment.
Keep integration compatible with NumPy 1.x
The package permits NumPy 1.24+ in src/pendulum_simulator/pyproject.toml, but np.trapezoid was introduced in NumPy 2.0. On supported NumPy 1.24–1.26 installations, every call to summarize_transfer raises AttributeError before returning any metrics; use the compatible np.trapz API or raise the minimum NumPy version.
Useful? React with 👍 / 👎.
| mask = (time >= start_s) & (time <= end_s) | ||
| if np.count_nonzero(mask) < 2: | ||
| raise ValueError("analysis window must contain at least two samples") | ||
| return np.flatnonzero(mask) |
There was a problem hiding this comment.
Integrate the declared window boundaries
When the user-entered start or end is not exactly a trajectory sample—which is normal because the spin boxes accept arbitrary four-decimal values—this mask silently discards both partial boundary intervals. For example, a 0.01–0.29 window on 0.1-spaced data integrates only 0.1–0.2 while reporting the requested bounds, and narrower valid windows raise an uncaught ValueError; interpolate boundary samples or constrain and snap the UI to the sample grid.
AGENTS.md reference: AGENTS.md:L129-L133
Useful? React with 👍 / 👎.
| shaft_com_velocity = wrist_velocity + 0.5 * params.L2 * club_rate[:, None] * club_tangent | ||
| tip_velocity = wrist_velocity + params.L2 * club_rate[:, None] * club_tangent | ||
| shaft_inertia = params.m2 * params.L2**2 / 12.0 | ||
| shaft_energy = 0.5 * params.m2 * np.sum(shaft_com_velocity**2, axis=1) | ||
| shaft_energy += 0.5 * shaft_inertia * club_rate**2 |
There was a problem hiding this comment.
Match distal energy to the simulated mass model
Whenever m2 is nonzero, this diagnostic uses a distributed uniform-shaft model, but physics.py simulates the entire effective distal mass m2 + mClub as a point mass at the tip. Consequently, distal_kinetic_energy_j is not the kinetic energy of the trajectory that produced the forces and velocities, so reported distal energy gains can be materially wrong and cannot be reconciled with the model's work balance.
Useful? React with 👍 / 👎.
| velocities = result.joint_velocities_at(index) | ||
| grip_velocity[index] = velocities["wrist_vel"] | ||
| distal_speed[index] = velocities["tip_speed"] | ||
| wrist_couple[index] = result.torques_at(index)[1] |
There was a problem hiding this comment.
Use the clamped wrist torque in work diagnostics
When torque clamping is enabled in the desktop controls, the equations of motion clamp the drive torque, but SimulationResult.torques_at() returns the raw command. This line therefore integrates commanded rather than achieved wrist-couple work—for example, a 100 N·m command with a 20 N·m clamp is reported at five times the applied torque—making the control-work diagnostic inconsistent with the simulated trajectory.
Useful? React with 👍 / 👎.
…6-08-13 Required because main moved under this branch: strict_required_status_checks_policy is true and allow_update_branch is false, so auto-merge cannot land a behind-or-conflicting branch and would have sat silently forever. Only conflict was SPEC.md's Change Log hot-prepend. Kept all three rows, newest first: CONS-A1's two 2026-08-13 entries (Comment-to-Issue-Converter pick-runner removal + .codex-worktrees ignore; pdf_renamer SQLite handle leak) above this branch's 2026-08-12 pendulum drift-transfer entry. Nothing dropped. .gitignore is taken from main unchanged, so CONS-A1's new .codex-worktrees/ rule is preserved rather than clobbered.
…dulum-2026-08-13 # Conflicts: # .github/workflows/Jules-Issue-Mention-Handler.yml # .github/workflows/PR-Comment-Responder.yml
CONS-A4. Consolidates the two remaining unrelated-subsystem PRs into one merge boundary.
Supersedes #4080 (
jules-...-8eacfe8f, completist docs audit) and #4411(
research/shoulder-velocity-drift-transfer, pendulum drift-transfer diagnostics).Containment verified by ancestry, not by title:
verify_coverage.shreportscovered=2 NOT-covered=0against this branch, so closing both drops nothing.Why these two are one PR
They are unrelated subsystems, so the honest answer to "one PR or two" is decided
by whether they interfere: they do not. #4411 merged into #4080 with zero
conflicts, and after de-churning (below) their file sets are disjoint. Kept as one
PR because every extra PR costs ~28 workflow runs and ~4 self-hosted fleet slots,
which is the problem this whole drive exists to fix. The two halves are cleanly
separable for review:
COMPLETIST_LATEST.mdrefresh, plus two genuine CI fleet-load fixestransfer_strategy.py+transfer_strategy_panel.py+ 2 test modules + docs. This is the substantive code change29 files, +1989/-220.
The two CI fixes are worth their own attention
#4080's branch carried two changes that have nothing to do with completist docs
and are the most immediately valuable thing in this PR — cheap
if:pre-filtershoisted onto the
pick-runnerjobs ofJules-Issue-Mention-Handler.ymlandPR-Comment-Responder.yml. GitHub evaluates them before scheduling, so anon-matching comment now costs zero fleet capacity instead of occupying two
d-sorg-fleetrunners just to be skipped one job later.Defects found and fixed while consolidating
docs(completist): audit completist data and generate report #4080 deleted 90 documentation files. Reverted. The branch removed 19
dated historical
Completist_Report_*.md(2026-03-08 … 2026-07-23), 7hand-written
docs/assessments/issues/ISSUE_*.md(security data leakage, testcoverage, logging split, constants duplication, two thesis-defence reviews,
duplicate file IO), and 57 generated
Issue_NNNN_*.md. It also deleteddocs/development/professional-scada-epic.md.This is an agent regression, not tool behaviour and not a retention policy:
issues / generated report". No deletion is mentioned.
scripts/analyze_completist_data.pycontainsno
unlink,rmtree, orremove; it only globsISSUES_DIRto deduplicateand count.
trend visualisation depends on that history.
Issue_005instead ofcontinuing from
Issue_2027, so it is not a superset of what it removed.All 90 restored from main. Deliberate pruning, if wanted, belongs in its own
reviewable PR.
Stale-base revert in
.jules/bolt.md. docs(completist): audit completist data and generate report #4080's side removed the two Boltlearnings main gained from ⚡ Bolt: Optimize SVG path string allocations #4071 and ⚡ Bolt: Replace map and reduce array methods with single-pass loops in default tab initializers #4176 after the branch forked. Kept
main's content.
Committed gitlinks. Six
160000entries under.codex-worktrees/,inherited by docs(completist): audit completist data and generate report #4080.
origin/mainhas none, no.gitmodulesdeclares them, andthe commits they reference exist on no remote — a fresh clone would get six
dangling gitlinks. Removed. (
.gitignoredeliberately untouched; that line isowned by CONS-A1 CONS-A1: CI/infra consolidation (file-size-budget checkout, pdf_renamer SQLite leak, fleet-load fixes) #4445.)
~290 files of inherited formatting churn reverted. docs(completist): audit completist data and generate report #4080's branch carried
three repo-wide pre-commit commits (
ba3730ac1,35bec2d99,c70755ba1)produced by a ruff build that disagrees with the CI-pinned 0.14.10 — 281 of
299 changed
.pyfiles failedruff format --checkunder the pinnedversion, the same red-gate mode that blocked 🎨 Palette & Bolt Suite: Form Submission, Accessibility, SVG & CSV Optimizations #4429/Codex Flight Suite: Consolidated Agent Flight and Metric Models #4437/Codex Rate of Closure Suite: Consolidated Agent Camera, Attribution and Execution Workflows #4439. The churn also
displaced
# noqacomments, producing 9 live F841 errors intests/unit/sidekick/test_sidekick_ux_hardening.py, a UP017 rewrite intest_action_audit.py, and two lost SLF001 suppressions intest_sidekick_f4_collaborators.py. It further reformattedsrc/pendulum_simulator/,src/movement_optimizer/andsrc/data_processing/, which the CI format gate excludes and repo policy saysnot to touch.
280 of the 295 modified
.pyfiles were proven content-neutral beforereverting: each file's blob and main's blob normalise to identical bytes under
one identical ruff 0.14.10 format pass. The remaining 15 were reverted on
provenance — none is owned by a docs-only task or a pendulum-only change — and
each was inspected to be reflow plus displaced-noqa only. Pendulum: Add Drift-Transfer Diagnostics #4411's own files
were taken from its head, which forked from current main and is churn-free.
Net: 299 changed
.pyfiles → 5; 323 files → 29. This also removes thependulum churn STATE.md predicted would collide with CONS-B1: Palette & Bolt Suite (form submission, accessibility, SVG & CSV optimizations) + movement-optimizer motion-view extraction #4438.
Verification
ruff check/ruff format --check(pinned 0.14.10), replicatingci-standard.yml's exactgrep -vexclude list: 0 files gated — the onlychanged
.pyfiles are Pendulum: Add Drift-Transfer Diagnostics #4411's 5, all under the excludedsrc/pendulum_simulator/tree. Checked them anyway: lint clean, all 5 alreadyformatted.
double_pendulum_golf.transfer_strategyimports cleanly and exposesTransferSignals,TransferSummary,double_pendulum_transfer_signals,pareto_front,summarize_transfer.git grep "<<<<<<< HEAD"empty; no barefrom datetime import UTC; zeromode-
160000entries.pytest-qtaborts atconfigure time with
ImportError: DLL load failed while importing QtCore. Thatis the known PyQt6 6.10 /
Qt6Core.dllfault on this machine, an environmentproblem rather than a PR defect. CI runs the suite.
Issue references
Closes #4406 — carried over from #4411, which delivers the model-neutral
transfer-signal contract, the exact drift/control grip-force closure checks, the
phase-window work/braking/impulse metrics, the Pareto ranking, and the PyQt
Drift Transfer tab that fails closed for unqualified model tiers.
SPEC.md§12 carries its dated Change Log row.
Supports D-sorganization/UpstreamDrift#8551.
#4080 references no issue — it is a bot-generated documentation audit.
Reviewer note
quality-gateis the fast hosted gate.tests (3.11)runs on the 7-runnerself-hosted fleet behind a
pick-runnerjob; atests (3.11)check that has notbeen created yet means
pick-runneris still queued — that is a queue, not afailure.