cast/test
claude-hdb 40322bbf75 feat: --resource, the third name a hand-built box does not share with you
#20 shipped the refusal without shipping the resolution: capture correctly
refuses when a manifest resource does not exist on the source, and then
there was no way to say "it's over there, under another name."

Found immediately, on the box that motivated it. The manifest says `core`,
`landing`, `postgres`, `redis`, `umami`. The box says `Incubator Stack v2`,
`Incubator Landing`, `Incubator Database v2`, `Incubator Redis v2`,
`Incubator Umami`. Neither is wrong — one names things for a human reading a
UI, the other for a machine reading a diff — and neither gets to overwrite the
other.

  --resource core="Incubator Stack v2"     (repeatable)

Applied at the boundary: live resources are renamed to the manifest's
vocabulary once, immediately after the lookup, so computeDiff / classify /
reconcile all match by name exactly as before and none of them needs to know a
hand-built box was involved.

Read-side only, and `apply` refuses it up front — before a clone, a decrypt or
a single call. apply CREATES under the manifest's names, so an alias there
could only mean "adopt the existing one instead": a different operation nobody
has asked for, whose silent failure mode is a duplicate resource created beside
the one you were pointing at.

diff needed this as much as capture did. Without it, a --full diff against a
box whose resources are named differently reports every manifest resource as
"to create" and never mentions the live ones — the D-237 lie by another route,
a confident full-create plan against a box that has all of it under other names.
That diff is the staleness gate of a live migration.

Two smaller things, both about not laundering a naming gap into a pass:

- inventory, when NOTHING matched and yet the box has resources, now says so
  and prints the --resource lines to paste. "The box is empty" is exactly the
  wrong conclusion, and it was the easy one to draw.
- the absent-resource refusal prints the same, per absent resource.

An alias whose left side names no manifest resource is an error, not a no-op:
a typo would otherwise map nothing, leave the real resource looked-up under its
own name, and refuse with no hint that the flag had missed.

inventory keeps the box's own name beside ours in the report (`core ←
"Incubator Stack v2" on the box`) — a document that renamed the box's resources
to our vocabulary and never mentioned theirs would be unusable against the UI
it describes.

npm run check + build clean; 169 tests passing (was 164).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 18:50:06 +00:00
..
fixtures feat: assert the token's team before touching Coolify (fail-closed) 2026-07-12 20:55:04 +00:00
apply.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
bindings.test.ts fix: diff refuses an absent target instead of reporting it as empty (#11, #6) 2026-07-13 14:52:38 +00:00
capture-cli.test.ts feat: cast capture — adopt a hand-built Coolify into the age secret store (#15) 2026-07-13 16:51:43 +00:00
capture.test.ts feat: cast capture — adopt a hand-built Coolify into the age secret store (#15) 2026-07-13 16:51:43 +00:00
cli.test.ts feat: select the Coolify instance by name instead of editing .coolify.env (#14) 2026-07-13 16:42:45 +00:00
config.test.ts feat: select the Coolify instance by name instead of editing .coolify.env (#14) 2026-07-13 16:42:45 +00:00
coolify.test.ts feat: assert the token's team before touching Coolify (fail-closed) 2026-07-12 20:55:04 +00:00
diff.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
envtemplate.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
inventory.test.ts feat: read-side coordinates (#17, #18) + cast inventory (#19) 2026-07-13 18:20:53 +00:00
live-lookup.test.ts fix: diff refuses an absent target instead of reporting it as empty (#11, #6) 2026-07-13 14:52:38 +00:00
manifest.test.ts feat: assert the token's team before touching Coolify (fail-closed) 2026-07-12 20:55:04 +00:00
read-side-cli.test.ts feat: --resource, the third name a hand-built box does not share with you 2026-07-13 18:50:06 +00:00
resolve.test.ts fix: authenticate clones via gh / token, never fall into git's prompt (#13) 2026-07-13 16:30:04 +00:00
secrets.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
smoke.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
team.test.ts feat: assert the token's team before touching Coolify (fail-closed) 2026-07-12 20:55:04 +00:00
wire.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00