capture: an absent RESOURCE reports as 15 missing names — the D-237 bug, one level deeper #18

Closed
opened 2026-07-13 18:04:00 +00:00 by dan-claude-bot · 0 comments
dan-claude-bot commented 2026-07-13 18:04:00 +00:00 (Migrated from github.com)

What happened

cast capture against a hand-built box, pointed at the right project and the
right environment, reported every single required name as individually
missing
:

  DATABASE_URL_PROD    MISSING     required by core.DATABASE_URL, absent from the source
  REDIS_URL_PROD       MISSING     required by core.REDIS_URL, absent from the source
  MAILGUN_API_KEY      MISSING     required by core.MAILGUN_API_KEY, absent from the source
  … 15 of 15 …
  UMAMI_APP_SECRET     MISSING     required by umami.APP_SECRET, absent from the source

0 name(s) to write

refusing to write the store: 15 name(s) the manifest requires are not
present on the source. […] Supply each one with --override <NAME> […] or fix the source.

The source box is serving production right now. It is sending mail through
Mailgun as we speak — it obviously has MAILGUN_API_KEY. Nothing was missing.

cast never found the resources. It looked for the manifest's apps (core,
umami) inside the project, the source box names them something else, and every
per-name lookup therefore came back empty. Fifteen of fifteen "missing" is the
signature of a wrong lookup, not a finding about content.

Why this matters more than it looks

The suggested remedy makes it worse. --override for all 15 names would have
"worked": the operator hand-supplies every secret through
$CAST_CAPTURE_<NAME>, capture writes a perfectly valid store, and the
resource-name mismatch — a real, reportable difference between the manifest and
the source — is never discovered.
The tool would have talked the operator into
hand-carrying the exact data it exists to stop them from hand-carrying, and
buried the actual finding.

This is the same class of bug #12/D-237 fixed — an absent target reading back
as an empty one — just one level deeper in the tree. #12 closed the project and
environment axes. The resource axis is still open, and it fails in the same
way: silently, plausibly, with a clean-looking report.

Proposal

capture (and diff) must distinguish "the resource does not exist" from
"the resource exists and lacks this variable" — and refuse on the former,
naming what does exist:

refusing to capture: the manifest declares resources not present on this source

  looked for:  application "core"   (manifest: environments.prod.apps.core)
               service     "umami"  (manifest: environments.prod.services.umami)
  exists here: incubator-stack, landing, postgres, redis, umami-analytics

A resource absent from the source reads back exactly like one with no env vars
set — every required name reports MISSING, and --override would then have you
hand-carry values that are sitting right there under a different name.

Only once the resource is found should per-name MISSING be reported — at which
point it means what it says, and --override is the right remedy.

Ideally the same refusal should suggest the fix: a resource-name mapping (or
--project-style flag), so a source whose app is called incubator-stack can be
read by a manifest that calls it core.

Acceptance

  • A manifest resource absent from the source refuses, and the message lists
    the resources that do exist on the source.
  • Per-name MISSING is only ever reported for resources that were actually
    found.
  • The all-names-missing case can no longer be resolved by --override-ing every
    name.
## What happened `cast capture` against a hand-built box, pointed at the right project and the right environment, reported **every single required name as individually missing**: ``` DATABASE_URL_PROD MISSING required by core.DATABASE_URL, absent from the source REDIS_URL_PROD MISSING required by core.REDIS_URL, absent from the source MAILGUN_API_KEY MISSING required by core.MAILGUN_API_KEY, absent from the source … 15 of 15 … UMAMI_APP_SECRET MISSING required by umami.APP_SECRET, absent from the source 0 name(s) to write refusing to write the store: 15 name(s) the manifest requires are not present on the source. […] Supply each one with --override <NAME> […] or fix the source. ``` The source box is **serving production right now**. It is sending mail through Mailgun as we speak — it obviously has `MAILGUN_API_KEY`. Nothing was missing. **cast never found the resources.** It looked for the manifest's apps (`core`, `umami`) inside the project, the source box names them something else, and every per-name lookup therefore came back empty. Fifteen of fifteen "missing" is the signature of a **wrong lookup**, not a finding about content. ## Why this matters more than it looks The suggested remedy makes it worse. `--override` for all 15 names would have "worked": the operator hand-supplies every secret through `$CAST_CAPTURE_<NAME>`, capture writes a perfectly valid store, and **the resource-name mismatch — a real, reportable difference between the manifest and the source — is never discovered.** The tool would have talked the operator into hand-carrying the exact data it exists to stop them from hand-carrying, and buried the actual finding. This is the **same class of bug #12/D-237 fixed** — an absent target reading back as an empty one — just one level deeper in the tree. #12 closed the *project* and *environment* axes. The **resource** axis is still open, and it fails in the same way: silently, plausibly, with a clean-looking report. ## Proposal `capture` (and `diff`) must distinguish **"the resource does not exist"** from **"the resource exists and lacks this variable"** — and refuse on the former, naming what *does* exist: ``` refusing to capture: the manifest declares resources not present on this source looked for: application "core" (manifest: environments.prod.apps.core) service "umami" (manifest: environments.prod.services.umami) exists here: incubator-stack, landing, postgres, redis, umami-analytics A resource absent from the source reads back exactly like one with no env vars set — every required name reports MISSING, and --override would then have you hand-carry values that are sitting right there under a different name. ``` Only once the resource is *found* should per-name MISSING be reported — at which point it means what it says, and `--override` is the right remedy. Ideally the same refusal should suggest the fix: a resource-name mapping (or `--project`-style flag), so a source whose app is called `incubator-stack` can be read by a manifest that calls it `core`. ## Acceptance - A manifest resource absent from the source **refuses**, and the message lists the resources that do exist on the source. - Per-name `MISSING` is only ever reported for resources that were actually found. - The all-names-missing case can no longer be resolved by `--override`-ing every name.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/cast#18
No description provided.