All three reviewers landed on the same line. Reproduced on this head under
`set -euo pipefail`:
prev_n=08
[ -n "$prev_n" ] && [ "$prev_n" -eq "$prev_n" ] 2>/dev/null || prev_n=0
# -> guard PASSES: test parses 08 as decimal
n=$((prev_n + 1))
# -> bash: 08: value too great for base (error token is "08")
Two holes that had to close together. `test -eq` reads decimal, arithmetic
reads a leading zero as octal, so a value can pass the guard and still abort
the arithmetic it was guarding. The abort lands after the physical
`incus import` and before the stamp, the placement correction and the start —
the exact window the degrade-never-die contract exists to protect, and the
same side box_provenance()'s schema check falls on.
case "$prev_n" in ''|*[!0-9]*) prev_n=0 ;; esac
n=$((10#$prev_n + 1))
Digits-only closes sign and garbage; 10# forces base ten. Checked across
08 -> 9, 007 -> 8, 5 -> 6, and '' / not-a-number / -3 / 3x / 00 -> 1.
The existing not-a-number fixture could never have caught this: that value
fails the guard and degrades, so it exercises the path that already worked.
Added a count=08 fixture beside it, asserting both halves — the import does
not fail, AND the count advances to 9 rather than degrading to 1, because 08
is a real previous total and reading it as anything else would be its own
small lie. A zero-padded count is not exotic; it is what any external tool
that formats numbers writes.
Verified by mutation: with the old guard restored both new assertions fail.
Also drops user.box.mode.asked from the IMPCLONE fixture (grok's nit). Since
#129 the clone path clears that key, so a fixture built from the mint shape
that kept it described a box the clone path cannot produce. Nothing asserts
it today — which is precisely why it would have rotted unnoticed.
An imported box kept the artifact's mint stamp verbatim (#103) — correct, the
mint time, box version, image and origin belong to the originating host and
should survive the trip. But nothing recorded the import, so an imported box
was indistinguishable from one minted here at the artifact's mint time.
Not origin=import. 'origin' answers how the instance came into BEING — mint or
clone — and overwriting it would make an exported clone come back claiming to
be an import, with nothing left saying it was ever a clone and an origin.from
naming a lineage no key explains. The import is a third fact, orthogonal to
the first two, so it takes its own keys and leaves every other one alone.
Birth pair plus latest pair, the shape heavy-duty/rig#61 settled on for the
same repeated-event question: imported/imported.by pinned once and never
rewritten, imported.last/.last.by refreshed on every arrival, imported.count
for the trips in between. Last-wins alone would erase the evidence of the
earlier trips, which is the same mistake origin=import makes one level up.
box info prints IMPORTED directly under MINTED, because that adjacency is what
stops the artifact's mint time being misread as this host's. It states only
the ordering and never claims another host: box has no record of which host
minted a box, and a re-import onto the same host is the documented upgrade
flow. user.box.schema does not move — adding a key is not breaking — and is
not written by the import at all, so a legacy artifact still reads as
MINTED (not recorded) rather than acquiring a shape it does not have.
Closes#131.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>