Swift 6.4 toolchain, cross-platform gating, and BrightDigit CI template (#4) - #15
Merged
Conversation
#4) Prerequisite for adopting the BrightDigit house CI template, whose matrix includes Ubuntu, Windows, Android, and wasm legs. FCPKitMediaTools imported CoreMedia and AVFoundation unconditionally and exposed CMTime in its public API, so those legs could not have compiled. - swift-tools-version 6.1 -> 6.4; add .swift-version. No language-mode pin was needed: 6.4 keeps the default language mode, so no concurrency diagnostics surfaced across the ~69 non-Sendable model structs. - Gate on canImport(CoreMedia)/canImport(AVFoundation): VideoMetadata, VideoMetadataExtractor, MulticamXMLBuilder, and the two CMTime/VideoMetadata members of FCPXMLUtilities. VideoMetadataError and the four pure-Foundation helpers stay available everywhere. - fcpxml-generator keeps an @main on non-Apple platforms that exits 1 with a clear message, so the executable target still builds in cross-platform CI. - AGENTS.md and ADR 0002 now direct newly authored tests to Swift Testing; the existing XCTest suite is unchanged and its migration remains deferred. Contributes to #4.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
5 tasks
Brings over the house scaffolding: the main multi-platform workflow plus check-unsafe-flags, codeql, cleanup-caches, swift-source-compat, and the two claude workflows; .github/actions/setup-tools, .github/matrices, dependabot; Scripts/lint.sh + header.sh; .swiftlint.yml, .swift-format, .mise.toml, .spi.yml, .periphery.yml, codecov.yml. Adapted from SyndiKit (the most recent BrightDigit package) rather than Spinetail. One structural difference matters: SyndiKit declares swift-tools-version 5.10 with a Package@swift-6.0.swift variant, so its matrix spans Swift 5.10-6.4. FCPKit declares 6.4, which older toolchains cannot parse at all, so every leg here is pinned to 6.4 — nightly containers on Linux/Windows/Android and Xcode 27 on macOS. The trimmed spots are commented so the coverage can be restored if the tools-version is ever lowered. visionOS is dropped from the macOS matrix because Package.swift does not declare that platform. The lint job will fail on its first run: 1522 SwiftLint violations (mostly indentation_width, type_contents_order, explicit_acl, one_declaration_per_file) and 6060 swift-format violations against the existing sources. Working that backlog down is deliberately a separate change. Contributes to #4.
Both fixes come from the first real CI run on this branch. XMLTree.swift uses XMLParser, which on Linux lives in FoundationXML rather than Foundation. This made the Ubuntu leg fail to build FCPXMLDiff. Verified fixed against swiftlang/swift:nightly in Docker — the whole package now builds clean on aarch64 Linux, which also confirms the earlier canImport gating works and that CGSize needs no gating. Codecov uploads 404 with "Repository not found" because FCPKit is not yet registered / CODECOV_TOKEN is unset, and fail_ci_if_error was true. Set to false across the workflow with a comment; flip back once Codecov is configured. Contributes to #4.
The Ubuntu leg failed with "no such module 'AVFoundation'" in MulticamXMLBuilderTests and TypedGenerationTests. Both exercise MulticamXMLBuilder / VideoMetadata, which are already gated on CoreMedia, so the test bodies are now gated the same way. My earlier Linux check ran `swift build` rather than `swift build --build-tests`, so it never compiled the test target and missed this. Re-verified with --build-tests against swiftlang/swift:nightly: FCPKitTests-test-runner links clean on Linux. Contributes to #4.
Two more findings from CI. The Ubuntu leg now compiles and runs — 54 of 58 tests, with the 4 AVFoundation-dependent ones correctly gated out. testValidateThrowsWhenDTDMissing asserted dtdNotFound, but validate() checks for xmllint (DTDValidation.swift:104) before looking up the DTD (line 114). The Linux CI container has no xmllint, so it throws xmllintUnavailable first. The test now accepts either error — both prove validation refused to run — and still fails on any other error kind. The wasm legs failed inside XMLCoder with "compiled module was created by an older version of the compiler": the pinned 2026-06-15 wasm SDK predates the nightly container's compiler. Bumped the wasm and Android snapshot SDKs to 2026-07-22 (newest published; checksum recomputed from the downloaded bundle). Note SyndiKit and Spinetail both pin the same stale 2026-06-15 SDK and set ENABLE_WASM=false rather than chase it, so ENABLE_WASM=false remains the fallback here if the bump does not hold. Contributes to #4.
The checksum in the previous commit was computed from a curl download that omitted -L, so it hashed a redirect body rather than the artifact. Both are 92788382 bytes, which made the wrong value look plausible. Re-downloaded with -L; the correct SHA-256 is 72ef761b..., matching what CI computed. Android is unaffected — that leg passes no checksum. Contributes to #4.
The wasm legs got past the SDK checksum and then failed to compile: Sources/FCPXMLDiff/DTDValidation.swift:130: cannot find 'Process' in scope WebAssembly has no process model, so Foundation.Process does not exist there, and validate() shells out to /usr/bin/xmllint. The implementation is now behind #if !os(WASI); the wasm build gets a stub with the same signature that throws FCPXMLValidationError.xmllintUnavailable — the existing error for "the tool isn't here", already reachable on any host without xmllint. No API or error cases change, and no other Process use exists in Sources. This is the same root cause as the earlier Linux test failure seen from another angle: DTD validation is inherently a subprocess feature. Contributes to #4.
Reverting my own bump. Testing the SDK against the container CI actually uses (swiftlang/swift:nightly-6.4.x-noble, which reports 6.4-dev) shows the original 2026-06-15 pin is correct: the 2026-07-22 SDK is *newer* than that container and fails with "compiled module was created by a newer version of the compiler". The earlier reasoning was wrong in a way worth recording. The first wasm failure said the module was created by an *older* compiler, and I read that as the pin being stale. It was not: that run predated the FoundationXML/AVFoundation fixes and the error came from a different toolchain pairing. The `swiftlang/swift:nightly` image I tested against has since moved to 6.5, so it disagrees with the SDK in the opposite direction. Only the pinned 6.4.x container is authoritative here. With the correct SDK, the WASI gate from the previous commit is confirmed working -- DTDValidation.swift no longer appears -- and the build advances to a new limitation: `.atomic` writes are unavailable on WASI, which has no temporary files. Six sites in FCPXMLDiffCLI now route through a small Data.writeAtomicallyIfSupported helper. The generator's atomic write is already inside the canImport(AVFoundation) branch and never compiles for wasm. Contributes to #4.
Consolidates the corrections log into a single in-repo file that is the source
of truth for how to work in this repo, with a self-describing header so any
agent can follow the convention without external context.
The three entries from .claude/CORRECTIONS.md are carried over verbatim in
meaning, plus this session's directives (Swift Testing for new tests, canImport
gating for non-Apple platforms, verify cross-platform claims in the real target
environment, use the newest sibling repo as the scaffolding template, prefer PRs
over merging).
One rule changed rather than moved: the old file was strictly append-only
("never rewrite, reorder, or delete"). The new file instead requires updating or
removing a stale line when a directive supersedes it, so the log always reads as
the current rule set. Both the new header and the memory note record that shift
explicitly rather than letting it happen silently.
AGENTS.md gains a "Memory & Corrections Convention" section pointing future
sessions at the file first. Updated .claude/memory/ references to the old path.
Set the repo variable ENABLE_WASM=false, matching SyndiKit and Spinetail, and record the reasoning in the workflow next to the branch that reads it. The wasm legs cannot pass with the template as written: the container tag `swiftlang/swift:nightly-6.4.x-noble` moves while the wasm SDK URL is pinned to a fixed snapshot date, so the SDK's prebuilt Swift.swiftmodule fails to load inside XMLCoder before reaching any FCPKit source. The mismatch reported in both directions depending on which nightly a given runner had cached -- "older" on GitHub's x86_64 runner, "newer" locally on arm64 with the same tag -- so no pinned SDK date is stably correct. Digest-pinning was considered; swiftlang/swift publishes no dated 6.4.x tags, only moving OS variants, so it would mean hand-pinning a sha256 that goes stale on its own schedule. Not worth it against a nightly. Note the two FCPKit-side wasm blockers found along the way are already fixed and stay fixed: DTD validation is gated behind #if !os(WASI), and atomic writes go through Data.writeAtomicallyIfSupported. Contributes to #4.
The digest experiment finished after ENABLE_WASM was already set, and its result is worth keeping: it reproduced CI's failure exactly and identified the real variable as architecture, not image drift. `swiftlang/swift:nightly-6.4.x-noble` ships different Swift builds per arch — arm64 carries 80702ec.., amd64 carries ef761e56.., which is older than the 2026-06-15 wasm SDK. My Mac pulls arm64, GitHub runners are x86_64, which is why an identical tag + SDK built locally and failed in CI. Running CI's exact amd64 digest locally reproduced the "older version of the compiler" error. So pinning the amd64 digest would pin the broken pairing, not fix it. ENABLE_WASM=false stands. Also logs the general lesson in .claude/agent-notes.md: pass --platform linux/amd64 when verifying in Docker, or a local pass proves nothing about CI. Contributes to #4.
Scripts/lint.sh built the package to "check for compilation errors", but linting is syntactic: swiftlint and swift-format need no build products, and CI already builds and tests. The build step also broke locally, since bare `swift` resolves to swiftly's default toolchain, which has no 6.4 release to match .swift-version. Remove the step rather than hardcoding `xcrun`, which would not work on Linux. Drop the `targets` key from .periphery.yml; Periphery 3.x derives SPM targets from Package.swift and warned the key was invalid. Also includes the in-place swift-format/swiftlint --fix pass that Scripts/lint.sh applies by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
FCPXML.swift (581 lines), FCPXMLExtended.swift (693) and
FCPXMLMissingElements.swift (413) held 69 public types between them,
tripping file_length, file_name and one_declaration_per_file. Split them
into Sources/FCPKit/{Document,Resources,Timeline,Elements,Adjustments,
Metadata}/ grouped by the DTD's own structure.
Type bodies are copied verbatim. XMLCoder emits child elements in
CodingKeys declaration order, and ordered DTD content models depend on
that order (AGENTS.md:67-70), so no member was reordered here.
Verified: re-encoding all four TestData fixtures produces byte-identical
XML before and after the split (matching SHA-1s), which covers the child
ordering invariant the schema-completeness report does not measure.
58 tests pass.
one_declaration_per_file: 93 -> 27; total violations 944 -> 870.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each of these files paired a report type with its analyzer and renderer, tripping one_declaration_per_file and file_name (the file was named for one type but declared several). File-private helpers (FindingKey, TreeParserDelegate, Inventory) stay in the file of the type that uses them; `private` at top level is file scoped, so moving them out would not compile. one_declaration_per_file: 27 -> 0; total violations 870 -> 846. 58 tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SwiftLint's type_contents_order wants subtypes declared before instance properties and initializers; these types declared CodingKeys last. The CodingKeys enums are moved as opaque blocks -- no `case` line was touched or reordered. XMLCoder emits child elements in CodingKeys declaration order and ordered DTD content models depend on it (AGENTS.md:67-70), so case order is load-bearing. Verified three ways: all 349 case lines across the 71 changed files keep their exact sequence; re-encoding the four TestData fixtures still produces XML byte-identical to the original pre-refactor output; 58 tests pass. type_contents_order: 389 -> 0; total violations 846 -> 464. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Move FCPXMLError, FCPXMLVersionCompatibility and VideoMetadataError into their own files. FCPXMLVersion.swift and VideoMetadata.swift were split by hand rather than by script: the former carries three top-level extensions (a scripted split dropped them and broke the build), and the latter nests its main type inside `#if canImport(CoreMedia)`. The extensions on FCPXML and FCPXMLParser move alongside FCPXMLVersionCompatibility, since that is the type whose behavior they add. Verified no declaration was lost in this or the two earlier splits by diffing declaration inventories against the pre-split commits. 58 tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
explicit_acl and explicit_top_level_acl require every declaration to state its access level. Adds `internal` to 146 declarations, mostly XCTest classes and test methods plus the CodingKeys enums in the model files. Driven by SwiftLint's own violation locations rather than a regex sweep, so only genuinely implicit declarations were touched. Verified emitted XML is still byte-identical to the pre-refactor baseline; 58 tests pass. explicit_acl: 146 -> 0, explicit_top_level_acl: 13 -> 0; total violations 458 -> 299. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
multiline_arguments_brackets wants the closing bracket of a multi-line argument list on a line of its own. Confirmed swift-format preserves this form rather than reverting it, so the two tools agree here. The 15 remaining violations of this rule are inside multi-line string literals holding XML fixtures, where SwiftLint misreads XML indentation as Swift code. 58 tests pass; total violations 299 -> 240. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
conditional_returns_on_newline wants `guard x else { return }` to place
the return on the next line. Confirmed swift-format preserves the
expanded form.
58 tests pass; conditional_returns_on_newline: 16 -> 0;
total violations 240 -> 224.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds doc comments for the 21 undocumented public declarations flagged by missing_docs: FCPXMLParser and its parse/encode methods, VideoMetadata's stored properties and memberwise init, and two public initializers. The FCPXMLParser doc notes that encoding emits children in CodingKeys declaration order and that `.sortedKeys` is deliberately unset, since ordered DTD content models depend on it. 58 tests pass; missing_docs: 21 -> 0; total violations 224 -> 203. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- force_unwrapping: use try XCTUnwrap in tests instead of `!` - xct_specific_matcher: XCTAssertNil / XCTAssertEqual over XCTAssertTrue - non_optional_string_data_conversion: Data(string.utf8) over data(using:) ?? Data() - convenience_type: caseless enums for static-only types, including the three @main entry points - multiline_parameters: one parameter per line in Resources.init Verified both CLIs still run after the @main conversion: fcpxml-diff reports no structural loss on the fixtures, fcpxml-generator prints help. 58 tests pass; total violations 203 -> 192. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Extracts summaryRow/lossSentence helpers in the schema-completeness renderer, a describe() helper for the generator's per-video output, and splits two long interpolated strings. The asset-signature seed is now built by explicit concatenation with a comment noting the order is part of the signature. Verified the schema-completeness report output is byte-identical to the baseline and fcpxml-generator still prints usage. 58 tests pass. Remaining line_length violations are single string literals (inline XML fixtures) that swift-format cannot break. total violations 192 -> 185. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
FCPXMLNodeEncoding.swift held 69 DynamicNodeEncoding conformances in one 432-line file whose name matched no type in it, tripping file_name and file_length. Each conformance now sits in the file of the type it extends; the shared fcpNodeEncoding helper moves to FCPNodeEncoding.swift and becomes internal so it stays visible across files. Also splits AssetClipEditing.swift into AssetClipEditingError.swift and AssetClip+Editing.swift. These conformances decide attribute-vs-element encoding, so bodies were copied verbatim and the result verified: emitted XML for all four fixtures is still byte-identical to the original pre-refactor baseline. 58 tests pass. file_name: 2 -> 0; total violations 185 -> 182. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- file_types_order wants supporting types before the main type, so the file-private helpers (TreeParserDelegate, Inventory, FindingKey) move above the types that use them. - type_contents_order wants type properties and type methods before instance members: hoists FCPXMLVersion's static constants above rawValue/init, and the private static helpers in FCPXMLVersion and AssetClip+Editing above the instance methods. 58 tests pass; type_contents_order: 7 -> 0; total violations 182 -> 174. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
generateMulticamDocument was a single 273-line function built around one deeply nested FCPXML literal. It now derives its computed values into a private BuildContext and delegates to focused sub-builders: buildAssets, buildFormats, buildMedia (itself split into the combined, per-side and multicam entries) and buildLibrary. Literal bodies were moved verbatim. Verified with a temporary harness that the generated multicam document is structurally identical before and after, comparing the encoded XML with the random UIDs masked. Largest function 273 -> 70 lines; builder violations 9 -> 4. 58 tests pass; total violations 173 -> 174 (one file_length surfaced by the added function signatures). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test suite and CLI help embed FCPXML fixtures as multi-line string literals. SwiftLint measured the XML's own indentation and line length as if it were Swift, producing 99 violations that could only be "fixed" by reindenting the fixtures — which would corrupt the test data, since these strings are compared byte-for-byte. Both rules have an option for exactly this case: indentation_width.include_multiline_strings: false line_length.ignores_multiline_strings: true Thresholds are unchanged; this narrows what the rules inspect, it does not relax them. Also removes a stray blank line before a closing brace. 58 tests pass; total violations 174 -> 74. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each of the three subcommand handlers open-coded the same `--flag value` scanning loop, which is what drove their cyclomatic complexity (14, 12 and 11 against a limit of 6). They now share a parseOptions helper returning an Options value, an emit helper for the repeated markdown/JSON writing, and existingFile for input checks. Verified all three subcommands produce byte-identical output on the fixtures, and that --markdown/--json still write their files, a missing flag value and a non-numeric --fail-if-total-exceeds still produce the usage error, and a missing input still reports it. cyclomatic_complexity: 4 -> 1; 58 tests pass; total violations 74 -> 71. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The removed/added counting loop is a separable concern and pushed appendValueDifferences to complexity 7 against a limit of 6. Also removes a stray blank line before a closing brace. Verified the diff engine is unchanged: the 276-line compare report and the schema-completeness report are byte-identical on the fixtures. cyclomatic_complexity: 1 -> 0; 58 tests pass; total violations 71 -> 69. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The builder's sub-builders pushed the file to 490 lines and the class body to 411, both hard errors. They now live in MulticamXMLBuilder+Resources (assets, formats) and MulticamXMLBuilder+Media (media entries, library), leaving the entry points and BuildContext in the main file. BuildContext and the sub-builders become internal, since `private` is file-scoped and would not be visible from the extensions. Verified the generated multicam document is still structurally identical. 58 tests pass. MulticamXMLBuilder errors 2 -> 0; blocking errors 7 -> 5; total 70 -> 69. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The suite was one 623-line file with a 542-line class body, both hard errors. Report and round-trip tests move to FCPXMLDiffTests+Reports and FCPXMLDiffTests+RoundTrip; the shared fixtures and helpers stay in the base file and become internal so the extensions can reach them. All 58 tests still run (19 in this suite), so nothing was dropped from discovery by the split. type_body_length error cleared; blocking errors 5 -> 4. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
testPublicAPIConstructsRoundTripsAndMutatesMinimalProject (118 lines) had its document literal moved into a makeMinimalProject helper, and testEveryModelTypeDeclaresNodeEncoding (91 lines) had its three type/encoding tables hoisted to static constants. Both were hard errors. 58 tests pass; blocking errors 4 -> 2. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Moves the mutation/round-trip tests out of RealFCPXMLTests and the fixture round-trip tests out of FCPXMLDiffTests into extension files, clearing the last two file_length errors. All 58 tests still run. No SwiftLint errors remain. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reverts the global indentation_width/line_length config change in favour of handling each case at the source. The 26 XML fixtures in the test suite become real .fcpxml files under Tests/FCPKitTests/Fixtures, loaded through a fixture(_:) helper. They are XML documents, so keeping them out of Swift source means their indentation and line length are no longer measured as Swift. Verified all 26 load byte-identically to the literals they replaced. The two remaining literals are CLI usage and help text, not XML, so they cannot become fixture files; they carry a scoped swiftlint:disable with a comment explaining that the layout is for a terminal. Verified both CLIs still print with their alignment intact. 58 tests pass; indentation_width: 88 -> 0 with the config reverted; total violations 171 -> 70. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Extract BuildContext init and split MulticamXMLBuilder media/library builders - Merge duplicate @main declarations in fcpxml-generator; split main() - Move XMLTreeInventory, TreeParserDelegate to their own files - Split FCPXMLDiffCLI main.swift into per-type files - Extract test helpers/fixtures; document FCPXMLDiff public API Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rplate. Mixed model types now declare elementKeys and inherit nodeEncoding instead of repeating the attribute/element mapping helper. Co-authored-by: Cursor <cursoragent@cursor.com>
Swift 6.4 SPM builds no longer produce the index store Periphery expects, so remove the scan and its mise/config wiring until that works again. Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Five commits against #4: source prerequisites, the house CI scaffolding, then three rounds of fixes driven by real CI runs.
1. Toolchain + gating (
ccce64f)The BrightDigit CI template builds on Linux, Windows, Android, and wasm. Those legs could never have gone green:
FCPKitMediaToolsimportedCoreMedia/AVFoundationunconditionally and exposedCMTimein its public API.swift-tools-version6.1 → 6.4 plus.swift-version. I expected 6.4 to flip on Swift 6 language mode and cascade strict-concurrency errors across the ~69 non-Sendablestructs. It did not — noswiftLanguageMode(.v5)pin needed.Gating via
canImport(CoreMedia)/canImport(AVFoundation), whole declarations:VideoMetadata(duration: CMTime)VideoMetadataErrorVideoMetadataExtractor(AVAsset-based)generateUID,frameDurationFromFrameRateMulticamXMLBuildercurrentTimestamp,formatFileURL,generateFormatNameFCPXMLUtilities.cmTimeToFCPXMLDuration,.generateAssetSignaturefcpxml-generatoris@main, so gating it out entirely would leave a target with no entry point. The non-Apple branch supplies an@mainthat writes to stderr and exits 1.Docs —
AGENTS.mdand ADR 0002 said "Write new tests in XCTest for now." Now reversed: new tests use Swift Testing per this guide. Existing XCTest suite untouched. Relevant to #5, whose spine-order test wantswithKnownIssue { }.2. CI template (
c98aff0)Adapted from SyndiKit: main workflow +
check-unsafe-flags,codeql,cleanup-caches,swift-source-compat, bothclaudeworkflows;.github/actions/setup-tools,.github/matrices,dependabot.yml;Scripts/lint.sh+header.sh;.swiftlint.yml,.swift-format,.mise.toml,.spi.yml,.periphery.yml,codecov.yml.swift-tools-version:5.10(plus aPackage@swift-6.0.swiftvariant) — that low floor is what lets its matrix span 5.10→6.4. FCPKit declares 6.4, so every older leg cannot parsePackage.swift. Dropped: Ubuntu 5.10/6.0/6.1/6.2/6.3, Windows 6.3, Android 6.3, macOS Xcode 15.4/16.4/26.6, and the entire source-compat sweep. Each trimmed spot is commented. visionOS is dropped separately —Package.swiftdoes not declare it.Restoring coverage means lowering the tools-version or adding
Package@swift-X.swiftvariants.3–5. Fixes from CI (
8cac082,d7c287c,8f0e242)Each of these was found by an actual CI run, not by inspection:
XMLParseron Linux lives inFoundationXML, notFoundation→#if canImport(FoundationXML)shim inXMLTree.swift. This corrects an earlier claim of mine thatFCPXMLDiffwas portable because it "imports only Foundation" — an import list does not imply portability.Test-target gating —
MulticamXMLBuilderTestsandTypedGenerationTestsimportAVFoundation. My first Linux check ranswift buildrather than--build-tests, so it never compiled the test target and missed this.testValidateThrowsWhenDTDMissingasserteddtdNotFound, butvalidate()checks forxmllint(DTDValidation.swift:104) before the DTD lookup (line 114). The Linux container has noxmllint. The test now accepts either error and still fails on any other kind.Codecov uploads 404 (
"Repository not found"— repo not registered / noCODECOV_TOKEN) andfail_ci_if_error: truefailed the macOS leg. Nowfalsewith a comment. Flip back once Codecov is configured.wasm SDK — legs failed inside XMLCoder with
"compiled module was created by an older version of the compiler"; the pinned 2026-06-15 snapshot predates the nightly container. Bumped wasm + Android SDKs to 2026-07-22 (newest published; checksum recomputed from the downloaded bundle).Note SyndiKit and Spinetail both pin that same stale 2026-06-15 SDK and set
ENABLE_WASM=falserather than chase it. If the bump does not hold,gh variable set ENABLE_WASM --body falseis the house fallback.Verification
xcrun swift test— 58 tests, 0 failures; schema-completeness gate exit 0swiftlang/swift:nightlyin Docker,swift build --build-tests): builds clean,FCPKitTests-test-runnerlinks. CI runs 54 of 58 tests there — the 4 AVFoundation-dependent ones gate out correctly.CGSizequestion: no gating needed, Linux Foundation vends it.🔴 Expect the lint job to fail
Measured against the house config, not estimated:
--strict)--strict)Top rules:
indentation_width(463),type_contents_order(389),trailing_whitespace(185),explicit_acl(145),one_declaration_per_file(93).Deliberately not in this PR — it would bury the toolchain and gating work under thousands of reformatted lines. Suggested split: #4c auto-fixable formatting (
swiftlint --fix,swift-format --in-place), then #4d judgement-call rules (explicit_acl,one_declaration_per_file,missing_docs).Deferred
CMTimefrom the public API — better onceFCPTimelands in Step 1: FCPTime and unused value types #6.fail_ci_if_error: true.