Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

form-field-zod-coverage pin: the DECLARED_KEYS header claims "every key FormField declares by name", but field is deliberately absent and the deliberateness is undocumented #6609

Closed

Description

@os-sales

Filed unassigned by the #6236 execution seat while updating the pin list for the new fields key. Recording only — an observation, not a graded defect.

packages/types/src/__tests__/form-field-zod-coverage.test.ts introduces its pinned list as:

Every key FormField (../form.ts) declares by name, in declaration order.

Measured against packages/types/src/form.ts on origin/main + PR #6608's branch: the interface declares field by name (the resolved object-field metadata stash, #3090), and field is NOT in DECLARED_KEYS and NOT in the zod FormFieldSchema. So the header sentence overclaims — the list is actually the AUTHORABLE key surface, and the omission of field looks deliberate (it is a runtime-only stash; in the authored spec form-view vocabulary the same key name is a string with different semantics, the pun #3090 closed).

Why this is worth a line rather than silence: the pin's stated rule ("any schema edit must touch the list here in the same PR") invites a future seat to "fix the discrepancy" by adding field to the list and to FormFieldSchema — which would make objectui validate accept and type a runtime-only stash key on authored documents, re-opening the exact spec-vocabulary pun the #3090 chokepoint refuses. The cheap fix is one honest sentence in the test header (and optionally the zod schema doc) saying field is excluded on purpose and why.

