2026-09-10 - Half of a refusal was never a refusal
--format pkg has been refusing since the pipeline was
built, naming two entries it could not compute:
no contents for entries: 0x200 0x1001 - nothing here can compute them, so they must be supplied
That refusal has been reported to the operator twice as "the thing blocking the packaging scripts from retiring", and treated both times as one problem. It was two, and one of them was this repository's to solve all along.
0x200 was
a fact the builder was holding
The entry name table is a NUL-separated list of the names of the
entries the package carries. write.rs already has
entry_name(id) mapping every one of them -
param.sfo, playgo-chunk.dat,
playgo-chunk.sha, playgo-manifest.xml,
icon0.png - and resolve_name_offset already
searches a supplied table for each name to fill in
entry_record.name_offset.
So the builder knew every name in the table it was demanding a caller hand it. Requiring it was asking for a fact it already held.
It is now derived when absent, and a supplied one still wins - a package rebuilt to match existing material needs its own table byte for byte.
The order is not sorted, and that is measured
icon0.png is 0x1200 and comes
first, ahead of 0x1000. The sequence is
taken from a real package via obSCEne's build-pkg.sh, where
the table is 75 bytes and reads
\0icon0.png\0param.sfo\0playgo-chunk.dat\0playgo-chunk.sha\0playgo-manifest.xml\0,
and a test pins it byte for byte and by length.
The format does not require that order -
name_offset points at wherever a name sits, so any order is
self-consistent - but a package built here should look like one that
works rather than merely parse like one. A second test walks every id
through resolve_name_offset and checks the offset lands on
its own name, because generating a table and then pointing into it
wrongly is worse than not generating one.
What is left, and it is genuinely the other kind
0x1001, PLAYGO_CHUNK_DAT, stays supplied.
It is a plgo structure with a sub-table index at
0xC0 and chunk, mchunk and scenario records - not a list
this crate can assemble from what it knows. obSCEne derives it from
LibOrbisPkg's ChunkDat.FromProject, and their
own comment records the cost of guessing at it: a first version wrote
only the header, and a console read the counts, found they promised a
chunk the body did not describe, and returned 0x80f00200
from scePlayGoCoreGetRawContentInfo after the
header passed.
So the refusal now names one entry rather than two, and the one it names is a real gap with a citable source and a known failure mode.
The thing worth carrying
Two facts arriving in the same error message are not the same kind of fact. These were grouped because they appeared together in one refusal, and that grouping survived being reported upward twice without anybody asking whether both halves were true. One was a missing derivation; the other was a builder declining to look in its own pocket.