Skip to content

${...} placeholders in authored metadata resolve to nothing and reach the consumer verbatim — the masked-failure escape #8078 measured, now load-bearing for two refusal messages #8336

Description

@hotlong

Found while implementing #8082 (session session_01Euoy6wyfzgiWtgCg4s6JK2); measured originally during #8078 (#7990 census): a ${...} placeholder written in authored metadata (e.g. a datasource config.url of postgresql://${DB_HOST}/db) is resolved by nothing — it is stored verbatim in sys_metadata and handed verbatim to the database client at connect. The author believes environment substitution happens; the connection then fails (or connects somewhere unintended) with no error pointing at the unresolved placeholder — the masked-failure shape.

Why this now needs its own card

Two shipped refusal messages are written AROUND this defect rather than through it:

Decision shape (for triage)

Two honest directions, mutually exclusive:

  1. Implement resolution: define where ${ENV} in authored metadata is substituted (presumably at connect/render in services, never at rest), and which keys participate. Cost: a real capability with a security surface (env exfiltration via metadata authorship needs thought — who can author metadata that reads arbitrary server env vars?).
  2. Refuse loudly at publish: placeholder syntax in connection-material keys is rejected with "placeholders are not resolved here" guidance, making the non-capability explicit (declared = enforced; startup-focus favors this until a real pull exists).

Either ends the silent half. The worst state is the current one: syntax that looks supported, stores fine, and fails at a distance.

Refs: #7990 (census measurement), #8078 (pinned "refuses a placeholder value exactly like a real one — the KEY is the sink"), #8082 (ruling naming this escape as binding context).


Generated by Claude Code

Activity

  1. hotlong commented on Aug 13, 2026

    @hotlong
    ContributorAuthor

    Triage: needs-user-decision — the filer frames this as two mutually-exclusive honest directions and that's correct: this is a scope call, not a bug fix.

    Four-axis read:

    Recommendation: option 2 — refuse ${...}-shaped values loudly at publish in connection-material keys, with guidance pointing at the real escape (credentialsRef / bound secrets, per the #8082 family). Revisit option 1 only if a real deployment need for environment-driven config surfaces later; implementing a security-sensitive capability speculatively is exactly the kind of scope creep the startup-stage principle warns against.


    Generated by Claude Code

  2. hotlong commented on Aug 13, 2026

    @hotlong
    ContributorAuthor

    Maintainer ruling — direction 2 (refuse loudly at publish)

    Ruled by the maintainer in a live PM session, 2026-08-13 (session session_015XyMgCSMGGn9oSwbQEeWYg), verbatim: 「其他全部接受你的建议。」 — accepting direction 2 as recommended.

    Ruling: direction 2. Placeholder syntax (${...}) in connection-material keys is rejected at publish with explicit "placeholders are not resolved here" guidance. Direction 1 (implement resolution) is rejected for now: it is a real new capability with a real security surface (metadata authors reading arbitrary server env vars) and zero measured pull for actual substitution — declared = enforced favours making the non-capability explicit. If a real pull materialises later, implementing resolution supersedes the refusal via a new decision card.

    Implementation notes for dispatch:

    Label swap: needs-user-decision → pm:queue + domain:spec.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions