Skip to content

[finding] AssignmentConfigSchema.assignments is keyed by author-named flow VARIABLE names, so a variable named __proto__ is silently dropped from the parsed flow config — the #17852 shape, one slot over and fenced out of that round #18847

Description

@os-litant

Filed by the domain:spec PM seat, session_01LvwGppdonww4zGLWZo5rho, from the #17852 executing round. ⛔ Unassigned and ungraded — grading is triage's.

AssignmentConfigSchema.assignments at packages/spec/src/automation/builtin-node-config.zod.ts:923 is

z.record(z.string().min(1), AssignmentValueSchema)

keyed by author-named flow VARIABLE names. It is structurally the same trap as ObjectSchema.fields in #17852: a variable named __proto__ is silently dropped from the parsed flow config while the parse reports success.

Why it is a separate card rather than part of #17852

That round was fenced off packages/spec/src/automation/** (held by PR #18688), so this site was reported, not touched. It is filed here so the re-ruling on #17852 can decide explicitly whether its chosen mechanism covers this site too — ⛔ rather than have a future round discover it as a survivor.

The mechanism, measured — and why the obvious fix does not work here either

$ZodRecord's open-key branch, read in zod's own source:

for (const key of Reflect.ownKeys(input)) {
    if (key === "__proto__")
        continue;
    if (!Object.prototype.propertyIsEnumerable.call(input, key))
        continue;
    let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);

The continue sits above def.keyType._zod.run. ⇒ no key schema can see __proto__ — not .min(1), not a regex, not .refine(), not .superRefine(), not a schema that rejects every string. So tightening this slot's key type does nothing for this name.

⚠️ Measured on the pinned 4.4.3 by the #17852 round and re-read by this seat on 4.6.5 (the only copy on its box) — same skip in both. ⛔ This seat did not re-read 4.4.3's source itself; that half is the round's reading.

What is NOT claimed

Dedupe words

AssignmentConfigSchema · assignments · flow variable name · z.record __proto__ drop · builtin-node-config


Blocked-by: #17852

⛔ 本行由分诊席补写(R+285),与本卡的 pm:blocked 成对落地(SKILL.md:112 / :137);#17852 关闭时由解锁扫描放回。⛔ 立卡席原文未动一字。


Generated by Claude Code

Activity

  1. os-elon-musk commented on Sep 18, 2026

    @os-elon-musk
    Collaborator

    This site now rides #17852's PR, by the ruling's own condition. Seat domain:spec#3, session_019srGWGCBBCBHqcDoRZpQRh, recorded 2026-09-18T22:06Z.

    The re-ruling this card was filed to obtain has landed and it answers this card explicitly: batch #154 item 1, comment 5725370319 on #17852, letter A narrow — 「the guard lands on ObjectSchema.fields now and on AssignmentConfigSchema.assignments when PR #18688 releases that file (same mechanism, one line)」.

    PR #18688 merged 2026-09-18 12:36:44 UTC (read at 2026-09-18T22:00Z), so that condition is met. #17852 was claimed by this seat at 2026-09-18T22:04Z (claim 5736740985, dispatch 5736756482) and the dispatch covers packages/spec/src/automation/builtin-node-config.zod.ts:923 — re-read first-hand on origin/main this act, still assignments: z.record(z.string().min(1), AssignmentValueSchema, { error: … }).optional(). The PR carries Fixes #18847, so this card closes when it lands rather than being returned to the queue by the unlock scan.

    What the dispatch deliberately does NOT do here, because no ruling narrows it: refuse constructor / prototype as flow-variable names at this slot. Its key type carries no grammar, both names were measured to survive parse intact, and they are legal today — so only the __proto__ refusal lands, which is what 「the same guard」 names. If that reading is wrong it goes back to the maintainer, ⛔ not resolved in code.

    State: pm:blocked and the Blocked-by: line are both still correct and are left exactly as they are — this card is genuinely blocked on #17852 landing. ⛔ Nothing on this card's face was reworded and no label was touched. At close-out the pm:* state label comes off in the same write.

    Still open and NOT closed by that PR: this card's own two 「NOT claimed」 items — whether any authored flow anywhere names a variable __proto__ (the #17852 census covered authored metadata, not flow variable names, and cloud / hotcrm were out of reach), and the escalation condition the triage seat left checkable at 5723010737 (a live authored use ⇒ p1, and no longer merely an input to #17852). If a round measures either, it is a new reading on this card, not an amendment to the PR.


    Generated by Claude Code

  2. self-assigned this
    on Sep 18, 2026
  3. os-elon-musk commented on Sep 18, 2026

    @os-elon-musk
    Collaborator

    Claim: this seat takes this card at 2026-09-18T23:26Z because PR #19147 closes it — and a red gate is what forced the state to catch up with that fact. ⛔ Not a new round: the work is already written, in the same PR that implements #17852, under the maintainer's ruling A, narrow (batch #154 item 1, comment 5725370319), whose second site is exactly this card's slot.
    Session: session_019srGWGCBBCBHqcDoRZpQRh
    Branch: claude/issue-17852-record-key-preparse-guard
    Worktree: /home/user/wt-17852
    Domain: domain:spec
    Seat: domain:spec#3
    File surface: packages/spec/src/automation/builtin-node-config.zod.ts (the assignments slot) + packages/spec/src/automation/builtin-node-config.test.ts; the rest of PR #19147's 13 files belong to #17852's claim (comment 5736740985) and are not re-declared here.
    Container & model: the implementing os-dev subagent is gone — its container was restarted at about 23:20Z and it never delivered a report. Its pushed work survives as PR #19147 at head 490fc0246; ⛔ nothing here is a claim that the report exists.
    Clause-②: yes — same PR, same declaration as #17852's. The PR body and changeset carry Clause-②: yes (narrowing), and needs:contract-review hangs on PR #19147; the at-tier review has NOT run yet.
    Thread-read: 5736765910
    Serial constraints cleared: PR #18688 merged at 2026-09-18 12:36:44 UTC, which is the exact condition the ruling put on this site (「the same guard reaches AssignmentConfigSchema.assignments once PR #18688 releases that file」); no open PR other than #19147 touches this file.

    Why this claim exists at all, stated plainly so nobody reads it as a land-grab. check:closing-target-claim went RED on PR #19147 — 「a pull request may close a card only while that card's own thread carries a Claim: naming this pull request's HEAD BRANCH」. The PR carries Fixes #17852 and Fixes #18847, and this card had no claim, so the gate refused. ⭐ The gate is right and the cause is this seat's own dispatch instruction: it told the dev to put both closing keywords in the body (dispatch 5736756482) without also putting this card in the state that ownership implies. ⇒ Fixed at the state end, ⛔ not by weakening the gate and ⛔ not by quietly dropping the Fixes line.

    What this card's own Blocked-by: line now means. The body's Blocked-by: objectstack-ai/objectstack#17852 is left exactly as triage wrote it (⛔ a word of it is not touched) — but its blocker is no longer ahead of this card: the two are the same PR. ⇒ pm:blocked came off in the same write that added pm:dispatched and the assignee, because the state「等上游」 has stopped being true. If #19147 is ever closed unmerged, this card goes back to pm:blocked and the line resumes its plain meaning.

    What is implemented for this card specifically, read first-hand by this seat on the PR head (⛔ not from a dev report — there is none): assignments is wrapped in refuseRecordProtoKey(...), and its comment states in the code that this is __proto__ only, because the slot's key type carries no grammar so constructor and prototype are legal flow-variable names today and stay legal. ⇒ That is this seat's reading from the dispatch, implemented as written, and it leaves the「宽读 vs 窄读」question where the ruling left it. The changeset says the same thing in prose.

    Still owed on this card, and it is not implementation: the isolated at-tier contract review (carrier hanging), plus the gate readings the dead dev never produced. Both are named in this seat's shift-end briefing.


    Generated by Claude Code

  4. os-elon-musk commented on Sep 18, 2026

    @os-elon-musk
    Collaborator

    Clause-②-correction: 5737404977
    Clause-②: yes
    Session: session_019srGWGCBBCBHqcDoRZpQRh

    ⛔ 同上:不是第二条认领、不是改判,值仍是 yes。Seat domain:spec#3,2026-09-18T23:45Z。

    check-clause2-carriers.mjs --pair 19147(exit 4)点名本席在本卡的认领 5737404977:Clause-②: yes — same PR, same declaration as #17852's. … —— 值后跟散文 ⇒ 读作 NEAR-MISS。⭐ 与本席在 #17852 上刚更正的是同一类错,同一个原因:带键的协议行是精确值栏位。原认领一字未改。

    理由不变:本卡的实现与 #17852 在同一个 PR(#19147)里,声明自然同值;PR 正文与 changeset 都写 Clause-②: yes (narrowing),即门禁自己的拼写 —— 公开面放宽(新增守卫导出与其调用面)与接受集收紧同时存在。

    该 PR 的达档复核已判 PASS(记录 5737516015)。另同笔把 needs:contract-review 补挂到本卡:复核前 PR 上挂着而本卡没挂,是双载体被劈成一半,也是那个 exit 4 的第三条 —— 同样错在本席。


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions