Summary
Swift and C# do not currently implement the same definition of a portable output path:
- Swift uses NFC followed by Foundation full case folding.
- C# uses NFC followed by
StringComparer.OrdinalIgnoreCase.
- The rejected control and format-character sets differ.
- Superscript Windows device names such as
COM¹ and LPT² are missing.
- There is no shared component or full-path length contract.
This conflicts with the format claim that both implementations enforce the same portability rules.
Impact
One platform can create or accept a package that the other rejects or cannot extract. Some accepted names are not creatable on Windows, and oversized components can pass inspection but fail at extraction time.
Evidence
Docs/FORMAT.md:55-63,122-126
macOS/BundlePack/Shared/ZipArchiveInspector.Validation.swift:228-277
macOS/BundlePack/App/PackageBuilder.IO.swift:196-215,386-410
Windows/BundlePack.Core/FileHelpers.cs:8-31
Windows/BundlePack.Core/BundlePackArchive.Validation.cs:156-176,245-277
Windows/BundlePack.Core/BundlePackService.IO.cs:288-304
Reproduction cases
payload/straße.txt and payload/STRASSE.txt
- final sigma, Turkish I, and NFC versus NFD pairs
- U+007F, U+0085, bidi controls, ZWJ, and ZWNJ
COM¹.txt, COM².txt, COM³.txt, and the corresponding LPT names
- components at the UTF-8 and UTF-16 255/256 boundaries
The Swift full-fold behavior was measured locally. Windows runtime confirmation is still required for the exact OrdinalIgnoreCase differential cases.
Proposed change
- Define a normative canonical output-path key in
Docs/FORMAT.md.
- Pin or explicitly version the Unicode behavior used by the contract.
- Specify the exact rejected scalar categories and exceptions.
- Complete the Windows device-name set.
- Define conservative UTF-8 byte and UTF-16 code-unit component limits plus a full relative-path limit.
- Use the same vectors in reader, writer, and extraction-name tests on both platforms.
Acceptance criteria
- A language-neutral fixture lists each path and its expected canonical key or rejection code.
- Swift and C# produce identical results for the complete fixture.
- Writers reject collisions before copying input data.
- Readers continue to reject absolute paths,
.., ADS-like names, trailing spaces and periods, and case-insensitive or NFC collisions.
- Extraction failures caused solely by an accepted component length are covered by tests and eliminated.
Compatibility constraints
Keep UTF-8 entry names, / separators, NFC collision protection, existing traversal defenses, and the rule that readers never silently rename an accepted stored path. Any intentionally incompatible rule needs a coordinated format-version decision.
Summary
Swift and C# do not currently implement the same definition of a portable output path:
StringComparer.OrdinalIgnoreCase.COM¹andLPT²are missing.This conflicts with the format claim that both implementations enforce the same portability rules.
Impact
One platform can create or accept a package that the other rejects or cannot extract. Some accepted names are not creatable on Windows, and oversized components can pass inspection but fail at extraction time.
Evidence
Docs/FORMAT.md:55-63,122-126macOS/BundlePack/Shared/ZipArchiveInspector.Validation.swift:228-277macOS/BundlePack/App/PackageBuilder.IO.swift:196-215,386-410Windows/BundlePack.Core/FileHelpers.cs:8-31Windows/BundlePack.Core/BundlePackArchive.Validation.cs:156-176,245-277Windows/BundlePack.Core/BundlePackService.IO.cs:288-304Reproduction cases
payload/straße.txtandpayload/STRASSE.txtCOM¹.txt,COM².txt,COM³.txt, and the correspondingLPTnamesThe Swift full-fold behavior was measured locally. Windows runtime confirmation is still required for the exact
OrdinalIgnoreCasedifferential cases.Proposed change
Docs/FORMAT.md.Acceptance criteria
.., ADS-like names, trailing spaces and periods, and case-insensitive or NFC collisions.Compatibility constraints
Keep UTF-8 entry names,
/separators, NFC collision protection, existing traversal defenses, and the rule that readers never silently rename an accepted stored path. Any intentionally incompatible rule needs a coordinated format-version decision.