Fix a guaranteed crash, modernize date parsing, add Swift 6.4 CI - #8
Merged
Merged
Conversation
RISCfuture
force-pushed
the
swift-6.4/modernization
branch
2 times, most recently
from
September 14, 2026 23:07
033de08 to
9ef860c
Compare
Fix a guaranteed trap in both archive downloaders: the non-HTTP-response
guard threw `Error.badResponse(response as! HTTPURLResponse)`, force-casting
the very value whose `as?` had just failed. `badResponse` already accepts a
`URLResponse`, so pass the response through unchanged. The file downloader
also cleans up its tempfile on that path, matching the other error exits.
Replace `DateFormatter` with `Date.ParseStrategy` and
`Date.VerbatimFormatStyle` for the fixed-pattern cycle dates: one shared
strategy for the README effective date (previously rebuilt in four places)
and two format styles for the TXT and CSV distribution URLs. The
`FixedWidthField.datetime` payload carries a parse strategy accordingly,
which also makes the case Sendable.
Drop the legacy `.linkedLibrary("swift_Concurrency")` linker setting from all
three targets, and add Swift 6.4 CI legs for each OS already in the matrix.
All seven `@preconcurrency` imports remain required: `Regex`'s `Reference` is
still non-Sendable in Swift 6.4, as is ZIPFoundation's `Archive`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EbZbx5D2gGeXT8UxuiKEdq
Date.ParseStrategy is lenient in two ways the README format cannot tolerate: it rolls out-of-range components over, reading "October 32, 2025" as November 1st, and it stops at the first match, accepting trailing text. DateFormatter rejected both. Callers turn the result straight into a download URL, so a lenient parse silently fetches the wrong 28-day subscription rather than reporting no cycle. Route the four README call sites through parseReadmeCycleDate, which re-renders the parsed date and requires it to equal the input. Surrounding whitespace is still tolerated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EbZbx5D2gGeXT8UxuiKEdq
Adopt SE-0458 `.strictMemorySafety()` in the shared `swiftSettings` array so every target audits its unsafe constructs, then acknowledge the eleven existing unsafe uses: - `@unsafe` on the seven `@preconcurrency` imports of RegexBuilder and ZIPFoundation, whose pre-Sendable types are only ever used within a single parser instance. - `unsafe` on the three `String(format:)` calls, whose C variadic arguments match their format specifiers. - `unsafe` on the `ioctl(TIOCGWINSZ)` call in the E2E progress tracker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EbZbx5D2gGeXT8UxuiKEdq
Progress now flows down into SwiftNASR as a `Subprogress` minted from the caller's own `ProgressManager`, rather than up out of it as a `Progress` handed to a handler block. Six public signatures trade their `withProgress:` handler for `progress: consuming Subprogress? = nil`: `NASR.load`, `NASR.parse`, `Loader.load`, `Downloader.load`, `Distribution.readFile`, and `Distribution.readFileRaw`. The platform floor rises to macOS/iOS/tvOS/watchOS/visionOS 27 and the manifest to tools-version 6.4, which is where `ProgressManager` starts existing: it carries no lower availability annotation on Apple platforms, it is `@available(FoundationPreview 6.4)` on Linux, and `MacOSVersion.v27` is itself `@available(_PackageDescription 6.4)`. CI follows: the Darwin legs collapse into one `xcode-27` job driven by `maxim-lobanov/setup-xcode` (no earlier image can supply the macOS 27 SDK), the Linux 6.3 leg is dropped, and `.github/actionlint.yaml` declares `xcode-27` so `actionlint` keeps checking runner labels. `DirectoryDistribution` double-counted every file it read, adding each line's length on top of the length of the chunk the line arrived in and reporting 35 bytes read from a 21-byte file. `Progress` clamped `fractionCompleted` to 1.0 and hid it; `ProgressManager` reports the overshoot. The file's byte accounting is now pinned through the new `completedByteCount`/`totalByteCount` metadata, which every read and download reports alongside its unit counts. Also: `CSVParser` sheds its vestigial `progress` and `bytesRead` requirements, a diagnosed record no longer stalls the fixed-width parse progress short of its total, and the E2E progress bar follows `Observations.untilFinished` over the observable root manager instead of re-reading `fractionCompleted` on a 10 Hz timer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EbZbx5D2gGeXT8UxuiKEdq
RISCfuture
force-pushed
the
swift-6.4/modernization
branch
from
September 15, 2026 03:11
d78c15a to
35863c8
Compare
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.
throw Error.badResponse(response as! HTTPURLResponse)sat inside theelseof a failedas?, so a non-HTTP response crashed instead of throwing.linkerSettings: [.linkedLibrary("swift_Concurrency")]from all three targets — a legacy workaround, verified unnecessary on 6.4.DateFormatter→Date.ParseStrategy, deduplicating the sameMMMM d, yyyyformatter that was rebuilt in four places.Date.ParseStrategyis lenient whereDateFormatterwas strict — it rolls out-of-range components over (October 32→ Nov 1) and accepts trailing text. Since callers turn the result straight into a download URL, a lenient parse would silently fetch the wrong 28-day subscription.parseReadmeCycleDatere-renders and compares; 11 new parameterized cases cover it.All 7
@preconcurrencyimports were tested individually and kept — still load-bearing, sinceRegexis not Sendable in 6.4.🤖 Generated with Claude Code
https://claude.ai/code/session_01EbZbx5D2gGeXT8UxuiKEdq