Skip to content

build(package): stop shipping Swift test sources - #3785

Merged
thymikee merged 7 commits into
mainfrom
build/pack-exclude-swift-tests
Oct 17, 2026
Merged

thymikee merged 7 commits into
mainfrom
build/pack-exclude-swift-tests

Conversation

@thymikee

@thymikee thymikee commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Summary

The npm package shipped apple/macos-helper/Tests/**, but that Swift never compiles into the helper.

  • The tests move back into the shipped manifest's tree: apple/macos-helper/Package.swift declares the test targets and package.json files excludes apple/macos-helper/Tests/** from the pack.
  • The pack keeps exactly one PackStub.swift per test target: SwiftPM refuses to load a package whose declared test target has no sources, and the install-time swift build runs on the packed tree, so the stubs are load-bearing. An earlier iteration shipped a manifest without test targets behind a Sources symlink in a dev-only test package; the symlink broke Stryker's sandbox copy (EISDIR, run 39045124618) and any tool that copies the tree, and SwiftPM rejects sources outside a package root, so no split layout avoids it.
  • The publish guard (scripts/size-report-package.mjs) derives the declared test targets from the shipped manifest and requires each target's PackStub.swift in the pack; the repo guard asserts the same invariant against the real npm pack --dry-run file list, so no test source can leak back in and no stub can go missing.
  • Rejected alternatives: a FileManager.fileExists check in the shipped manifest (depends on the manifest's working directory and sandbox); a dev-only test package compiling the shipped sources (needs a directory symlink or an out-of-root path:, both rejected by tooling/SwiftPM).

Validation

  • Packed tree: npm pack, extracted into a clean dir, then swift build -c release --package-path apple/macos-helper → Build complete. The pack holds no test sources beyond Tests/AgentDeviceMacOSHelperTests/PackStub.swift and Tests/AgentDeviceMacOSInputTests/PackStub.swift.
  • Size delta vs main (npm pack --dry-run --json --ignore-scripts, identical builds): 525 → 523 files, tarball 1,435,877 → 1,433,786 B (−2,091 B), unpacked 4,661,050 → 4,653,755 B (−7,295 B).
  • pnpm test:macos-helper → 8 XCTest cases (6 Input + 2+1+5 Helper), 0 failures. Repo guard, publish-guard, and size-report tests pass.
  • Mutation: pnpm gate mutation --modules snapshot-occlusion locally → Stryker sandbox copy passes (no EISDIR), initial test run succeeded, lane envelope pass at stage complete. No repo tool copies a directory symlink anymore; the regularFile guard in scripts/lib/repo-git.ts stays as the general fix for non-blob diff sides.
  • pnpm check:affected --run --head 563d35e6ea → [passed] exactCommit=true, all runnable checks green; receipt .tmp/validation/run-zVw3OY/receipt.json.

The npm files list ships apple/macos-helper whole, so its Tests/ entered
the tarball even though the install never compiles them. Excluding the
directory through files alone breaks the shipped build: SwiftPM refuses
any command once a declared test target's sources are missing, and a
manifest that probes FileManager for the directory depends on the
install working directory and manifest sandbox.

Move the test targets to apple/macos-helper-tests, a development-only
package whose Sources symlink compiles the shipped helper sources with
@testable reach. The shipped manifest keeps only the products the
install builds, so a packed tree builds unchanged and the tests keep
running through pnpm test:macos-helper in CI's macos-helper gate. A
repo guard holds the two manifests in parity.
The publish asset guard already rejects shipped benchmark scripts; add
the sibling invariant for the helper's Tests/ directory so a future
files-list edit cannot re-ship sources the install never compiles.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 12 files

You’re at about 97% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

View guided diff | Turn on auto-fix | Re-trigger cubic

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.38 MB 5.37 MB -6.4 kB
Package (unpacked) 5.38 MB 5.37 MB -6.4 kB
Package (download) 1.62 MB 1.62 MB -1.9 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 29.9 ms 28.6 ms -1.3 ms
CLI --help 83.5 ms 81.1 ms -2.4 ms

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-17 16:53 UTC

@thymikee

Copy link
Copy Markdown
Member Author

The code looks ready at 449b4d4: dropping the Swift test sources from the package and keeping them in a symlinked test package is sound, and the guard test blocks re-adding a testTarget. CI is still pending, with Smoke Tests (3), Repo Guards & Compatibility, Coverage and Integration Tests all queued or running and none failed, so I can't attribute anything yet. I did not run swift build, swift test or npm pack, so the 8-test pass and the packed-tree build are your claims for now. SwiftPM accepting a symlinked Sources directory on the CI macOS runner is unproven until the macos-helper gate in macos.yml passes. Not blocking, and you can take or leave both: the header comment in test/repo-guards/macos-helper-package-contents.test.ts says nothing in the repo compiles the shipped manifest, but pnpm build:macos-helper and check:macos-helper now build apple/macos-helper itself, so the comment could say the guard keeps testTarget out of the shipped manifest; and the target list is duplicated across apple/macos-helper-tests/Package.swift and the main manifest, which the guard keeps in step, so that is a small maintenance cost and needs no change. Before merge, the macOS helper gate (swift build and swift test through the symlink) and the Repo Guards and Bundle Size jobs need to go green.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 17, 2026
The coverage-crap gate died on EISDIR before measuring anything: this PR
commits apple/macos-helper-tests/Sources as a symlink (mode 120000) to a
directory, its diff carries the target as one added line, and the gate
read the touched list as file contents. readChangedLinesDiff's parser now
records the new-side object mode from the diff headers as regularFile,
and both changed-line gates skip what it rules out (a symlink, a gitlink)
instead of reading their working-tree entries.
@thymikee

Copy link
Copy Markdown
Member Author

Coverage gate: EISDIR fixed

Cause. The coverage-crap gate died before measuring anything (EISDIR: illegal operation on a directory, read, job 117419145530). This PR commits apple/macos-helper-tests/Sources as a symlink (git mode 120000) to a directory. Its diff carries the target as one added line, so the path reached the touched-file list and the gate read it as file contents. Locally, check:affected skips the coverage lanes (GitHub owns them), so it could not catch this.

Fix. 0bde27b5cf — parseUnifiedDiff (scripts/lib/repo-git.ts) now records the new-side git object mode from the diff headers as regularFile, and both content readers of the changed-file list skip what it rules out: the CRAP gate's touched-file collection (readTouchedFiles) and the changed-line coverage gate's loop. The same working tree also holds a gitlink risk (mode 160000); both are skipped by the object type, not by a try/catch on error text. No other changed-file reader in scripts/ reads contents (check-affected, apple-ci-impact, mutation selection classify paths by name only).

Tests. Entry-point regressions in both gates' run.test.ts (a committed symlink-to-directory) reproduce the exact EISDIR without the fix; parser tests pin symlink/gitlink/mode-change/deletion headers.

Receipt. pnpm check:affected --run --head 0bde27b5cf — all runnable checks passed, exactCommit=true. Pushed fast-forward on top of 449b4d4.

…out a symlink

The dev-only package apple/macos-helper-tests compiled the helper sources through a
committed symlink to ../macos-helper/Sources. A symlink to a directory breaks every
tool that copies the tree: Stryker's sandbox dies on copyfile (EISDIR), which failed
both mutation jobs on this branch (run 39045124618), and it breaks Windows checkouts.
SwiftPM rejects sources outside a package root, so no split-package layout avoids the
link. Put the tests back under apple/macos-helper/Tests and keep them out of the pack
with files exclusions; ship one PackStub.swift per test target, because SwiftPM refuses
to load a package whose declared test target has no sources, and the install-time
swift build runs on exactly that packed tree.

Proof on the packed tree: swift build -c release succeeds; pnpm test:macos-helper runs
all 8 XCTest cases from the checkout; the Stryker sandbox copy and full lane pass
locally (snapshot-occlusion, envelope pass).
@thymikee

Copy link
Copy Markdown
Member Author

Round 2: removed the directory symlink (option B). Head cf63ab3df8.

The apple/macos-helper-tests/Sources symlink broke Stryker's sandbox copy (EISDIR, run 39045124618, both mutation jobs) on top of the round-1 coverage-gate breakage. Evidence for the new layout: SwiftPM rejects test sources outside a package root ("is outside the package root") and refuses to load a package whose declared test target has no sources (error, not warning, even for swift build). So the tests live at apple/macos-helper/Tests again, the shipped manifest declares the test targets, and files excludes the test sources from the pack except one PackStub.swift per target — that stub is what makes the packed-tree swift build load.

  • Packed-tree proof: extract → swift build -c release --package-path apple/macos-helper → Build complete. Pack test files: exactly the two PackStubs.
  • Size vs main: −2 files, −2,091 B tarball, −7,295 B unpacked.
  • pnpm test:macos-helper: 8 XCTest cases, 0 failures.
  • Stryker: pnpm gate mutation --modules snapshot-occlusion locally — sandbox copy passes, initial test run succeeded, envelope pass (stage complete).
  • Kept the regularFile guard at 0bde27b: it is a general fix for any future non-blob diff side, not symlink-specific.

Validation: pnpm check:affected --run --head cf63ab3df8 → passed, exactCommit=true. No open review threads; no CI regressions to attribute.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 14 files (changes from recent commits).

You’re at about 97% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread scripts/size-report-package.mjs Outdated
Comment thread test/repo-guards/macos-helper-package-contents.test.ts Outdated
Comment thread scripts/__tests__/size-report-package.test.ts Outdated
The publish guard counted stubs instead of matching them to the test targets the
manifest declares, so two stubs for one target could hide a missing one. Derive the
target list with one owner (readMacosHelperTestTargets, exported from the guard's own
module and used by the repo guard too) and require Tests/<Target>/PackStub.swift for
each. The repo guard now asserts on the real npm pack --dry-run file list instead of
the files config text, and the fixture test carries the helper manifest so the stub
branch is covered on both the pass and the missing-stub path.

Closes the three review threads on cf63ab3.

@thymikee thymikee left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

round 3 validation running

The repo guard imports the plain-Node size-report module, which the typechecked
program excludes, so tsc saw it as an untyped boundary. A hand-written .d.mts
declares the two exports the checked code reads, keeping the script bare-node
runnable, and the guard's JSON parse carries its own narrowing.
@thymikee

Copy link
Copy Markdown
Member Author

Round 3: cubic review threads 1–3 fixed. Head 650f9b0d90 (57367bc + 650f9b0).

  1. packStubs.length < 2 → per-target check: readMacosHelperTestTargets (scripts/size-report-package.mjs, one owner) reads the declared test targets and the guard requires Tests/<Target>/PackStub.swift for each. Confirmed claim.
  2. The repo guard now asserts on the real npm pack --dry-run --json --ignore-scripts file list (Tests set == exactly the per-target stubs), not the files text. Confirmed claim.
  3. The fixture now ships Package.swift + a macosHelperManifestSource option, covering the stub branch pass and one-stub-missing fail. Confirmed claim.

Typecheck fallout from the guard's mjs import fixed with a scoped scripts/size-report-package.d.mts (650f9b0), plus its Fallow ignorePatterns entry (precedent: the two help-conformance .d.mts files).

Validation: pnpm check:affected --run --head 650f9b0d90 → passed, exactCommit=true, receipt .tmp/validation/run-28vqPR/receipt.json. All three threads replied and resolved.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 5 files (changes from recent commits).

You’re at about 97% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread scripts/size-report-package.mjs
Comment thread test/repo-guards/macos-helper-package-contents.test.ts Outdated
…d run npm cross-platform

The pack guard warned in a comment that a manifest-less helper pack is unbuildable but
only checked the stub set, so a dropped files entry that ships Sources without
Package.swift passed. Require the manifest whenever any apple/macos-helper/Sources
entry is packed, and let the fixture pack stand in for a real helper pack (manifest,
sources, stubs) so both the missing-manifest and missing-stub failures are covered.
The repo guard ran npm through execFileSync, which dies on ENOENT for npm.cmd on
Windows; runCmdSync resolves PATH extensions there, as installed-package-metro does.

Closes both review threads on 650f9b0.
@thymikee

Copy link
Copy Markdown
Member Author

Round 4: the two remaining cubic threads fixed. Head 563d35e6ea (one commit).

  1. Confirmed: the manifest warning was comment-only. assertPublishPackageContents now fails when the pack ships apple/macos-helper/Sources/** without Package.swift; the fixture pack is a real helper pack (manifest + Sources + both stubs) and the failing case is asserted.
  2. Confirmed: execFileSync('npm') is ENOENT on Windows. packedPaths uses runCmdSync (host-kit), matching installed-package-metro.

Validation: pnpm check:affected --run --head 563d35e6ea → passed, exactCommit=true, receipt .tmp/validation/run-zVw3OY/receipt.json. Both threads replied and resolved. Per instruction this is the last guard-wording round; further cubic threads get an assessment reply and stay open for the maintainer.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

You’re at about 97% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/__tests__/fixtures/size-report-npm-pack.json">

<violation number="1" location="scripts/__tests__/fixtures/size-report-npm-pack.json:41">
P3: This reformat turns the fixture's unchanged entries into expanded objects, so the diff is far larger than the two added entries. Restore the compact one-line object style used before this PR so the change only shows the new `Package.swift` and `PackStub.swift` entries.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

"size": 0
},
{
"path": "apple/macos-helper/Package.swift",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: This reformat turns the fixture's unchanged entries into expanded objects, so the diff is far larger than the two added entries. Restore the compact one-line object style used before this PR so the change only shows the new Package.swift and PackStub.swift entries.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/__tests__/fixtures/size-report-npm-pack.json, line 41:

<comment>This reformat turns the fixture's unchanged entries into expanded objects, so the diff is far larger than the two added entries. Restore the compact one-line object style used before this PR so the change only shows the new `Package.swift` and `PackStub.swift` entries.</comment>

<file context>
@@ -1,21 +1,83 @@
+      "size": 0
+    },
+    {
+      "path": "apple/macos-helper/Package.swift",
+      "size": 1057
+    },
</file context>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Assessment: true. My script rewrite of the fixture re-expanded every entry into multi-line objects; the compact one-line style should be restored, keeping only the three added entries (Package.swift + the two PackStub.swift). Not pushed this round: the coordinator closed guard-review rounds at 563d35e and asked that further threads be left for the maintainer, and a push would re-trigger this bot's review. Leaving open; uncontroversial formatting fix.

@thymikee
thymikee merged commit 6e8c2a0 into main Oct 17, 2026
23 checks passed
@thymikee
thymikee deleted the build/pack-exclude-swift-tests branch October 17, 2026 16:49
thymikee added a commit that referenced this pull request Oct 17, 2026
…ment

* origin/main:
  build(package): stop shipping Swift test sources (#3785)
  fix(scroll): take edge hints from a same-rect scrollable ancestor (#3784)
  docs(agents): write agent docs in ASD-STE100 and remove misleading docs (#3723)
  fix(daemon): retain cleanup locks and preserve healed snapshots (#3760)

# Conflicts:
#	packages/daemon/src/sessions/__tests__/replay-repair/session-replay-repair-record-exclusion.test.ts
thymikee added a commit that referenced this pull request Oct 17, 2026
…refactor/daemon-runtime-no-process-globals

* origin/refactor/host-environment:
  build(package): stop shipping Swift test sources (#3785)
  fix(scroll): take edge hints from a same-rect scrollable ancestor (#3784)
  docs(agents): write agent docs in ASD-STE100 and remove misleading docs (#3723)
  fix(daemon): retain cleanup locks and preserve healed snapshots (#3760)
  test: say which package still reads PATH from the process in the recording scenario
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant