feat: box import records the trip, without rewriting who the box was #133

Merged
dan-claude-bot merged 2 commits from feat/import-provenance into main 2026-07-21 12:09:30 +00:00
5 changed files with 437 additions and 1 deletions

View file

@ -7,6 +7,32 @@ which records not just what changed but what each drill run proved.
### Added ### Added
- **`box import` records that the trip happened — without rewriting who the
box was** (#131) — an imported box kept the artifact's mint stamp verbatim
(#103), which is 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. It now stamps `user.box.imported`
/ `user.box.imported.by` (the **first** trip, pinned once and never
rewritten), `user.box.imported.last` / `user.box.imported.last.by` (the
**latest**, refreshed on every arrival) and `user.box.imported.count` — a
birth pair plus a latest pair, the shape heavy-duty/rig#61 settled on for
the same repeated-event question, because last-wins alone would erase the
evidence of every earlier trip. This is deliberately **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 any more. The import is a
*third* fact, orthogonal to the first two, so it takes its own keys and
every key the artifact carried is left exactly as it arrived. `box info`
prints an `IMPORTED` line 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 (`the mint above predates it`) and never claims another
host, since 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 a breaking change — and is not written by the
import at all, so a legacy artifact with no stamp still reads as
`MINTED (not recorded)` rather than acquiring a shape it does not have.
- **A minted box records how it was minted, and `box info` reads it back** - **A minted box records how it was minted, and `box info` reads it back**
(#103) — `cmd_new` knew a great deal at the moment it launched and wrote (#103) — `cmd_new` knew a great deal at the moment it launched and wrote
three `user.*` keys, dropping the rest on the floor: the box version that three `user.*` keys, dropping the rest on the floor: the box version that

View file

@ -464,6 +464,39 @@ box version that cloned it) and leaves the lineage keys alone, because the
clone's disk genuinely did come from that image, template and role. `origin.from` clone's disk genuinely did come from that image, template and role. `origin.from`
records one hop: a clone of a clone names its parent, not its grandparent. records one hop: a clone of a clone names its parent, not its grandparent.
**An import records the trip, and rewrites nothing**
([#131](https://github.com/heavy-duty/box/issues/131)). Everything `incus
import` restores is the _artifact's_ truth, so an imported box keeps its mint
stamp verbatim — the mint time, the box version, the image and the origin
belong to the originating host and survive the trip on purpose. What `box
import` adds is the one fact the artifact cannot carry: that the trip happened.
```
MINTED 2026-06-01T10:00:00Z by box 0.7.0
IMPORTED 2026-07-20T09:14:03Z by box 0.8.1 (the mint above predates it)
ORIGIN clone of work/authed
```
It is **not** `origin=import`, and the difference is the whole point. `origin`
answers how the instance came into _being_ — mint or clone — and overwriting it
would destroy that: the clone above would 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.
The `IMPORTED` line sits directly under `MINTED` because that adjacency is what
stops the mint time being misread as this host's. Note what it does not claim:
box has no record of _which_ host minted the box, and a box can be exported and
re-imported onto the same host (that is the upgrade flow above), so the line
states only the ordering — the one thing box actually knows.
**A box can make the trip more than once**, and both ends are kept: the first
import is pinned forever, the latest is refreshed on every arrival, and a count
says how many. Last-wins alone would erase the evidence of the earlier trips,
which is the same mistake `origin=import` makes one level up. (The shape
follows [heavy-duty/rig#61](https://github.com/heavy-duty/rig/issues/61)'s
manifest: a birth pair plus a latest pair.)
**Boxes minted before this stamp existed keep working**, under this verb and **Boxes minted before this stamp existed keep working**, under this verb and
every other — they render as a box with blanks and say `MINTED (not recorded)` every other — they render as a box with blanks and say `MINTED (not recorded)`
rather than erroring. `user.box.schema` names the stamp's _shape_ (an integer, rather than erroring. `user.box.schema` names the stamp's _shape_ (an integer,

100
bin/box
View file

@ -438,6 +438,17 @@ snapshots). What box then re-stamps is THIS host's truth:
differs, the same move migrate-host makes re-homing a legacy box differs, the same move migrate-host makes re-homing a legacy box
· a fresh machine identity (reset_identity, exactly like a clone), so its · a fresh machine identity (reset_identity, exactly like a clone), so its
DHCP lease can never collide with the box it was exported from DHCP lease can never collide with the box it was exported from
· the import EVENT — when the box landed here, and by which box version
The mint stamp is NOT rewritten. The artifact's mint time, box version, image,
template and origin (mint or clone) are the originating host's truth and
survive the trip intact — 'box info' shows them unchanged, with an IMPORTED
line under them saying the mint predates the arrival. In particular the import
does not overwrite 'origin': a clone that was exported and imported still
reads as a clone, and still names the box it was cloned from.
A box that makes the trip more than once keeps both ends: the first import is
pinned forever, the latest is refreshed each time, and a count says how many.
Auth state rides along by design — the artifact carries the box's whole disk, Auth state rides along by design — the artifact carries the box's whole disk,
logins included. That is the point (log in once, keep the file), and the same logins included. That is the point (log in once, keep the file), and the same
@ -1420,6 +1431,7 @@ box_cfg() { incus config get "$1" "$2" 2>/dev/null || true; }
# legacy 'user.claudebox' tag already says out loud at resolve_box. # legacy 'user.claudebox' tag already says out loud at resolve_box.
box_provenance() { box_provenance() {
local i="$1" schema created ver img fp m asked tpl u role rrepo rref origin from local i="$1" schema created ver img fp m asked tpl u role rrepo rref origin from
local imp impby impl implby impn
schema="$(box_cfg "$i" user.box.schema)" schema="$(box_cfg "$i" user.box.schema)"
created="$(box_cfg "$i" user.box.created)"; ver="$(box_cfg "$i" user.box.version)" created="$(box_cfg "$i" user.box.created)"; ver="$(box_cfg "$i" user.box.version)"
img="$(box_cfg "$i" user.box.image)"; fp="$(box_cfg "$i" user.box.image.fingerprint)" img="$(box_cfg "$i" user.box.image)"; fp="$(box_cfg "$i" user.box.image.fingerprint)"
@ -1428,6 +1440,12 @@ box_provenance() {
role="$(box_cfg "$i" user.box.role)" role="$(box_cfg "$i" user.box.role)"
rrepo="$(box_cfg "$i" user.box.rig.repo)"; rref="$(box_cfg "$i" user.box.rig.ref)" rrepo="$(box_cfg "$i" user.box.rig.repo)"; rref="$(box_cfg "$i" user.box.rig.ref)"
origin="$(box_cfg "$i" user.box.origin)"; from="$(box_cfg "$i" user.box.origin.from)" origin="$(box_cfg "$i" user.box.origin)"; from="$(box_cfg "$i" user.box.origin.from)"
# The import event (#131) — a THIRD fact, read from its own keys. 'origin'
# above still says mint or clone, which is what it has always meant.
imp="$(box_cfg "$i" user.box.imported)"; impby="$(box_cfg "$i" user.box.imported.by)"
impl="$(box_cfg "$i" user.box.imported.last)"
implby="$(box_cfg "$i" user.box.imported.last.by)"
impn="$(box_cfg "$i" user.box.imported.count)"
# A pre-rename box has no metadata at all but is always a Claude box — the # A pre-rename box has no metadata at all but is always a Claude box — the
# same mapping box_user() makes, for the same reason. # same mapping box_user() makes, for the same reason.
[ -n "$tpl" ] || [ "$(box_cfg "$i" user.claudebox)" != 1 ] || { tpl=claude; u="${u:-claude}"; } [ -n "$tpl" ] || [ "$(box_cfg "$i" user.claudebox)" != 1 ] || { tpl=claude; u="${u:-claude}"; }
@ -1438,6 +1456,25 @@ box_provenance() {
else else
printf '%-11s%s\n' MINTED "(not recorded — this box predates the mint stamp)" printf '%-11s%s\n' MINTED "(not recorded — this box predates the mint stamp)"
fi fi
# Directly under MINTED, because adjacency is what defeats the misreading:
# the mint time above is the ARTIFACT's, carried across the trip on purpose,
# and a reader who meets it alone will take it for this host's.
#
# The qualifier states the one thing box actually knows — the ORDERING. It
# does not say "on another host": a box can be exported and re-imported onto
# the SAME host (that is the installer's own upgrade advice, #66), and
# nothing on the box records which host minted it. Inventing a location here
# would be precisely the fabricated fact the stamp exists to avoid.
if [ -n "$impl" ] || [ -n "$imp" ]; then
printf '%-11s%s\n' IMPORTED \
"${impl:-$imp} by box ${implby:-${impby:-unknown}} (the mint above predates it)"
# The birth of the import history, shown only when it is a DIFFERENT trip
# from the latest — on a single import both pairs hold the same values and
# a second line would be noise. Continuation indent, no second label.
if [ -n "$imp" ] && [ "$imp" != "${impl:-$imp}" ]; then
printf '%-11s%s\n' '' "import ${impn:-?} — the first was $imp by box ${impby:-unknown}"
fi
fi
if [ -n "$tpl" ]; then if [ -n "$tpl" ]; then
local paren="" local paren=""
[ -z "$u" ] || paren="user $u" [ -z "$u" ] || paren="user $u"
@ -1636,6 +1673,69 @@ cmd_import() {
tag="$(incus config get "$target" user.box 2>/dev/null || true)" tag="$(incus config get "$target" user.box 2>/dev/null || true)"
[ "$tag" = 1 ] || tag="$(incus config get "$target" user.claudebox 2>/dev/null || true)" [ "$tag" = 1 ] || tag="$(incus config get "$target" user.claudebox 2>/dev/null || true)"
[ "$tag" = 1 ] || incus config set "$target" user.box=1 [ "$tag" = 1 ] || incus config set "$target" user.box=1
# The import EVENT (#131). Everything above either restores the ARTIFACT's
# truth or re-establishes THIS host's boundary; none of it records that the
# trip happened. The mint stamp (#103) rides inside the artifact verbatim —
# which is correct, mint facts belong to the originating host — and that is
# exactly what creates the gap: an imported box is otherwise indistinguishable
# from one minted here at the artifact's mint time.
#
# Deliberately NOT 'origin=import'. 'origin' answers how this instance came
# into BEING — mint or clone — and overwriting it destroys that answer: a
# clone that was exported and imported would 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 any more. The import is a THIRD fact,
# orthogonal to the first two, so it takes its OWN keys, and every key the
# artifact carried — origin, origin.from, created, version, template, user,
# image, role, rig.* — is left exactly as it arrived.
#
# Birth pair + latest pair, the shape heavy-duty/rig#61 settled on for the
# same repeated-event question. It transfers: a box can make the trip more
# than once, and these keys ride inside the artifact on every subsequent one.
# · imported / imported.by FIRST-wins. Pinned once, never rewritten.
# · imported.last / .last.by LAST-wins. When it landed HERE.
# · imported.count how many trips — first and last alone
# cannot tell 2 apart from 5, and nothing
# else on the box can reconstruct it.
# Last-wins alone would repeat, one level down, the very mistake this key
# exists to avoid: the second import would erase the evidence of the first.
# First-wins alone cannot answer "when did this land on THIS host", which is
# the question an operator actually asks.
local first_at prev_n n now
first_at="$(incus config get "$target" user.box.imported 2>/dev/null || true)"
prev_n="$(incus config get "$target" user.box.imported.count 2>/dev/null || true)"
# A count that is absent (the first trip) or not an integer (a hand-edited
# config, a foreign user.box.imported.count) must never fail an import that
# has already happened — arithmetic on it under 'set -e' would. Same side the
# schema check in box_provenance() falls on: degrade, never die.
# Two holes, and they have to close together. `[ 08 -eq 08 ]` PASSES — test
# parses decimal — and then `$((08 + 1))` aborts with "value too great for
# base", because arithmetic reads a leading zero as octal. That abort lands
# after the physical 'incus import' and before the stamp, the placement fix
# and the start: precisely the window this guard exists to protect. So the
# digits-only case closes sign and garbage, and 10# forces base ten.
case "$prev_n" in ''|*[!0-9]*) prev_n=0 ;; esac
n=$((10#$prev_n + 1)); now="$(mint_time)"
local istamp=(
user.box.imported.last="$now"
user.box.imported.last.by="$(box_version)"
user.box.imported.count="$n"
)
# The birth of this box's import history: pinned on the first trip and
# carried by the artifact forever after, so a box on its third host still
# names the trip that started it.
[ -n "$first_at" ] || istamp+=(user.box.imported="$now" user.box.imported.by="$(box_version)")
# No 'user.box.schema' is written here, on either path. "Absent schema means
# pre-stamp" is load-bearing for the MINTED line, and stamping schema=1 onto
# a legacy artifact that carries no mint stamp would claim a shape it does
# not have. These keys need no schema to be read — every reader tolerates
# absence by construction. Nor does the schema BUMP: #103's contract is that
# it moves on removal or repurposing, never on addition, and this only adds.
#
# Before the start, like the clone re-stamp and for the same reason: an
# imported box is never observable — not for a second, not by a concurrent
# 'box info' — without the record of how it got here.
incus config set "$target" "${istamp[@]}"
# Placement: the artifact carries its profile list, but the isolation # Placement: the artifact carries its profile list, but the isolation
# contract is THIS host's box-net profile. A box export already says # contract is THIS host's box-net profile. A box export already says
# box-net; anything else (a pre-0.4.0 artifact, a hand-rolled export) gets # box-net; anything else (a pre-0.4.0 artifact, a hand-rolled export) gets

View file

@ -50,7 +50,13 @@ default, that survives `rm`, a host teardown, an upgrade, a move. The split
of truths is the design: everything `incus import` restores is the artifact's of truths is the design: everything `incus import` restores is the artifact's
(disk, config, snapshots); everything box re-stamps on import is the current (disk, config, snapshots); everything box re-stamps on import is the current
host's (the `user.box=1` boundary tag, the `box-net` placement, a fresh host's (the `user.box=1` boundary tag, the `box-net` placement, a fresh
machine identity via the same `reset_identity` a clone gets). Auth state machine identity via the same `reset_identity` a clone gets, and the record
that the trip happened). That last one is #131, and it is deliberately *not*
`origin=import`: `origin` says how the instance came into **being** — mint or
clone — and the import is a third, orthogonal fact. Overwriting `origin` would
make an exported clone come back claiming to be an import, with its
`origin.from` lineage left unreadable, so the import gets its own keys and the
artifact's mint stamp survives the trip untouched. Auth state
rides along deliberately — and because scrubbing a disk image is a promise rides along deliberately — and because scrubbing a disk image is a promise
tarball surgery cannot keep, export shouts that the file is a credential tarball surgery cannot keep, export shouts that the file is a credential
instead of pretending to sanitize it. instead of pretending to sanitize it.

View file

@ -1391,6 +1391,277 @@ one_version_reader() {
check "the tree's VERSION has a single reader, box_version() (#103)" 0 "" \ check "the tree's VERSION has a single reader, box_version() (#103)" 0 "" \
one_version_reader one_version_reader
# ---------------------------------------------------------------------------
# The import event (#131) — DRIVEN, on both halves, like the mint stamp above.
#
# An imported box keeps the artifact's mint stamp verbatim: the mint time, the
# box version, the image and the origin belong to the originating host and
# survive the trip on purpose (#129). What was missing is any record that the
# trip HAPPENED — and the obvious fix, 'origin=import', is the wrong one: it
# would overwrite whether the thing was a mint or a clone before it was
# exported, and leave 'origin.from' naming a lineage nothing explains. So the
# import takes its own keys, and the assertions that matter most here are the
# ABSENCE ones: every key the artifact carried must come out the far side
# untouched.
#
# The write half needs its own shim, because cmd_import reads 'incus config
# show <target>' as the name-collision guard and must see the name FREE — the
# opposite answer from the one the mint shim gives.
ISHIM="$(mktemp -d)"; IWORK="$(mktemp -d)"
cat > "$ISHIM/incus" <<'SHIM'
#!/usr/bin/env bash
# Fake incus for the import drive. FAKE_CFG answers 'config get' with a file
# of "<key> <value>" lines — it stands in for the config that rode inside the
# artifact and that 'incus import' has just restored.
printf 'incus %s\n' "$*" | tr '\n' ' ' >> "$FAKE_INCUS_LOG"
printf '\n' >> "$FAKE_INCUS_LOG"
case "$*" in
# Nothing exists under that name: the collision guard passes. The same call
# enumerates volatile hwaddrs later, where an empty answer is also correct.
"config show "*) exit 1 ;;
"config get "*)
[ -n "${FAKE_CFG:-}" ] || exit 0
key="$*"; key="${key##* }"
awk -v k="$key" '$1 == k { $1 = ""; sub(/^ /, ""); print }' "$FAKE_CFG" ;;
*"--columns P") printf '"box-net"\n' ;; # already on the contract, no re-home
esac
exit 0
SHIM
chmod +x "$ISHIM/incus"
# A real tarball, because cmd_import reads the instance name out of the
# artifact with tar before incus is ever called — a stub cannot fake that.
ARTIFACT="$IWORK/work-20260718T120000Z.tar.gz"
mkdir -p "$IWORK/backup" && printf 'name: work\n' > "$IWORK/backup/index.yaml"
tar -czf "$ARTIFACT" -C "$IWORK" backup/index.yaml
importbox() { # importbox <logfile> <cfg-file|""> — the real box, shimmed
local log="$1" cfg="$2"
: > "$log"
env FAKE_INCUS_LOG="$log" FAKE_CFG="$cfg" PATH="$ISHIM:$PATH" \
"$BOX" import "$ARTIFACT" </dev/null >"$log.out" 2>&1
local rc=$?
cat "$log.out"
return "$rc"
}
# One matcher per surface, so an absence assertion is a plain non-zero exit.
# 'config set' is the ONLY call that can write a key, so grepping it is what
# separates "box stamped this" from "the artifact carried it".
import_set() { grep -F 'config set' "$1" | grep -qE "$2"; }
# --- the first trip ---------------------------------------------------------
# The artifact of a box that was MINTED elsewhere and never imported before.
MINTED_ART="$IWORK/minted.cfg"
cat > "$MINTED_ART" <<'CFG'
user.box 1
user.box.schema 1
user.box.created 2026-06-01T10:00:00Z
user.box.version 0.7.0
user.box.template claude
user.box.user claude
user.box.origin mint
CFG
ILOG="$IWORK/import.log"
check "import: a shimmed 'box import' runs to completion (#131)" 0 "imported work" \
importbox "$ILOG" "$MINTED_ART"
check "import: records WHEN the box landed here, UTC ISO 8601 (#131)" 0 "" \
import_set "$ILOG" 'user\.box\.imported\.last=[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z'
check "import: records WHICH box version performed the import (#131)" 0 "" \
import_set "$ILOG" "user\\.box\\.imported\\.last\\.by=$(cat "$ROOT/VERSION")"
check "import: pins the FIRST trip as its own key (birth pair, rig#61) (#131)" 0 "" \
import_set "$ILOG" 'user\.box\.imported=[0-9]{4}-'
check "import: ...with the box version that made it (#131)" 0 "" \
import_set "$ILOG" "user\\.box\\.imported\\.by=$(cat "$ROOT/VERSION")"
check "import: counts the trip — the first one is 1 (#131)" 0 "" \
import_set "$ILOG" 'user\.box\.imported\.count=1'
# --- the absence assertions: this is the whole point of the issue -----------
# 'origin=import' is the road not taken. 'origin' says how the instance came
# into BEING — mint or clone — and the import is a third, orthogonal fact.
check "import: does NOT overwrite origin — an import is not a coming-into-being (#131)" 1 "" \
import_set "$ILOG" 'user\.box\.origin='
check "import: does NOT restamp the mint time — it is the origin host's (#131)" 1 "" \
import_set "$ILOG" 'user\.box\.created='
check "import: does NOT restamp the box version that MINTED it (#131)" 1 "" \
import_set "$ILOG" 'user\.box\.version='
check "import: does NOT restamp the template — lineage rides in the artifact (#131)" 1 "" \
import_set "$ILOG" 'user\.box\.template='
check "import: does NOT restamp the image the artifact was built on (#131)" 1 "" \
import_set "$ILOG" 'user\.box\.image'
check "import: does NOT restamp the rig that converged it (#131)" 1 "" \
import_set "$ILOG" 'user\.box\.rig\.'
# Adding a key is not a breaking change (#103's schema contract), so the schema
# does not move — and is not written here at all: stamping schema=1 onto a
# legacy artifact would claim a mint stamp shape it does not have.
check "import: does NOT touch user.box.schema — adding a key is not breaking (#131)" 1 "" \
import_set "$ILOG" 'user\.box\.schema'
# Before the start, like the clone re-stamp: an imported box is never
# observable without the record of how it got here. Fail-closed — a missing
# line makes the arithmetic fail, not pass.
import_stamp_precedes_start() {
local set start
set="$(grep -n 'config set .* user.box.imported.last=' "$1" | head -1 | cut -d: -f1)"
start="$(grep -n '^incus start ' "$1" | head -1 | cut -d: -f1)"
[ -n "$set" ] && [ -n "$start" ] && [ "$set" -lt "$start" ]
}
check "import: the import stamp precedes the start (#131)" 0 "" \
import_stamp_precedes_start "$ILOG"
# --- a CLONE that was exported and re-imported ------------------------------
# The case that makes 'origin=import' indefensible: it would come back
# claiming to be an import, with nothing left saying it was ever a clone and
# an origin.from pointing at a lineage no key explains.
CLONE_ART="$IWORK/clone-artifact.cfg"
{ grep -v '^user.box.origin ' "$MINTED_ART"
echo 'user.box.origin clone'
echo 'user.box.origin.from work/authed'; } > "$CLONE_ART"
CLOG="$IWORK/clone-import.log"
check "import: an exported CLONE imports cleanly (#131)" 0 "imported work" \
importbox "$CLOG" "$CLONE_ART"
check "import: ...and is still a clone afterwards — origin untouched (#131)" 1 "" \
import_set "$CLOG" 'user\.box\.origin='
check "import: ...and still names the box it was cloned from (#131)" 1 "" \
import_set "$CLOG" 'user\.box\.origin\.from'
check "import: ...while still recording that the trip happened (#131)" 0 "" \
import_set "$CLOG" 'user\.box\.imported\.last='
# --- the second trip: first-wins, last-wins, and a count --------------------
# The artifact of a box that has already been imported twice. Last-wins alone
# would erase the evidence of the first trip, which is the same mistake
# 'origin=import' makes one level up.
TWICE="$IWORK/twice.cfg"
{ cat "$MINTED_ART"
echo 'user.box.imported 2026-06-15T08:00:00Z'
echo 'user.box.imported.by 0.7.0'
echo 'user.box.imported.last 2026-07-01T09:00:00Z'
echo 'user.box.imported.last.by 0.8.0'
echo 'user.box.imported.count 2'; } > "$TWICE"
RLOG="$IWORK/reimport.log"
check "re-import: an already-imported artifact imports again (#131)" 0 "imported work" \
importbox "$RLOG" "$TWICE"
check "re-import: the FIRST trip is pinned, never rewritten (#131)" 1 "" \
import_set "$RLOG" 'user\.box\.imported=[0-9]'
check "re-import: ...nor is the version that made it (#131)" 1 "" \
import_set "$RLOG" 'user\.box\.imported\.by='
check "re-import: the LATEST trip IS refreshed (#131)" 0 "" \
import_set "$RLOG" 'user\.box\.imported\.last=[0-9]{4}-'
check "re-import: ...by this box version (#131)" 0 "" \
import_set "$RLOG" "user\\.box\\.imported\\.last\\.by=$(cat "$ROOT/VERSION")"
check "re-import: the count advances 2 → 3 (#131)" 0 "" \
import_set "$RLOG" 'user\.box\.imported\.count=3'
# A count that is not an integer (hand-edited config, a foreign key) must not
# fail an import that has already happened — arithmetic under 'set -e' would.
BADN="$IWORK/badcount.cfg"
{ cat "$MINTED_ART"; echo 'user.box.imported.count not-a-number'; } > "$BADN"
BLOG="$IWORK/badcount.log"
check "re-import: a non-integer count does not fail the import (#131)" 0 "imported work" \
importbox "$BLOG" "$BADN"
check "re-import: ...it restarts the count rather than inventing a total (#131)" 0 "" \
import_set "$BLOG" 'user\.box\.imported\.count=1'
# A leading zero is the hole the non-integer fixture CANNOT catch: '08' passes
# an -eq guard (test parses decimal) and then dies in arithmetic, which reads
# it as octal. That abort would land after the physical 'incus import' and
# before the stamp, the placement fix and the start — the exact window the
# degrade-never-die contract exists to protect. A zero-padded count is not
# exotic either: it is what any external tool that formats numbers writes.
ZEROPAD="$IWORK/zeropad.cfg"
{ cat "$MINTED_ART"; echo 'user.box.imported.count 08'; } > "$ZEROPAD"
ZLOG="$IWORK/zeropad.log"
check "re-import: a zero-padded count does not fail the import (#131)" 0 "imported work" \
importbox "$ZLOG" "$ZEROPAD"
# Counted as decimal 8, not degraded to 0 and not read as octal: '08' is a
# real previous total, so the honest next value is 9.
check "re-import: ...and counts it as decimal, so 08 advances to 9 (#131)" 0 "" \
import_set "$ZLOG" 'user\.box\.imported\.count=9'
# --- a legacy artifact with no stamp at all ---------------------------------
# A pre-stamp box export, or a hand-rolled 'incus export' of an unmanaged VM.
# It must import cleanly, get the boundary tag, get the import record — and NOT
# acquire a fabricated mint, which is what 'not recorded' exists to say.
LLOG="$IWORK/legacy-import.log"
check "import: a legacy artifact with NO stamp imports cleanly (#131)" 0 "imported work" \
importbox "$LLOG" /dev/null
check "import: ...it still gets the boundary tag (importing is minting) (#131)" 0 "" \
grep -qF 'config set work user.box=1' "$LLOG"
check "import: ...and the import record (#131)" 0 "" \
import_set "$LLOG" 'user\.box\.imported\.last='
check "import: ...but NO invented mint time (#131)" 1 "" \
import_set "$LLOG" 'user\.box\.created='
check "import: ...and no invented mint version either (#131)" 1 "" \
import_set "$LLOG" 'user\.box\.version='
# --- the read half: 'box info' must not let the mint be misread -------------
# The whole hazard: MINTED carries a time that is deliberately NOT this host's,
# and a reader who meets it alone will take it for one. The IMPORTED line sits
# directly under it and states the only thing box actually knows — the
# ORDERING. It does not claim another host: a box can be exported and
# re-imported onto the SAME host (#66's upgrade advice), and nothing records
# which host minted it.
IMPCFG="$MWORK/imported.cfg"
{ cat "$STAMPED"
echo 'user.box.imported 2026-07-20T09:14:03Z'
echo 'user.box.imported.by 0.8.1'
echo 'user.box.imported.last 2026-07-20T09:14:03Z'
echo 'user.box.imported.last.by 0.8.1'
echo 'user.box.imported.count 1'; } > "$IMPCFG"
check "info: surfaces when the box arrived, and by which box (#131)" \
0 "IMPORTED 2026-07-20T09:14:03Z by box 0.8.1" infobox "$IMPCFG"
check "info: ...and says the mint above is NOT this arrival (#131)" \
0 "the mint above predates it" infobox "$IMPCFG"
check "info: ...while the artifact's mint time still reads unchanged (#131)" \
0 "MINTED 2026-07-19T14:22:07Z by box 0.8.0" infobox "$IMPCFG"
# It must not invent a location for the mint — box has no record of one.
check "info: ...and never claims the mint happened on another host (#131)" 1 "" \
info_has "$IMPCFG" 'another host|elsewhere|remote host'
# A single trip prints ONE line: both pairs hold the same values and a
# 'first was...' continuation would be noise.
check "info: a single import prints no redundant 'first was' line (#131)" 1 "" \
info_has "$IMPCFG" 'the first was'
# A box that made the trip more than once shows both ends and the count.
IMPCFG2="$MWORK/imported-twice.cfg"
{ cat "$STAMPED"
echo 'user.box.imported 2026-06-15T08:00:00Z'
echo 'user.box.imported.by 0.7.0'
echo 'user.box.imported.last 2026-07-20T09:14:03Z'
echo 'user.box.imported.last.by 0.8.1'
echo 'user.box.imported.count 3'; } > "$IMPCFG2"
check "info: a repeat traveller shows the latest trip (#131)" \
0 "IMPORTED 2026-07-20T09:14:03Z by box 0.8.1" infobox "$IMPCFG2"
check "info: ...and the first one, with the count (#131)" \
0 "import 3 — the first was 2026-06-15T08:00:00Z by box 0.7.0" infobox "$IMPCFG2"
# An imported CLONE reads as a clone that also travelled — the two facts sit
# side by side, neither having eaten the other.
IMPCLONE="$MWORK/imported-clone.cfg"
# mode.asked is dropped, not merely unasserted: since #129 the clone path
# clears it (nobody asked THIS box anything), so a fixture built from the mint
# shape that kept the key would describe a box the clone path cannot produce.
# No assertion here reads it — which is exactly why it would rot unnoticed.
{ grep -v '^user.box.origin ' "$IMPCFG" | grep -v '^user.box.mode.asked '
echo 'user.box.origin clone'
echo 'user.box.origin.from work/authed'; } > "$IMPCLONE"
check "info: an imported clone is still a clone (#131)" \
0 "ORIGIN clone of work/authed" infobox "$IMPCLONE"
check "info: ...and still says it was imported (#131)" 0 "IMPORTED" infobox "$IMPCLONE"
# A box that was never imported says nothing at all — no empty IMPORTED line,
# the same rule every other key in the block follows.
check "info: a never-imported box prints no IMPORTED line (#131)" 1 "" \
info_has "$STAMPED" '^IMPORTED'
# And a legacy box with no stamp whatsoever still reads as 'not recorded'.
check "info: a stampless box still says the mint was not recorded (#131)" \
0 "predates the mint stamp" infobox "$LEGACY"
check "info: ...and prints no IMPORTED line for a key it does not have (#131)" 1 "" \
info_has "$LEGACY" '^IMPORTED'
check "help import: names the import record it writes (#131)" 0 "import EVENT" \
"$BOX" help import
check "help import: says the mint stamp is NOT rewritten (#131)" 0 "does not overwrite" \
"$BOX" help import
rm -rf "$ISHIM" "$IWORK"
rm -rf "$MSHIM" "$MWORK" rm -rf "$MSHIM" "$MWORK"
# The rehearsal itself stays runnable: syntax-checked here, run on real hosts. # The rehearsal itself stays runnable: syntax-checked here, run on real hosts.