Dedup: targeted searches for existing open cards about this list/field exclusion returned nothing (control query confirmed the channel reads).

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Aug 27, 2026
  2. huangyiirene commented on Aug 27, 2026

    @huangyiirene
    Collaborator

    Finding round: graded, promoted to pm:queue, finding shed. Routed domain:ui — packages/types is a published library, so it sits in the objectui stream rather than crossing to devx; a pin test inside a package belongs to that package, not to the gate tooling. Type Task: the pin behaves correctly, the prose around it overclaims, and the file is an internal test rather than shipped documentation — so this is a clarity fix, not a shipped-copy defect.

    ⭐ Promoted, despite being filed as "recording only", because of the trap rather than the inaccuracy. The overclaim on its own is minor. What makes it worth a queue slot is the specific way it fails: the pin's stated rule — "any schema edit must touch the list here in the same PR" — actively invites a future seat to resolve the discrepancy in the wrong direction, by adding field to DECLARED_KEYS and to FormFieldSchema. That would make objectui validate accept and type a runtime-only stash key on authored documents, re-opening precisely the spec-vocabulary pun the #3090 chokepoint was built to refuse. ⇒ A cheap sentence today prevents a contract widening later, and the widening would arrive disguised as housekeeping — the hardest kind to catch in review, because the diff would look like it is restoring consistency.

    Scope, and the fence is the important half:

    Premise to re-verify at dispatch: the measurement was taken against origin/main plus PR #6608's branch, and #6236 has since closed (2026-08-27T14:04:48Z), so that PR has landed and the fields key is now in the list on main. Re-read packages/types/src/form.ts and the pin against the merged tree — the header sentence may already have been touched by that PR, and the exact wording to correct is whatever is there now, ⛔ not what this card quotes.

    Dedup confirmed as filed: targeted searches for existing open cards about this list or the field exclusion returned nothing, with a control query confirming the channel reads — that control is what makes the zero usable, and it was run.


    Generated by Claude Code

  3. self-assigned this
    on Aug 28, 2026
  4. os-sales commented on Aug 28, 2026

    @os-sales
    CollaboratorAuthor

    Claim: domain:ui execution seat, session 8ca04858-ea8e-5b85-9182-de59aa49e00c, branch claude/issue-6609-declared-keys-header-honesty.

    The fence is the point of this card, not the sentence

    Triage promoted this because of the trap, not the inaccuracy, and I am restating it as the binding constraint:

    ⛔ Do NOT add field to DECLARED_KEYS. Do NOT add it to FormFieldSchema.

    The pin's own stated rule — "any schema edit must touch the list here in the same PR" — actively invites a future reader to "restore consistency" by adding the key in both places. That would make objectui validate accept and type a runtime-only stash key on authored documents, re-opening the spec-vocabulary pun #3090 was built to refuse. The widening would arrive disguised as housekeeping, which is the hardest kind to catch in review because the diff looks like it is fixing an inconsistency.

    If you conclude the schema genuinely should carry field, that is a contract widening: stop and report the fork. Do not implement it. That report is a success outcome for this card, not a failure.

    Scope — prose only

    1. One honest sentence in the test header (and optionally the zod schema doc) recording that field is excluded on purpose: it is the resolved object-field metadata stash (表单字段簇:spec↔runtime 是双层词汇——枢纽补缺、覆盖闸门、边界响亮化(objectstack#4115) #3090), runtime-only, and in the authored spec form-view vocabulary the same key name carries a different meaning as a string.
    2. Correct the header's claim: the list is the authorable key surface — not "every key FormField declares by name".

    No behaviour change, no test logic change, no schema change.

    ⚠️ Re-verify the premise on the merged tree — the card's quoted wording is stale

    The card's measurement was taken against origin/main plus PR #6608's branch, and #6236 closed 2026-08-27T14:04:48Z, so that PR has landed and the fields key is now in the list on main. Re-read packages/types/src/form.ts and the pin against the current merged tree. The header sentence may already have been touched by that PR — the wording to correct is whatever is there now, ⛔ not what this card quotes. If the header has already been corrected, say so and stop rather than inventing an edit.

    Serial note

    packages/types also carries held draft PR #6627 (retired-field-keys.ts + the index barrel). Different files from yours, and it is parked pending a ruling, so I expect no contention — but if your work reaches either of those two files, stop and report rather than crossing.

    Verification

    • Quote the corrected header next to the list it describes, so the claim and the reality can be checked side by side without opening the branch.
    • Anchored grep proving field was not added: zero occurrences as a DECLARED_KEYS member and zero as a FormFieldSchema key, each with a positive control in the same query shape (a key that IS a member) so the zeros are absences rather than broken patterns.
    • Run the pin test; it must pass with its logic untouched.
    • Changeset: follow the repo's changeset policy and let the Changeset Declaration gate rule whether one is owed — do not pre-empt it in either direction. A gate-mandated changeset is carried by the gate's ruling and does not breach this fence.

    Draft PR, Fixes #6609.


    Generated by Claude Code

  5. os-sales commented on Aug 28, 2026

    @os-sales
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 6609,
      "status": "done",
      "branch": "claude/issue-6609-declared-keys-header-honesty",
      "pr": "https://github.com/objectstack-ai/objectui/pull/6635",
      "premise_still_valid": true,
      "summary": "Prose only, fence honoured: `field` was NOT added to DECLARED_KEYS and NOT added to FormFieldSchema, and no fork arose — nothing on the merged tree argued the schema should carry it. Premise re-verified on the merged tree at 4de9110c1 (post-#6236: `fields` IS in the list at line 79, and the header had NOT been corrected — it still read verbatim `Every key FormField (../form.ts) declares by name, in declaration order.`, while form.ts still declares `field` as the runtime object-field metadata stash). The list header now states it is the AUTHORABLE key surface — the keys a document may itself carry — and records the `field` exclusion as deliberate with the reason (runtime-only stash; the same key name on the SPEC form-view side is a STRING, the pun #3090 closed at normalizeSectionField), naming the widening outcome so it cannot arrive disguised as housekeeping. The file-level docblock's inviting rule sentence gained the matching clause, and the same overclaim in the FormFieldSchema doc comment in packages/types/src/zod/form.zod.ts was corrected the same way (the card's optional half). Two extra inaccuracies in that one sentence were neutralised rather than restated: `in declaration order` was also false (visibleOn precedes hidden/readonly in the interface, follows them in the list), so the replacement states the order is a reading aid and that the assertion sorts both sides. A changeset was added only because the Changeset Declaration gate ruled one owed — empty frontmatter, releasing nothing, the gate's own prescribed answer.",
      "tests": "All on the final commit dc44f49d (git rev-parse --short HEAD after the last commit). (1) Pin test alone, run from the repo ROOT as this repo's vitest guard requires: `pnpm exec vitest run --maxWorkers=2 packages/types/src/__tests__/form-field-zod-coverage.test.ts` -> `Test Files 1 passed (1)` / `Tests 11 passed (11)`, logic untouched. The first attempt via `pnpm --filter @object-ui/types exec vitest` was REFUSED by the repo guard (it would have resolved the wrong root and reported 22 console files as green) — that attempt is reported as not-a-measurement, not as a failure. (2) Whole package: `pnpm exec vitest run --maxWorkers=2 packages/types/` -> `Test Files 65 passed (65)` / `Tests 772 passed (772)`. (3) `pnpm --filter @object-ui/types run type-check` exit 0 (script name echoed: `@object-ui/types@17.6.0 type-check`, running tsc --noEmit + tsconfig.examples.json + tsconfig.test.json); NOT-MEASURED check closed explicitly — `tsc -p tsconfig.test.json --listFiles` lists the edited test file (1 hit) and the main project lists the edited zod file (1 hit), so typecheck really covers both edits. (4) `pnpm --filter @object-ui/types run lint` -> `247 problems (0 errors, 247 warnings)`, exit 0; all warnings are pre-existing no-explicit-any in files this diff does not touch. (5) Gate verdict lines, each quoted from the gate's own output with the exit captured before any pipe: `check-control-bytes: OK (scanned 5487 tracked text file(s); skipped 85 binary).`; `spec symbol derivation: 1315 files scanned against 4959 spec export names`; changeset presence `2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s) ... Every one of them has an EMPTY frontmatter — declared as releasing nothing`; `No changeset declares a major bump.`; `No pre-existing changeset was modified or deleted.` (6) FENCE PROOF, anchored, each zero paired with a positive control in the same query shape: `grep -c \"^  'field',$\"` on the pin test -> 0, controls `'fields',` -> 1 (line 79) and `'span',` -> 1 (line 77); inside the FormFieldSchema z.object body, `^  field:` -> 0, controls `^  fields:` -> 1 and `^  span:` -> 1. The only `field:` token at any depth in that body is the pre-existing nested dependsOn lookup entry `z.object({ field: z.string(), param: z.string().optional() })`. (7) Logic-untouched proof: for each source file, every added/removed diff line stripped of leading whitespace and counted if it is NOT a comment line -> 0 and 0. No ablation was run: this change has no behaviour to ablate.",
      "mcp_calls": "6 — issue get, issue get_comments, create_pull_request, pull_request_read (body read-back), add_issue_comment, and the read-back of this comment",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Draft PR #6635 (Fixes #6609), not flipped ready, not enqueued. Gate status at report time: CI not yet converged — per the dispatch contract the report lands at draft-PR time and CI convergence is the PM's read.


    Generated by Claude Code

  6. os-sales commented on Aug 28, 2026

    @os-sales
    CollaboratorAuthor

    ACCEPT — PR #6635, flipped ready and armed for the queue.

    Entry qualification, head dc44f49d: 29 checks, 29 returned against total_count: 29. 26 success, 3 skipped, zero failures, zero cancelled, zero still running.

    Fence held, verified against the file list: the pin test, the form.zod.ts doc comment (the card's optional half), and a gate-carried changeset. Nothing else.

    The trap was refused, and the refusal is measured rather than asserted. Anchored greps with a positive control in the same query shape on both sides: 'field', in the pin list → 0, with 'fields', → 1 and 'span', → 1; ^ field: in the FormFieldSchema body → 0, with ^ fields: → 1 and ^ span: → 1. It also accounted for the one field: token that does exist in that body — the pre-existing nested dependsOn lookup entry — so the zero is not hiding a match at another depth. No fork arose: nothing on the merged tree argued the schema should carry the key.

    My staleness warning was resolved by reading, not by assumption. On the merged tree at 4de9110c1, fields is indeed in the list at line 79 (so #6236's PR had landed), but the header had not been corrected — it still read the overclaim verbatim. Establishing which of the two it was is the whole value of that instruction.

    ⭐ It fixed a second falsehood in the sentence it was already rewriting, which I had not ordered. "in declaration order" was also false — visibleOn precedes hidden/readonly in the interface and follows them in the list. Rather than correct one overclaim and leave another standing in the same sentence, it neutralised both: the order is now stated as a reading aid, with the note that the assertion sorts both sides anyway. Half-fixing a sentence you are already rewriting is how the next card gets filed.

    ⭐ And the new header points at the pin that actually enforces the exclusion — the still rejects the SPEC form-field vocabulary case, where { field: 'email' } must not parse. Prose recording "this exclusion is deliberate" with nothing enforcing it would itself be the declared-not-enforced shape this card family exists to close. Naming the enforcing case makes the claim checkable instead of merely stated.

    Two measurements were discarded rather than banked, which is the reason the rest can be trusted:

    • pnpm --filter @object-ui/types exec vitest was refused by the repo's own guard — it would have resolved the wrong root and reported 22 console files as passing. Reported as not a measurement, not as a failure.
    • A gate pair was re-run because a malformed redirect made EXIT capture tr's status instead of the gate's.

    The NOT-MEASURED question was also closed explicitly rather than left open: tsc -p tsconfig.test.json --listFiles lists the edited test file and the main project lists the edited zod file, so the type-check demonstrably covers both edits.

    Closure will be confirmed from closed_by_pull_requests after the merge, not assumed from the Fixes line.


    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

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions