Files
Claude 1fec20a2a3
Some checks failed
CI / Native — linux (pull_request) Failing after 5m12s
CI / WASM — Web (pull_request) Successful in 32m8s
CI / Formatting (pull_request) Successful in 1m31s
fix(export): take the sylpheed-formats dependency by path, not by tag
Removes the last reason this repository depends on its own history.

The pin was deliberate and carried its own exit condition, written into the
comment above it: "revert to the path dependency the day the tag is an ancestor
of `main`." Measured -- `formats-pin-2026-09-01` (e2630413) IS an ancestor of
`main` now, so the condition is met, and the cost the comment named goes away
with it: while the pin held, `sylpheed-cli` built from the workspace crate and
the exporter from the tag, so `tools/port/verify-screen` compared two eras
instead of detecting drift. They read one decoder again.

It also removes a failure mode nobody priced in. Depending on this repo by tag
is what made the #49 history rewrite break the build: every commit was replaced,
the locked rev vanished, and clean checkouts could not resolve it while the
rewriting machine kept working off its `~/.cargo/git` cache (PR #60). A path
dependency cannot fail that way. `Cargo.lock` now has ZERO references to
Sylpheed.git.

⚠️ This moves the exporter across a 243-file decoder change (8 467 insertions),
so it was gated on the full suite rather than a compile:

  45 suites / 377 passed / 0 failed / 14 ignored, cargo exit 0
  45 binaries launched, 45 reported  (a SIGKILLed suite prints no result line
  and would otherwise vanish from the tally)
  corpus report: PRESENT for disc, res3d and iso

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 14:05:52 +02:00

77 lines
4.6 KiB
TOML

[package]
name = "sylpheed-export"
description = "Convert a Project Sylpheed disc into the open asset tree the Godot port reads"
version.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
# The decoders, PINNED BY REVISION. Not vendored and not reimplemented: they are
# disc-wide verified in their own repository, and floating the pin would let a
# decoder change land mid-milestone -- exactly the confusion this prevents.
#
# `sylpheed_formats::media` in particular owns the cases where one playable thing
# is not one archive entry (segment-spanning reads, multi-sub-wave banks, and the
# continuous cutscene-voice stream). Do not re-derive those here.
#
# Pin moved f817dd5 -> 7eeae30 on 2026-08-29. WHAT I WANTED FROM IT: `UiBuild`
# gained a public `records` map (record name -> the nested `.rat` leaf's byte
# range). Without it a consumer could not locate a leaf at all: `parse_build`
# sorted T8aD children into `sprites` and `.rat` children into a PRIVATE map, so
# the focus ring -- which lives inside `ptbtn0Nf.rat`, a record the parent
# bundle declares no element for -- was unreachable through the public API.
# Also brings `Keyframe::rotation_deg`, which the game does render.
#
# PINNED BY TAG, not by sha, and MISSION §2 now requires it. The reachability
# risk this comment used to warn about is closed: a sha reachable only from an
# `auto/*` branch is orphaned when that branch is deleted or -- worse --
# SQUASH-MERGED, because squash creates new commits, so `main` would look like
# it contained the work while this pin became unreachable. A tag is a permanent
# ref, it says what it is here in the file, and it fails loudly at FETCH rather
# than silently at build. `formats-pin-2026-08-29` is 7eeae30.
#
# Previous pin note, kept because the reasoning still holds:
# Pin moved 5414db3 -> f817dd5 on 2026-08-29. WHAT I WANTED FROM IT: `56cc7ac`,
# "a RATC child's name is stated, not inferred". A child was named by scanning
# backwards for the last printable run before its magic; for `pteff05.t32` the
# three trailing payload bytes are `38 41 58` = `8AX` and beat the real name, so
# the FULL-RESOLUTION BACKGROUND OF ALL FIVE MENU SCREENS registered under a
# name no element declares and resolved to no sprite. This port exported those
# screens without their background and said so in every render as "pteff05 (no
# sprite in the export)" -- which docs/DECISIONS.md then wrote up as correct.
# It was not. f817dd5 is the last commit touching `crates/` on that branch.
#
# Previous pin note, kept because the reasoning still holds:
# Pin moved 8b6dbcf -> 5414db3 on 2026-08-28. WHAT I WANTED FROM IT: the fix to
# `ui_layout::rest()`. At 8b6dbcf a trailing run of identical keyframes was
# always treated as the exit, so an element with no exit animation rested at its
# invisible pre-roll -- `ptframe1`/`ptframe2`, the main menu's circuit bracket,
# which a capture of the running game plainly shows. 5414db3 is the revision at
# which that fix carries its disc-wide check (30 of 13 991 elements move, 4
# become visible, 0 become invisible), not merely the one where it was written.
# A PATH dependency now that the decoders and the exporter live in one
# repository. This deletes a whole class of failure that the two-repo split
# created: no pinned revision to go stale, no tag to keep alive, no commit that
# a squash-merge can orphan, and no way for the exporter to be built against a
# decoder it was never tested with. A decoder change and the exporter change it
# requires now land in the same commit or not at all.
# ✅ UNPINNED 2026-09-20. The pin above was deliberate and carried its own exit
# condition -- "revert to the path dependency the day the tag is an ancestor of
# `main`" -- because while it held, `sylpheed-cli` built from the WORKSPACE crate
# and the exporter from the tag, so `tools/port/verify-screen` compared two eras
# instead of detecting drift. `formats-pin-2026-09-01` is now an ancestor of
# `main` (measured), so the two read one decoder again.
#
# 🔴 AND THE PIN HAD A COST NOBODY PRICED IN: it made this repository depend on
# its OWN history by tag. The issue-#49 history rewrite replaced every commit,
# the locked rev vanished, and the build broke for every clean checkout while
# still working on the machine that did the rewrite, because its `~/.cargo/git`
# still held the old object (PR #60). A path dependency cannot fail that way.
sylpheed-formats = { path = "../sylpheed-formats" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
anyhow = "1"
clap = { version = "4", features = ["derive", "env"] }
image = { version = "0.25", default-features = false, features = ["png"] }