Skip to content

Wave 1 stabilization: scheduler fixes, test suite, CI, docs - #16

Merged
ikorich merged 8 commits into
mainfrom
feature/lib-modernization-plan
Jun 11, 2026
Merged

Wave 1 stabilization: scheduler fixes, test suite, CI, docs#16
ikorich merged 8 commits into
mainfrom
feature/lib-modernization-plan

Conversation

@ikorich

@ikorich ikorich commented Jun 11, 2026

Copy link
Copy Markdown
Member

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

Test plan

  • Host: swift build + swift test — 24/24 pass (Swift 6.3.2, macOS).
  • Wasm: 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-changes vs base: no new public API breakage.
  • DocC: swift package generate-documentation --target OpenCombineJS — zero warnings.
  • swiftformat --lint clean; all four workflow YAMLs validated.

Notes

  • Security audit (Phase 3 step 3): APPROVE-WITH-NOTES, zero Critical/High; Medium findings remediated in this PR (upstream tag format validation, quoting, job-scoped issues: write, artifact signature verification). Deferred recommendation: SHA-pinning third-party actions.
  • First CI run on GitHub-hosted runners is the only locally unverifiable surface (runner image contents, e.g. Xcode 26 presence on macos-26).
  • The behavior changes from the bug fixes (correct sub-millisecond strides, repeating schedules actually repeating) are called out in CHANGELOG under 0.3.0.

Closes #2
Closes #3
Closes #4
Closes #5
Closes #6
Closes #7
Closes #8
Closes #9
Closes #10

ikorich added 4 commits June 11, 2026 17:51
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
@ikorich ikorich added bug Something isn't working test suite Testing infrastructure and coverage continuous integration CI and automation documentation Improvements or additions to documentation labels Jun 11, 2026
ikorich added 4 commits June 11, 2026 18:15
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
GitHub Actions evaluates ${ { } }-style expressions anywhere in the
workflow file, including comments inside run scripts; the literal
"${ { } }" in a comment failed workflow validation ("workflow file
issue" run on every push). Found via actionlint.

Refs #6, #12
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
@ikorich
ikorich merged commit 95feb74 into main Jun 11, 2026
4 checks passed
@ikorich
ikorich deleted the feature/lib-modernization-plan branch June 11, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment