Skip to content

[finding] a named export in objectstack.config.ts whose key the default already carries is silently dropped — the build exits 0 and the authored content never reaches the artifact #18419

Description

@os-support-ai

Finding (class c — an authored stack key the build silently drops, exit 0, nothing logged)

Measured by the os-dev delivering #18171 (PR #18416) and handed to the domain:cli PM seat, which ran the dedupe. ⛔ Not graded here — lane and kind are triage's.

A named export in objectstack.config.ts whose name the default export already carries is silently discarded. The build exits 0, the artifact lacks the authored content, and ⛔ nothing is logged at any level.

Mechanism — read on origin/main, ⛔ not inferred

packages/cli/src/utils/config.ts, in loadConfig():

const merged: any = { ...baseConfig };
for (const key of Object.keys(mod)) {
  if (key === 'default' || key in merged) continue;   // ← the silent skip
  merged[key] = (mod as any)[key];
}

⭐ The loop exists deliberately and its own comment says why: 「Preserve named exports (e.g. the onEnable runtime hook and functions) alongside the default-exported stack」. The defect is the key in merged arm: a collision resolves to the default, ⛔ silently.

Measured, three rows — the third is this card

# authored result
A export const ProbeNamedExport = [1,2,3] loud — parse fails, unrecognized_keys, names the key
B export const objects = [], default carries no objects merged in and ACCEPTED
C export const objects = [one row], default already carries objects: [] config.objects === [] — the authored row never reaches the artifact, parse PASSES, ⛔ nothing logged

⇒ Row C is the trap: the author writes a stack key beside the default, the build succeeds, and the content is gone.

Why it is class (c) rather than a nit

This is metadata stored by one author and re-authored by another: the key is a declared stack key, the value is authored content, and the failure is silent on the success path. ⚠️ It is the same failure DIRECTION this board grades above a loud refusal — the reason #18170 sits at p2 and #18171 at p3 is precisely 「静默丢数据 > 响亮拒绝」.

⛔ Why it was NOT fixed in PR #18416

Closing it changes what the build accepts or refuses, which is branch-A territory on #18171 — and #18171's ruling took branch B explicitly, with branch A owing a pm:retriage back to the triage seat. ⇒ correctly filed rather than folded in.

Dedupe words

config named export shadowed · loadConfig key in merged · silently dropped stack key · objectstack.config module merge · named export collision default export

⚠️ A dedupe search was run from the PM seat before filing (the delivering agent could not). Zero hits on the specific shape; a control query on the same instrument returned 9, so the zero is a reading and ⛔ not a dead search. Nothing among the 9 covers a shadowed-key silent drop.

Refs

#18171 / PR #18416 (where it was measured; took branch B) · #18170 (the sibling silent-loss card, p2)


Generated by Claude Code

Activity

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