Wave 1 stabilization: scheduler fixes, test suite, CI, docs - #16
Merged
Conversation
Four verified bugs in JSScheduler, found during the modernization deep-analysis and pinned by the new test suite: - Stride.microseconds/.nanoseconds computed reciprocals instead of millisecond values (.microseconds(1000) yielded 1e-6 ms, not 1 ms). - Cancelling schedule(after:interval:) before the first fire force-unwrapped a nil IUO (crash) and never cleared the pending timeout, so the repeating phase started anyway. - Cleanup closures captured [weak timer] before the variable was assigned, so the captured binding was permanently nil and every JSTimer leaked in scheduledTimers forever. Replaced with token-based bookkeeping (key generated before timer creation). - The interval timer was created without isRepeating: true (JSTimer defaults to one-shot), so the repeating schedule fired exactly once. Also documents the single-threaded JS event-loop invariant and adds DocC comments to the public scheduler surface (#10). Fixes #2 Fixes #3 Fixes #4 Fixes #5
The library previously had zero tests (55 untested code paths). Adds the OpenCombineJSTests target with characterization and behavioral-contract tests designed in the modernization analysis: - SchedulerTimeTypeTests: pure Swift, host-runnable (stride conversions, arithmetic, Strideable laws; regressions for #2). - JSSchedulerTests, JSPromisePublisherTests, JSValueDecoderTests: JS-event-loop tests gated to WASI (regressions for #3 #4 #5, Future caching semantics, TopLevelDecoder fixtures). - In-code fixture factories; no file I/O under WASI. Runner: host subset via `swift test`; full suite under Node via JavaScriptKit PackageToJS: swift package --disable-sandbox \ --swift-sdk swift-6.3.2-RELEASE_wasm js test Package.swift also gains swift-docc-plugin for the DocC catalog (#10). Closes #7
The previous CI built for Swift 5.3-5.5 on retired ubuntu-20.04 images and could not even parse the swift-tools-version:6.3 manifest; no lane ran tests. - ci.yml: macOS 26 host lane (build + host tests) and Ubuntu wasm lane using the official version-matched swift.org wasm SDK, running the full 62-test suite under Node via PackageToJS. swift.org artifacts are GPG-verified before installation. - api-contract.yml: PR-blocking `swift package diagnose-api-breaking-changes` gate against the PR base (a fixed 0.2.0 baseline would be permanently red: main already carries the declared PromisePublisher.Failure break from fefb814). - canary-upstreams.yml: weekly allowed-to-fail builds against latest JavaScriptKit (host + wasm; detects the JSValueDecoder duplicate-conformance time-bomb, #9) and OpenCombine; files deduplicated canary-failure issues. Upstream tag values are format-validated before reaching sed/jq per the security audit. - label.yml: action versions bumped. - Least-privilege GITHUB_TOKEN permissions throughout. Closes #6 Refs #9, #12
- DocC documentation comments on every public symbol of JSPromise, JSScheduler and JSValueDecoder, plus a Documentation.docc catalog with overview and quick-start (builds clean with swift-docc-plugin). - JSValueDecoder: documents the retroactive TopLevelDecoder conformance risk (if an upstream ever ships the conformance, the file must be deleted and a minor release tagged) with the 2026-06-11 audit result; the weekly canary (#6 pipeline) watches for the trigger. - Example rewritten without force unwraps: graceful guards with console diagnostics, short user-facing DOM error message (full error goes to console.error per security review), event-loop context comments. README example mirrors the new code. - CHANGELOG: Unreleased 0.3.0 section covering #2-#10. Closes #8 Closes #9 Closes #10
First CI run findings: - The Ubuntu toolchain tarball 404'd: swift.org filenames use the "ubuntu24.04" pattern (with dot, no arch suffix for x86_64), not "ubuntu2404-x86_64". Verified the corrected URL returns 200. - actions/checkout@v4 is Node20-deprecated (runner warning; forced to Node 24 from 2026-06-16) — bumped to v6 in all workflows. - Stale "build-only" comments removed: the wasm lane runs the full suite under Node via PackageToJS. Host lane and API gate passed on the first run unchanged. Refs #6
swift.org serves all-keys.asc gzip-encoded even without Accept-Encoding; plain curl saves the raw gzip bytes and gpg fails with "no valid OpenPGP data found". --compressed makes curl decode the body before piping to gpg --import. Refs #6
The wasm SDK artifact on download.swift.org is published as .artifactbundle.tar.gz — the .zip path 404s (the earlier HEAD probe saw a CDN 302 and was a false positive; verified with ranged GETs). Install now uses `swift sdk install <url> --checksum` with the official SHA-256 from the swift.org releases API, which both validates integrity (F-04) and replaces the manual download. Canary SDK step gets the same .tar.gz correction. Refs #6
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.
Motivation
First wave of the OpenCombineJS modernization plan (deep source analysis, 2026-06-11). The library had four verified scheduler bugs, zero tests, CI that could not parse the Swift 6.3 manifest, and no API documentation. This PR stabilizes the library and puts the safety net in place for Wave 2 (dual Combine backend, async/await bridge — #11, #13) and Wave 3 (#14, #15).
Changes
JSSchedulerbug fixes (JSScheduler: Stride.microseconds/.nanoseconds compute reciprocals instead of millisecond values #2 JSScheduler: cancelling schedule(after:interval:) before first fire crashes; pending timeout survives cancel #3 JSScheduler: cleanup closures capture nil weak timer — every scheduled timer leaks #4 JSScheduler: schedule(after:interval:) fires only once — missing isRepeating: true #5): stridemicroseconds/nanosecondscomputed reciprocals; cancellingschedule(after:interval:)before the first fire crashed and never cancelled the pending timeout; cleanup closures captured a nil[weak timer]so every timer leaked forever; the repeating schedule fired only once (missingisRepeating: true).Documentation.docccatalog (swift-docc-plugin), JSValueDecoder retroactive-conformance risk documented with audit result, example rewritten without force unwraps and mirrored in the README.Test plan
swift build+swift test— 24/24 pass (Swift 6.3.2, macOS).swift build --swift-sdk swift-6.3.2-RELEASE_wasm --build-tests+swift package --disable-sandbox --swift-sdk swift-6.3.2-RELEASE_wasm js test— 62/62 pass under Node v20.swift package diagnose-api-breaking-changesvs base: no new public API breakage.swift package generate-documentation --target OpenCombineJS— zero warnings.swiftformat --lintclean; all four workflow YAMLs validated.Notes
issues: write, artifact signature verification). Deferred recommendation: SHA-pinning third-party actions.macos-26).Closes #2
Closes #3
Closes #4
Closes #5
Closes #6
Closes #7
Closes #8
Closes #9
Closes #10