02 — Vendor schema + registry (KeynoteKitProtobuf) - #27
Conversation
|
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 |
Post-hoc verificationTwo extra checks run after opening this PR, both green. 1. Generation is byte-for-byte reproducible. Re-running the exact Toolchain: 2. The registry was cross-checked against protoc's own descriptor set, an
3. The tests are not vacuous. Mutating a single entry The mutation was reverted; the working tree is clean. |
Check in protoc-generated Swift for the 33 vendored Keynote 15.3 protos plus the 14.4 `TSKArchives_sos.proto` the registry still references, and port `TSPRegistryMapping` alongside them. Consumers never run `protoc` and `Package.swift` gains no build-tool plugin. `TSPRegistryMapping` exposes the 631-entry id -> message-name table and resolves each name to its generated Swift metatype. The table is not injective — 631 identifiers name 624 distinct messages — so it is modelled as `[UInt32: String]` and never inverted. Decoding is partial. The 15.3 protos mark 1,497 fields `required`, so a strict parse of a real component would reject documents Keynote itself round-trips; pairing a 15.3 schema with a 14.4 registry makes that worse. Generated code is excluded from lint rather than the rules being relaxed: `.swiftlint.yml` gains one `excluded:` entry and the generated directory carries its own empty `.swift-format`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The 15.3 protos mark 1,497 fields `required`, but Keynote does not populate all of them, so a strict proto2 parse throws `.missingRequiredFields` on components Keynote itself round-trips. Partial decoding is therefore correct rather than a workaround, and the constraint applies to any archive decode — not just registry lookups — so #17/#18 inherit it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes #14.
What landed
KeynoteKitProtobufnow carries checked-in Swift types for the vendored Keynote15.3 schema and a Swift port of the 14.4
TSPRegistryMapping. Noprotocatconsumer build time, and no build-tool plugin.
Generation
Mirrors
research/tools/prepare_keynote_parser.pyexactly — 34 protos, not 33:the 33 in
research/vendor/keynote-parser/protos/15.3/plus the 14.4TSKArchives_sos.protothat 15.3 dropped but the registry still references, withboth directories on the include path and
--swift_opt=Visibility=Public.Generated with Homebrew
protobuf35.1 /swift-protobuf1.38.1 — the pluginversion matches the
Package.swiftdependency pin exactly.No symbol collisions across the files that share a proto package (
TSCHspansfour files), so
FileNamingwas left at its default.Registry
TSPRegistryMappingis modelled as[UInt32: String]and never inverted —631 identifiers name only 624 distinct messages (
5/6bothKN.SlideArchive;7/12bothKN.PlaceholderArchive). A reverse map builtwith
Dictionary(uniqueKeysWithValues:)would trap at runtime.Name → Swift metatype resolution is longest-declared-prefix, which handles both
package-qualified names (
TSCH.PreUFF.ChartInfoArchive→TSCH_PreUFF_ChartInfoArchive) and the two genuinely nested messages(
TST.GroupByArchive.AggregatorArchive→TST_GroupByArchive.AggregatorArchive).Repo-size cost (consciously accepted)
.pb.swift)Generated/Whole-diff added lines: 203,630. This is the price of "no
protocon theconsumer machine" and is the intended trade.
Surprise worth recording: decoding must be partial
The 15.3 protos mark 1,497 fields
required(proto2). A strict parse of anempty or partial body throws
.missingRequiredFields, soTSPRegistryMapping.decodeuses
partial: true. Pairing a 15.3 schema with a 14.4 registry makes strictenforcement actively wrong — it would reject documents Keynote itself round-trips.
Lint: excluded, not weakened
No global rule was relaxed.
.swiftlint.yml— appended oneexcluded:entry(
Sources/KeynoteKitProtobuf/Generated). Existing entries untouched.--recursive, so the generateddirectory carries its own
.swift-formatwith{"rules": {}}; swift-formathonours the nearest config.
Scripts/lint.shwas not modified..periphery.ymluntouched — periphery is opt-in via$PERIPHERY, disabled inCI, and
retain_public: truealready covers the generated public types.Hand-written sources were split (
TSPRegistryErrorinto its own file, the twotest suites into their own files) so they satisfy
one_declaration_per_fileandfile_types_orderunderLINT_MODE=STRICT— which is what CI runs.Package.swift: not modifiedZero changes — the existing
swift-protobuf1.38.1 dependency and target wiringwere sufficient. Lane S (#16) is unblocked on this file.
Verification
DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer xcrun swift build— green... xcrun swift test— green, 12 tests in the protobuf suitesLINT_MODE=STRICT ./Scripts/lint.sh— exit 0, 0 violationsmise run prepare-keynote-parser— still prints631 registry entries; 0 missing message namesgrep -c '\.plugin(' Package.swift→ 0SwiftProtobufandcanImport(FoundationEssentials)-guardedFoundation; no Apple-only imports, no
.linkedFrameworkresearch/**untouched (git status --porcelain research/empty)Acceptance criteria
KeynoteKitProtobufand are committedTSPRegistryMappingportedprotocon the consumer machine.protoThe last is tested two ways: the 11 archive types named across
research/findings/are decoded by name, and all 631 identifiers are decodedvia the registry with each result's
protoMessageNameasserted against the table— so a transcription that paired a name with the wrong type would fail.
🤖 Generated with Claude Code