Skip to content

Ground Study + Rate of Closure Suites: regional execution, camera tracking, job workspaces & static web distribution (consolidates 32 closed PRs, supersedes #4409/#4410) - #4446

Open
dieterolson wants to merge 416 commits into
mainfrom
consolidated/ground-and-rate-closure-2026-08-13
Open

Ground Study + Rate of Closure Suites: regional execution, camera tracking, job workspaces & static web distribution (consolidates 32 closed PRs, supersedes #4409/#4410)#4446
dieterolson wants to merge 416 commits into
mainfrom
consolidated/ground-and-rate-closure-2026-08-13

Conversation

@dieterolson

@dieterolson dieterolson commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Supersedes #4409, #4410

One carrier for both suites. #4409 and #4410 consolidated the same already-closed
#4332-#4402 range: they shared ~360 commits, diverged by only 49, and neither was an
ancestor of the other, so each was re-running the full CI matrix over largely identical
content. Both were red. This branch is consolidated/rate-of-closure-batch with
consolidated/ground-study-batch merged --no-ff on top, with every blocking defect fixed.

quality-gate failed on both PRs at Reject Raw Merge Conflict Markers, despite head
commits on each branch claiming the markers were resolved. That step sits near the top of the
job, so it short-circuited everything after it — which is why fixing it exposed two further
blocking failures in the same content that nobody had ever seen.

1. Raw conflict markers — 5 files

File Markers What the conflict actually was
SPEC.md 73 open / 104 close — unbalanced Identity version rows + dated §12 Change Log entries
AGENT_HANDOFF.md 8 / 8 Prepended handoff entries
docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md 6 / 6 Prepended handoff entries
src/rate_of_closure/AGENT_HANDOFF.md 6 / 6 Prepended handoff entries
.secrets.baseline 15 / 15 detect-secrets entries (live merge conflict)

No source file carried a marker.

Every conflict had one cause: ~25 stacked feature branches each prepended a dated entry
just below a section heading and bumped the same version rows, so every merge collided at
exactly that spot. Because each side is an independent entry rather than a competing edit, the
correct resolution is the union of all sides, with exact-duplicate blocks collapsed.

SPEC.md needed a tolerant parser: prior "resolutions" had deleted markers arbitrarily,
leaving 14 orphaned ======= and 31 orphaned >>>>>>> lines with no matching <<<<<<<.
It was verified line-for-line afterwards that no original content was dropped from any of
the four documents. The single-valued Identity rows collapse from 33 / 33 / 6 duplicates to
one each, at the highest observed version (1.14.94) plus a bump to 1.14.95.

2. .secrets.baseline had Windows path keys

The baseline inherited from #4410 was regenerated on Windows and committed with backslash
path keys
(30 of 33), replacing the POSIX keys on main and #4409. No Linux CI scan can match
a docs\SECRETS_MANAGEMENT.md key, so the detect-secrets job would have reported every real
audited entry as a newly added secret. Regenerated with CI's exact invocation and POSIX keys;
the result is a superset of both main's and #4409's entries and is idempotent under rescan.

3. ruff-format version drift — 100 files

The branches were formatted with a ruff other than the pinned ruff==0.14.10, which reformatted
100 changed Python files into output the pinned formatter rejects — including files with no
connection to this work (launch.py, scripts/bump_vendor_pin.py, src/shared/**). This was
not pre-existing debt: main's versions of all 91 of those files that exist there pass
ruff format --check under 0.14.10 cleanly. Re-running the pinned formatter restores 85 of
those 91 to byte-identical-to-main
content; the other 6 keep genuine changes.

4. A rewrite that contradicted its own suppression

tests/unit/sidekick/agent/test_action_audit.py had an automated UP017 fix rewrite
tzinfo=timezone.utc to tzinfo=UTC and import UTC from datetime, while leaving in place
the very suppression forbidding it: # noqa: UP017 - Python 3.10 CI lacks datetime.UTC. The
tests matrix still includes Python 3.10, where datetime.UTC does not exist. Reverted. The
rest of the branch was swept: every other from datetime import UTC sits inside a guarded
sys.version_info compatibility shim.

5. Accidental tree entries, absent from main

  • .codex-worktrees/* — six mode-160000 gitlinks pointing at stale local Codex worktrees
    from June (PRs Fix Swingset legend plot clearance #3602-[codex] Seed transfer entropy permutation tests #3784, long since merged). There is no .gitmodules, so they are
    undeclared, and the commits they reference exist only in one local clone and are on no
    remote branch
    — a fresh git clone would get six gitlinks to objects the server does not
    have. This is the "unregistered historical gitlink" that the campaign handoff records as
    having broken actions/checkout's cleanup and forced a credential-free manual fetch
    workaround.
  • batch_plan.txt, non_draft_prs.json, pr_worker_final_results.json,
    specified_summary.txt
    — raw gh API dumps and PR-batching notes written into the
    repository root by the prior consolidation agent. CRLF-encoded, and they trip
    git diff --check.

6. 138 mypy errors in 42 files, previously masked

With the markers fixed, quality-gate reached its Type Check step for the first time and
reported 138 errors across 42 files — all 42 of them new files added by this work, none
pre-existing on main. None came from the merge: exactly 5 files needed hand resolution
(§1 above) and not one was Python, so no call site was resolved differently between the two
branches.

  • arg-type (84) — two dominant patterns. Indexing a 2-D array (theta[i, 1], y[0])
    yields a scalar at runtime but numpy's stubs type it as ndarray, while the callee genuinely
    needs a scalar because it calls math.cos; those sites now hoist float(...) locals. The rest
    are dict literals inferred as dict[str, object] and then splatted with **kwargs, which
    defeats keyword type-checking entirely — fixed with TypedDict annotations on the literals
    rather than by loosening any callee signature.
  • no-any-return (26) — bound to an annotated local and returned, rather than cast.
  • redundant-cast (18) — dead cast(...) wrappers removed where narrowing already applied,
    each replaced with an annotated local so the fix also holds where the inner expression
    degrades to Any, with unused typing.cast imports pruned so F401 stays clean.
  • var-annotated (8), has-type (1), return-value (1) — explicit annotations, one
    declaration-only class annotation, and one documented cast where the parameter must stay
    object to remain contravariant with the CompleteBatchExecution.validator signature. A cast
    is a runtime no-op, so the golden-fixture-pinned output bytes are untouched.

7. Two more masked steps

  • Six empty tests/__init__.py package markers under src/shared/python/swing_sim/** failed
    Changed Test Assertion Check; allowlisted alongside the equivalent ground/tests marker
    already listed there.
  • A cosmetic reformat of tests/architecture/test_sidekick_external_imports_3316.py had
    enlisted an unrelated repo-wide import-boundary guard into this PR's blocking test set, and
    that guard fails against main's own tree — the src/shared/python/sidekick/ tree here is
    byte-identical to main, and the guard is a pure AST walk over src/ comparing dotted module
    names, so it is neither path- nor platform-dependent. main's exact bytes are restored so the
    file leaves the changed set. The guard's own failure is tracked as separate follow-up work.

Content integrity

  • 1341 files changed; 670 under src/rate_of_closure, 111 under tests/rate_of_closure.
  • All 848 changed Python files parse (AST); zero syntax errors, no truncation. The only empty
    files are 5 __init__.py package markers.
  • Of 218 modified Python files, only 2 lost a symbol present on main, and both are the
    documented module-budget extraction rather than deletion — the
    src/rotation_converter/ui/pyqt6/main_window.py helpers now live in plot_helpers.py, and
    motion_tabs.py helpers in motion_helpers.py. Both new modules define and export the moved
    names.

Gate evidence, pinned toolchain

Reproduced against CI's own selections — ruff==0.14.10, mypy==1.13.0, Python 3.12, numpy
pinned <2.4 as requirements.txt requires:

  • ruff checkclean (731 gate files)
  • ruff format --checkclean (731 gate files)
  • mypySuccess: no issues found in 465 source files
  • CI's own 216 changed test files, run with CI's flags — 2465 passed, 11 skipped, 0 failed
  • Both the 60% Coverage Policy Gate and the Sidekick Per-File Coverage Gate provably skip on
    this branch: coverage_gate_required only turns true when a tracked_packages path changes,
    and this branch touches none.

Known non-blocking failure

file-size-budget fails: three new GUI modules exceed the 500-LOC budget and are not in
scripts/monolith_baseline.txttorque_profile_panel.py (612),
regional_ground_execution_workspace.py (572), rate_of_closure/ui/pyqt6/main_window.py (541).
It is not a required check, and the campaign handoffs already record the 612-line file as known
debt, so it is reported rather than refactored inside a consolidation.

Already-closed PRs this carries

All 32 are closed unmerged, so their work exists only on these consolidation branches.

From #4409 — Ground Study (21): #4332, #4335, #4350, #4351, #4352, #4353, #4354, #4355,
#4356, #4357, #4359, #4360, #4361, #4365, #4366, #4367, #4370, #4372, #4373, #4374, #4375

From #4410 — Rate of Closure (11): #4339, #4342, #4358, #4362, #4363, #4364, #4368, #4371,
#4376, #4388, #4402

Issues referenced

All open, and each is annotated with this PR. None are closed by this merge — the campaign
handoffs list remaining work under every one of them, and this PR deliberately carries no
closing keywords.

…8-toolstrip-workspace

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…8-toolstrip-workspace

# Conflicts:
#	SPEC.md
…4-variation-export-continuation

# Conflicts:
#	src/rate_of_closure/AGENT_HANDOFF.md
…9-wind-scalar-adapter

# Conflicts:
#	src/rate_of_closure/AGENT_HANDOFF.md
…9-wind-workflow

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…8-ground-contract

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…9-flight-ground-transfer

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
#	src/shared/python/swing_sim/flight/tests/test_contract_api.py
# Conflicts:
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
# Conflicts:
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
#	tests/rate_of_closure/test_python_compatibility.py
# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
codex-scheduled and others added 20 commits August 12, 2026 20:30
…ated/ground-study-batch

# Conflicts:
#	SPEC.md
…ground-study-batch

# Conflicts:
#	SPEC.md
…idated/ground-study-batch

# Conflicts:
#	SPEC.md
…-of-closure-batch

# Conflicts:
#	SPEC.md
#	src/shared/python/golf_club/__init__.py
#	tests/ops/test_cross_repo_python_integration.py
#	tests/shared/python/golf_club/test_contracts.py
…e-of-closure-batch

# Conflicts:
#	SPEC.md
…ated/rate-of-closure-batch

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…d/rate-of-closure-batch

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…lidated/rate-of-closure-batch

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…/rate-of-closure-batch

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…ted/rate-of-closure-batch

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…ed/rate-of-closure-batch

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
#	docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
#	src/rate_of_closure/AGENT_HANDOFF.md
…e-of-closure-batch

# Conflicts:
#	AGENT_HANDOFF.md
#	SPEC.md
…sure-batch (#4410)

Both branches consolidated the same already-closed #4332-#4402 range and shared
~360 commits while diverging by 49, so each was re-running the full CI matrix
for largely identical content. This merge produces one carrier for both suites.

Conflict resolution (5 files):

* SPEC.md — the Identity version rows and the dated Change Log entries had
  accumulated NESTED conflict markers across ~25 successive feature-branch
  merges, and prior "resolutions" deleted markers arbitrarily, leaving the file
  UNBALANCED (73 open vs 104 close markers, with 14 orphaned `=======` and 31
  orphaned `>>>>>>>` lines). Every side was an independent prepended changelog
  entry, so the resolution keeps the UNION of all sides; exact-duplicate blocks
  are collapsed. Verified line-for-line that no original content was dropped.
  The single-valued Identity rows are collapsed from 33/33/6 duplicates to one
  each, at the highest observed version (1.14.94) plus a consolidation bump.

* .secrets.baseline — regenerated with the exact CI invocation. The inherited
  #4410 baseline had been regenerated on Windows and committed with BACKSLASH
  path keys, which no Linux CI scan can match; keys are restored to POSIX form.
  The result is a superset of both main's and #4409's audited entries and is
  idempotent under rescan.

* AGENT_HANDOFF.md, docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md,
  src/rate_of_closure/AGENT_HANDOFF.md — balanced but committed conflict
  markers, resolved as the union of both branches' handoff entries.

`git grep "<<<<<<< HEAD"` is now empty, so the quality-gate "Reject Raw Merge
Conflict Markers" step that blocked #4409 and #4410 passes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Neither of these belongs in the product tree, and neither exists on `main` --
both were committed by accident during the prior consolidation attempts.

* `.codex-worktrees/*` — six mode-160000 gitlinks pointing at stale local Codex
  worktrees from June (PRs #3602-#3784, long since merged). There is no
  `.gitmodules`, so they are unregistered submodule entries. This is exactly the
  "unregistered historical gitlink" that the campaign handoff records as having
  broken `actions/checkout`'s cleanup step and forced a credential-free manual
  fetch workaround in the distribution workflow.

* `batch_plan.txt`, `non_draft_prs.json`, `pr_worker_final_results.json`,
  `specified_summary.txt` — raw `gh` API dumps and PR-batching notes written by
  the prior consolidation agent into the repository root. They are CRLF-encoded
  and trip `git diff --check`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…icting rewrite

The consolidation branches were formatted with a ruff other than the version
`quality-gate` pins (`ruff==0.14.10`), which silently reformatted 100 changed
Python files into output that the pinned formatter rejects. `main`'s versions of
all 91 of those files that exist there pass `ruff format --check` under 0.14.10
cleanly, so this was pure version-drift churn introduced by the consolidation,
not pre-existing debt -- and it is why Format Check was the next failure waiting
behind the conflict markers.

Re-running `ruff format` under the pinned 0.14.10 restores 85 of those 91 files
to byte-identical-to-`main` content; the other 6 keep their genuine changes
(for example the rotation-converter plot-helper extraction) and now differ from
`main` only by real work.

Separately reverts `tests/unit/sidekick/agent/test_action_audit.py`, where an
automated UP017 fix rewrote `tzinfo=timezone.utc` to `tzinfo=UTC` and imported
`UTC` from `datetime` while LEAVING IN PLACE the very suppression forbidding it:
`# noqa: UP017 - Python 3.10 CI lacks datetime.UTC.` The `tests` matrix still
includes Python 3.10, where `datetime.UTC` does not exist, so that rewrite would
have failed the 3.10 job at import.

Verified with the pinned toolchain over the exact gate file list
(`git diff --diff-filter=ACMRT --name-only $(git merge-base origin/main HEAD) HEAD -- '*.py'`
minus the gate's excluded prefixes, 731 files): ruff check clean, ruff format
--check clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9f01d99c1

ℹ️ 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".

Comment on lines +108 to +110
assert scenario.velocity_at(
case["time_s"], case["position_m"]
) == pytest.approx(case["expected_velocity_mps"], abs=1e-12)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Relax the wind golden tolerance

On Python 3.12.13 with pytest 9.0.3, the shear_turbulence case fails here: Python returns 9.786440272809793, while the cross-client fixture expects 9.7864402728063, a normal 3.49e-12 cross-runtime sin/libm difference that exceeds this 1e-12 tolerance. The changed-test lane in .github/workflows/ci-standard.yml collects this src/**/tests/test_*.py file and runs it in the Python matrix, so the commit cannot pass that lane unless the comparison allows the observed floating-point drift.

Useful? React with 👍 / 👎.

Comment on lines +250 to +253
debug_assert!(
dt.is_finite() && dt > 0.0,
"rk4_step: dt must be finite and > 0"
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate timesteps in release builds

When the release-built PyO3 or WASM step API receives dt <= 0 or a non-finite timestep, this debug_assert! is compiled out, so zero silently returns an unchanged state, negative values integrate backward, and NaN propagates through the result instead of returning the advertised error. simulate calls the same function repeatedly, and the new workflow explicitly builds the wheel with --release; make this a runtime precondition that returns Err rather than a debug-only invariant.

AGENTS.md reference: AGENTS.md:L129-L133

Useful? React with 👍 / 👎.

codex-scheduled and others added 4 commits August 13, 2026 22:03
The "Reject Raw Merge Conflict Markers" failure on #4409 and #4410 short-circuited
`quality-gate` before its Type Check step, so this type debt was never gated. With the
markers fixed, mypy reported 138 errors across 42 files -- all 42 of them NEW files added by
the consolidated work, none pre-existing on `main`.

These are typing fixes only; no runtime behaviour changes. Notably none of them came from the
merge: exactly 5 files needed hand resolution (`SPEC.md`, `.secrets.baseline` and three handoff
documents) and NOT ONE was Python, so no call site was resolved differently between the two
branches.

By error code:

* `arg-type` (84) -- mostly two patterns. Indexing a 2-D array (`theta[i, 1]`, `y[0]`) yields a
  scalar at runtime but numpy's stubs type it as `ndarray`, while the callee genuinely needs a
  scalar because it calls `math.cos`; those sites now hoist `float(...)` locals. The rest are
  dict literals inferred as `dict[str, object]` and then splatted with `**kwargs`, which
  defeats keyword type-checking entirely -- fixed with `TypedDict` annotations on the literals
  (`_StatusCommon`, `_CommonSpecFields`) rather than by loosening any callee signature. Also
  `tuple(genexpr for i in range(3))` typing as `tuple[float, ...]` instead of
  `tuple[float, float, float]`, fixed by writing the three elements explicitly.
* `no-any-return` (26) -- bound to an annotated local and returned, rather than cast.
* `redundant-cast` (18) -- dead `cast(...)` wrappers removed where narrowing already applied,
  each replaced with an annotated local so the fix also holds where the inner expression
  degrades to `Any`, and the now-unused `typing.cast` imports pruned so ruff's F401 stays clean.
* `var-annotated` (8) -- explicit annotations at the assignment.
* `has-type` (1) -- a declaration-only class annotation for a matplotlib base-class attribute
  that `--follow-imports=skip` cannot see. Verified no class attribute is actually created.
* `return-value` (1) -- a documented `cast` where the parameter must stay `object` to remain
  contravariant with the `CompleteBatchExecution.validator` signature. A cast is a runtime
  no-op, so the golden-fixture-pinned output bytes are untouched.

Two narrowly-scoped `cast`s to `Literal["green", "fairway"]` remain where
`TargetDefinition.kind` is declared `str` but `TargetRegion.kind` is a literal union; both
carry comments noting `__post_init__` already restricts the domain.

Verification, reproducing CI's own file selection (465 files, the changed non-test Python set
minus the gate's excluded prefixes) under the pinned `ruff==0.14.10` / `mypy==1.13.0` on
Python 3.12 with numpy pinned <2.4 as `requirements.txt` requires:

    mypy  -> Success: no issues found in 465 source files
    ruff check        -> clean (731 gate files)
    ruff format --check -> clean (731 gate files)

`tests/rate_of_closure`: 1167 passed, including the pinned canonical golden-bytes fixture. The
two remaining failures are load-induced flakes on this workstation, both passing in isolation
-- a loopback-authority readiness timeout that the campaign handoff already documents as
happening on a loaded box, and a web-launcher smoke test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`quality-gate`'s "Changed Test Assertion Check" step flagged six `tests/__init__.py`
files as changed test files carrying no behavioural assertion. All six are
docstring-only package markers for the split swing_sim contract test packages --
`swing_sim/tests` plus the `flight`, `impact`, `putting`, `solver` and `variation`
subpackages -- and one is literally empty.

They are the same class as `src/shared/python/swing_sim/ground/tests/__init__.py`,
which is already allowlisted a few lines above with the same rationale, so this
follows the established precedent rather than inventing an exemption. Listed
explicitly rather than as a glob, matching how that neighbouring entry is written.

Verified: `python scripts/check_test_assertions.py --changed-files <the gate's own
848-file changed list>` now reports "Changed Python test assertion check passed."

This step sits after Type Check in the job, so it only became visible once the mypy
errors were cleared -- the same masking pattern that hid the type debt behind the
raw-conflict-marker failure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hitecture test

`tests/architecture/test_sidekick_external_imports_3316.py` had been reformatted by
the consolidation for purely cosmetic reasons -- the sole change was where
`textwrap.dedent(` and its `"""` sit relative to each other. Verified via AST that
every string literal is byte-identical between the two forms, so the reformat could
not affect behaviour, and verified that BOTH forms pass `ruff format --check` and
`ruff check` under the CI-pinned ruff 0.14.10 with the repository's own config.

The problem is what that cosmetic edit dragged in. Because CI's `tests` job runs the
*changed* test files, reformatting this file enlists an unrelated repo-wide
architecture guard into this PR's blocking test set -- and
`test_production_code_uses_shared_python_imports` fails on it, reporting duplicate-import
violations such as `src/shared/python/sidekick/__main__.py:182: sidekick.launcher_factory`.

Those violations are **pre-existing on `main`, not introduced here**: the entire
`src/shared/python/sidekick/` tree is byte-identical to `main` on this branch, and the
guard's detection is a pure AST walk over `src/` comparing dotted module names, so it is
neither path- nor platform-dependent. The test simply never runs on `main` because
nothing changes it.

Restoring `main`'s exact bytes takes the file back out of the changed set, so this PR
stops being gated on unrelated pre-existing debt, with no loss of real work. The sibling
guard `test_shared_import_aliases_3316.py` is deliberately left alone -- its diff adds a
genuine new `swing_sim` alias-identity test for this work, and it passes (12 passed).

Worth a separate issue: that architecture guard is red on `main` and is invisible until
someone happens to touch its file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`main` moved to 73fd3d4 when the CI/infra consolidation merged, and `main` is
protected with strict required status checks and `allow_update_branch` disabled,
so a behind branch cannot land and auto-merge would stall silently rather than
report. Merging `main` in explicitly.

Two conflicts, both in files #4445 also touched, both resolved as unions:

* `SPEC.md` §12 Change Log -- #4445 prepended two dated rows and this branch had
  prepended one, at the same position. All three are kept, newest first.
* `scripts/test_assertion_allowlist.txt` -- #4445 appended the pdf_renamer
  sub-app conftest entry while this branch appended the six swing_sim package
  markers. Both blocks retained with their explanatory comments.

Worth noting the confluence: #4445 added a `.codex-worktrees/` rule to
`.gitignore`, which is exactly the mechanism that stops the six undeclared
gitlinks this branch removed from ever landing again. `git diff origin/main --
.gitignore` is zero lines, confirming that rule survived the merge rather than
being clobbered.

Verified after resolution: no `<<<<<<< HEAD` anywhere outside `.github`, no
mode-160000 gitlinks in the tree, and `.gitignore` byte-identical to `main`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant