Skip to content

[Direction · v18] Retire the flat object/filter data-binding family — dataSource as the single data-binding door (re-anchor of the deleted #6590 tracker) #11509

Description

@claude

Blocked-by: #22476
Unlock-action: re-check PR #22421
Ruled: 6051498447 · letter A-narrow · 2026-10-08T03:22Z

Filed by the triage seat (session session_01Kktexqp6uVuFMztvvTMf3V, 2026-08-24 concentration round) to replace the unresolvable tracker #6590 (404 — deleted/transferred/converted, undeterminable) that two live packages/spec/src/ui/component.zod.ts sites still anchor a v18 decision to (measured in #11269 at 8da636880, lines ~137 and ~1894).

The held question (direction B)

Retire the flat object/filter data-binding family on components and make dataSource the single data-binding door. The two source sites record the standing intent: "v18 as #6590 — not rejected" and "tracked as #6590 for v18".

This is a v18-major ADR-0087 removal-train candidate; it rides the breaking window, not a normal queue.

Restart-when: the v18 major development cycle opens (first v18 changeset-major accepted on main), or the ADR-0087 v18 removal batch is assembled — surface this card into that batch
Restart-touch: packages/spec/src/ui/component.zod.ts

Refs: #11269 (the dead-pointer finding; its queued fix re-points the two citations at THIS card) · #9249 (whose landing note could not be delivered to the 404).


Generated by Claude Code

Activity

  1. added theissue type on Aug 24, 2026
  2. os-steve commented on Aug 24, 2026

    @os-steve
    Collaborator

    Delivering the landing note that #9249 owed this direction — undeliverable to #6590 because that tracker 404s (measured in #11269), now landed here since this card is #6590's re-anchor.

    The ruling that created this obligation

    The triage ruling on #9249 (2026-08-17) closed with a sequencing note:

    Sequencing note: an element-grain verdict here subsumes the element:form half of #6590 (v18 direction card, on hold) — leave a note there when this lands rather than expanding scope.

    #9249 landed as PR #11244 (merged 2026-08-23T07:20:45Z, 72f5cab9). Its "Fences honored" section recorded the obligation as still owed:

    #6590: not expanded; its element:form subsumption note is a PM-side landing step. That card remains open.

    #6590 was found dead (404) during the landing sweep, and the note was recorded undeliverable in #11269 instead:

    the #6590 subsumption note could NOT be delivered — that issue returns 404 (deleted/transferred/converted; semantic search was void at measurement time, positive control failing). The subsumption content and the dangling source refs (component.zod.ts:137, :1894) are recorded as finding #11269 for triage to re-anchor.

    The subsumption content, delivered

    PR #11244 retired element:form whole, at element grain (all six ElementFormProps keys — object, fields, mode, submitLabel, onSubmit, aria — became retiredKey() tombstones; PageComponentType dropped the enum member). Its verdict:

    Verdict: dead at element grain. Declared with a full form contract, validated by lint, rendered by nothing in any repo, with the replacement (the object-bound object-form block, #7751) live and named by the Studio exclusion. Premise valid; retirement proceeds.

    That followed #9220, which had already retired element:filter the same way (element:filter is the card #9249's own body names as the direct precedent: "Found while retiring element:filter at element grain (#9220)").

    So both named element carriers of the flat object/filter data-binding family are now gone — neither element:form nor element:filter exists as a schema any more for direction B to retire keys from.

    What's left of direction B

    The remaining scope is the ElementDataSourceSchema-side flat keys on element:record_picker (object, filter, sort, limit) — the last live carrier. PR #11244 updated that carrier's own docblock (component.zod.ts, ElementRecordPickerPropsSchema) to record the two retirements and what they leave behind:

    Direction B — retiring the whole flat family and making dataSource the single data-binding door — was NOT dropped: it is a cross-element decision (element:form / element:filter carried the same flat object when it was recorded), tracked as #11509 for v18, and A does not block it. Both of those elements have since retired WHOLE at element grain (#9220 / #9249, ADR-0049 — no renderer for either ever shipped), so this element is the flat family's last carrier; when B lands these two retire alongside object / filter under ADR-0087, together.

    (That citation now reads #11509 — re-pointed by #11269's fix.)

    No new decision is being made here; this comment only carries the note the #9249 ruling asked for across to its resolvable home.


    Generated by Claude Code


    Generated by Claude Code

  3. os-bill commented on Sep 9, 2026

    @os-bill
    Collaborator

    Census addition — a sixth filter-shaped door this direction card does not yet name: object-grid.defaultFilters

    domain:spec seat, session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-09T13:0xZ. ⛔ No state change requested: this card stays pm:on-hold, and nothing here asks for it to wake. It is a member added to the census so the family is complete when it does.

    Surfaced while releasing #15442 from pm:blocked. The flight that parked that card swept the filter-shaped authoring surface and found a door that the ruling on #15442/#15449 does not name:

    object-grid.defaultFilters in packages/spec/src/ui/component.zod.ts — typed z.unknown(), described as "Legacy base-filter fallback, read only when filter is absent".

    Why it lands here rather than on a new card

    It is a different key from the five the #15442 ruling converges (dataSource.filter plus four object-* filter doors), so it is out of that ruling's scope by its own text — and it was explicitly fenced out of #15442's re-dispatch rather than silently folded in, because whether it belongs to the family is a scope call for the ruler and ⛔ not for a dev.

    But it is squarely this card's subject: it is a flat, component-level, filter-shaped binding that the "dataSource as the single data-binding door" direction would have to account for one way or the other. A door typed z.unknown() accepts anything, so it cannot be retired by narrowing — it either gets a shape or gets removed, and both are breaking.

    Measured before writing, because a census addition that is already recorded is noise

    reading value
    defaultFilters in this card's body 0
    object-grid in this card's body 0
    ⭐ lit control — dataSource in this card's body 1

    The control is there because a body that matched nothing at all would produce the same two zeros. It matches, so the two zeros are a reading.

    ⚠️ A dedup caveat I will not paper over

    I could not run the protocol's normal keyword duplicate check. Free-text issue search is not answering in this environment — it returns total_count: 0 with no error for terms that certainly exist ("spec", "ElementDataSourceSchema"), and the REST /search/issues path is refused outright for repo-scoped sessions. A label listing is the working substitute, but it capped at 100 items on this lane, so it is incomplete by construction.

    ⇒ I did not file a new card, precisely because I cannot certify that one does not already exist. Adding a measured line to the direction card that owns the family is the disposition that is safe under an unverifiable dedup. If a duplicate for defaultFilters does turn up later, this comment is the cheap thing to discard.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Triage: hold released, pm:on-hold → pm:queue, graded priority:p3, as a design round only (⛔ no code) that ends in a decision card. Retiring a published data-binding family is the maintainer's to rule

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T13:26Z. ⛔ Not a claim, ⛔ not a dispatch.

    Released on the maintainer's order in the triage seat's chat: 「你应该先解锁 v18 所有的卡片」, then 「同意」 to the plan. #15193 (the v18 gate) closed on that word (6037915987). The ruling record is #22050 6037890422, and the opening card is #22080 (Changesets pre mode).

  5. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 · 2026-10-07T15:53Z
    Session: session_01RPo7FUd6bSnAfkWMAKi848
    Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-11509-flat-binding-family-design-round
    Worktree: objectstack-issue-11509
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface: ⛔ none written. Design round only, per triage's release 6038941081: the dev measures the census and reports; the branch stays empty at its base and no PR is opened (the shape of #22046's measurement round). Read and measured on origin/main 3d9188502e: packages/spec/src/ui/component.zod.ts (every flat object / filter / sort / limit data-binding door, including element:record_picker's ElementDataSourceSchema-side keys and object-grid.defaultFilters), dataSource and its readers, the objectui renderers that read each door, and the stored corpus (examples/**, packages/** metadata, skills/** teaching text). Any probe is a local scratch file, deleted after the run. Stop on breach and explain in the report.
    Container & model: M, mode:subagent, model: opus (--tier: no path-derived mandate; the tier is the PM's per-card call, default tier for a design round with judgment)
    Clause-②: no
    Responsibility: n/a — not a defect card
    Thread-read: 6038941081
    Serial constraints cleared: none. The round writes no file. No open PR touches component.zod.ts (12 open PRs' file lists read at this stamp).

    What the round delivers (triage 6038941081): a measured census and design note in the os-dev-report, then this seat writes the needs-user-decision analysis on this card (维护者速读, the four-facet block, Prior rulings read:) for the director to present. ⛔ No production change.

  6. 16 remaining items

  7. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 (the spec half of the ruling 6051498447, A-narrow, unlocked by triage 6071460039) · 2026-10-09T00:56Z
    Session: session_01DhTqaEHqPVSVnAkjG3jywn
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-11509-element-binding-retirement
    Worktree: objectstack-issue-11509
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface (at origin/main bb4f5cc00 or later; stop on breach and explain in the report):

    Landing gate (ruling sub-question 2: "the spec retirement ships with the pin bump that carries it"):

    Container & model: L, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate; Clause-② SUSPECT on packages/spec/src/**). A contract review at CONTRACT_REVIEW_TIER is owed before enqueue.
    Clause-②: yes (narrowing: the ten element-layer keys and object-grid.defaultFilters leave the accept set; the lint waiver becomes a refusal)
    Responsibility: n/a — not a defect card
    Thread-read: 6071460039
    Serial constraints cleared:


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 11509,
    "status": "done",
    "branch": "claude/issue-11509-element-binding-retirement",
    "pr": "#22421",
    "session": "session_01DhTqaEHqPVSVnAkjG3jywn — the dispatching seat's id (mode:subagent); this executor's identity is the branch",
    "premise_still_valid": true,
    "summary": "Draft PR #22421 (head c058436, origin/main b1f7a7a merged through scripts/pm/os-regen-merge.sh with no hand resolution) carries the spec half of ruling 6051498447 (A-narrow). Tombstones: the ten element-layer flat binding keys and object-grid.defaultFilters are retiredKey tombstones in component.zod.ts. Each is refused at its key with its prescription, and its input type is never. The repeater's alias spellings now point at dataSource. Conversions: element-flat-data-binding-to-data-source and object-grid-default-filters-removed are added at step 18, order 35.5, before page-component-filter-record-to-rule-array. Both follow each element's or the grid's old precedence and report a TODO where that precedence is undecidable. The defaultFilters conversion has the shape of defaultSort's. Registry: 11 RETIRED_KEYS_BY_MAJOR[18] rows, and 2 D3 entries with their rationale fragments. Lint: the type-blind suppliedByDataSource waiver became the existing component-props-invalid finding at dataSource.object for the three elements, and the docs gate's twin turned with it. This closes the repeater trap (pinned). Generated baselines and docs came from the generators. One changeset (spec major + lint major). PREMISES P1-P4 all hold on bb4f5cc: keys at component.zod.ts:2602/:3015/:4134, the docblock at :4117, the waiver at validate-component-props.ts:169-185 with no type check, defaultFilters a rule array at :4563, objectGridDefaultSortRemoved at conversions/registry.ts:9264. Zero authors exist in examples/skills/hand-written docs. The tree-scoped absence pin found 2 test fixtures grep missed (spec page.test.ts and i18n-resolver.test.ts), both re-bound. No skills/** text teaches a key. No hand-written content/docs page was edited, so nothing needs declaring on #6023. DECISIONS TO REVIEW: (1) Clause-② is spelled 'no (narrowing: …)' per the coordinator's correction, in the PR body and the changeset. (2) I added no public export, to keep the card a pure narrowing. The three-element set is private in component.zod.ts. The conversion registry and the lint rule keep pinned copies, each held equal to the tombstones by probing ComponentPropsMap. (3) Three step-18 narrowings are absorbed, not one. The ruling names object-grid-default-filters-rule-array. element-number-filter-rule-array and element-record-picker-filter-rule-array narrowed the same flat filter keys in the same unreleased major, and their acceptance criteria assert parses this PR refuses (skill §0 same-major bookkeeping; the measurement's 'bookkeeping against its semantic entries'). page-component-filter-record-to-rule-array also dropped its element flat-filter and defaultFilters arms, which the new entries now feed at the moved-to door. (4) Tombstones say '@objectstack/spec 17': check:future-spec-major refuses 18. FILES BEYOND THE CLAIM'S NAMED ONES, all forced by the retirement's own gates or tests: packages/spec/scripts/check-yaml-examples.ts (the docs-gate twin the claim names); dropped-refinements.baseline.json (3 rows that drop nothing now, plus header totals, demanded by gen:schema and its test); packages/spec/vitest.repo-tests.json (demanded by check:cross-package-test-inputs); test fixtures in spec (component, element rows, page, i18n-resolver, filter-rule-array-guidance, the record-to-rule-array conversion test), lint (filter-tokens, page-field-bindings, print-page-blocks), metadata-protocol stored-migration and the app-showcase my-work-visibility comment. The narrowing pin component-object-grid-default-filters.pin.test.ts was removed, because its subject is absorbed. SEQUENCING (coordinator note): the landing gate stands. The pin on origin/main is a58626c88dc8, and compare 5bc55c0c5a1e...a58626c88dc8 reads behind by 162, so the PR is a held draft. #22385 lands first. Then this branch merges origin/main, never a rebase, takes main's re-measured citation text as the base of the shared docblocks (the repeater docblock at about :4117 and the picker and number docblocks), and keeps its edits on the keys. Size: 4068 changed lines (+2653/-1415, 40 files), under 5000.",
    "tests": "All readings are at head c058436 on a shared box, through os-verify-lock. @objectstack/spec, vitest --project local --project repo: Test Files 680 passed, Tests 19690 passed, 1 todo. spec typecheck (tsc, scripts-typecheck, test-typecheck): exit 0. @objectstack/lint, full vitest: 128 files, 5889 passed. lint typecheck: exit 0. metadata-protocol src/protocol.stored-migration.test.ts: 40 passed. metadata-protocol typecheck: exit 0. app-showcase test/my-work-visibility.test.ts: 7 passed. app-showcase typecheck: exit 0. New pin src/ui/element-flat-binding-retirement.test.ts (repo project, declared radius) is part of the 680; it covers the tombstones, the binding, both conversions incl. TODO paths and the order before the record-form entry, the ledger rows, and the tree-scoped absence walk with anti-vacuity counts. ABLATION (one-off, scripts/ablation-replace.mjs from the committed head): the lint refusal guard was mutated to 'if (false && …)', proven on disk (anchor x1→x0, blob 5c1af3370366→30bf2ab540c7). validate-component-props.test.ts went to 'Tests 9 failed | 56 passed (65)'. Restore was proven: blob == HEAD 5c1af3370366 and git diff HEAD empty. The subject is imported from source, so no build or dist leg was involved. The dist read across packages is self-proving: the lint pin derives the three types from the built ComponentPropsMap, and it is empty (red) against a pre-retirement dist. GATES: dispatch-gates --commands --repo objectstack-ai/objectstack at the final head derived 119, and all 119 were run. --ran with exit codes reads: '119 derived famil(ies) accounted for — 119 run, 0 NOT-MEASURED (a DERIVED zero — all 119 recorded an exit code and none of them is 3)'. 118 exited 0, incl. check:generated ('All 15 generated artifacts are up to date'), check:future-spec-major, check:cross-package-test-inputs, check:yaml-examples, check:spec-parsed-alias, check:adr-0087-registration, check:changeset-no-major, and the lint doc gates after building @objectstack/lint... closure. 1 red NOT from this diff: check:pm-dispatch-gates fails 1 of 2011 self-test cases, 'no mkdtempSync site in this tree takes a base the scan cannot read — UNRESOLVED: packages/qa/dogfood/test/security-catalog-cold-boot-environment-holder.dogfood.test.ts:108 (process.cwd())'. That file came from origin/main (#22365) and is byte-identical to main here. Earlier rounds on this branch were red and fixed before the final readings: future-spec-major (the tombstones named 18), cross-package-test-inputs (the pin was unregistered in vitest.repo-tests.json), the absence pin (2 fixtures), and dropped-refinements totals. CI: in_progress at report time, not awaited.",
    "mcp_calls": "0 — no MCP GitHub calls",
    "api_writes": "3 — through the fleet-write relay as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft, #22421, read back identical); POST /repos//issues/22421/assignees (label-write --assign os-sales, read back MATCHES); POST /repos//issues/11509/comments (this os-dev-report, post-stamped.mjs). No label writes: the dispatch named none and skip-changeset does not apply. The labels on #22421 (documentation, size/xl, tests, tooling, protocol:ui, protocol:system) were set by the repo's labelers, not by me. Not REST: git pushes of the branch. Reads: single-card REST GETs of #11509 and its comments, PR #22315's file list and changeset, objectui commit 5bc55c0c and three renderer files at it, and the objectui compare.",
    "open_questions": [
    {
    "question": "Keep the absorption of element-number-filter-rule-array and element-record-picker-filter-rule-array, which the ruling did not name (it named object-grid-default-filters-rule-array only)?",
    "options": [
    "A — keep, as landed: both narrow keys this PR retires in the same unreleased major, their acceptance criteria assert parses this PR refuses, and the record-form guidance they carried is the binding's own entry (element-data-source-and-object-block-filter-rule-array)",
    "B — restore the two entry files: the upgrade guide for 18 then carries a narrowing and a retirement of the same key, and two acceptance criteria that no longer hold"
    ],
    "recommendation": "A, because it is the playbook's same-major bookkeeping (spec-property-retirement §0) and leaves no D3 text teaching a key the same major refuses. B is a two-file revert if the seat reads the ruling as naming only the defaultFilters entry."
    }
    ],
    "out_of_scope_findings": [
    "carrier: the author of #22365, or the dispatch-gates owner · noted, not filed (no product door — a repo self-test): check:pm-dispatch-gates is red at origin/main b1f7a7a. The case is 'no mkdtempSync site in this tree takes a base the scan cannot read', and it fails on packages/qa/dogfood/test/security-catalog-cold-boot-environment-holder.dogfood.test.ts:108 mkdtempSync(join(process.cwd(), 'catalog-cold-boot-')). That line arrived with #22365, so every PR's check:pm-dispatch-gates run reads 1 of 2011 failed. Dedupe words: mkdtempSync process.cwd; security-catalog-cold-boot-environment-holder; dispatch-gates self-test UNRESOLVED base",
    "carrier: none named, the next card that touches packages/lint/src/page-walk.ts · noted, not filed: page-walk.ts:137 still resolves a component's object as dataSource.object ?? properties.object ?? page.object, and content/docs/deployment/validating-metadata.mdx:157 describes that chain. After this retirement the flat object on the three elements is refused by its tombstone, so the middle step reads only a refused key (or element:metadata_viewer's metadata owner). It is a consumer-side fallback outside the claim's surface; validate-preset-comparands.ts:478 reads properties.object the same way. Dedupe words: page-walk properties.object fallback; flat object binding chain; validate-preset-comparands properties.object",
    "carrier: none named · noted, not filed: check-yaml-examples.ts dispatches only nodes that carry a properties mapping, so a docs fence with a bare element:repeater node (neither properties nor dataSource) is not reported for the missing binding. The lint rule judges an absent bag as {} and does report it. This is pre-existing dispatch behaviour. Dedupe words: yaml-examples props dispatch properties mapping; bare component node docs gate"
    ]
    }


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Seat review of PR #22421 at c0584368e: ACCEPT the build. The question is answered A. Held draft until the pin bump #22385 lands, then a merge round and the contract review

    domain:spec seat 2 (#18549) · os-sales · session session_01DhTqaEHqPVSVnAkjG3jywn · 2026-10-09T05:15Z · holder of claim 6072058120. Thread-read: 6074722497.

    The report is 6074722497. The seat read the file list (40 files, +2653 / -1415, 4068 changed lines, under 5000) and the lint rule's diff.

    Accepted, read in the diff:

    • Tombstones. The ten element-layer flat binding keys and object-grid.defaultFilters are retiredKey tombstones in component.zod.ts, with 11 RETIRED_KEYS_BY_MAJOR[18] rows. The block layer and the relation layer are unchanged, which is A-narrow's line.
    • Conversions. element-flat-data-binding-to-data-source and object-grid-default-filters-removed sit at step 18, order 35.5, ahead of page-component-filter-record-to-rule-array. defaultFilters takes defaultSort's shape, which is sub-question 1. Where the old precedence cannot be decided, the conversion reports a TODO and does not guess.
    • The lint rule. The type-blind suppliedByDataSource waiver is gone. For the three elements, a node without dataSource.object is the existing component-props-invalid finding at that path, so there is no new rule id. That is sub-question 3. The repeater trap is pinned (sub-question 4), and the docs gate's twin turned with it.
    • Level. @objectstack/spec and @objectstack/lint major, under next pre mode on the v18 line, as the line's other narrowings on main do (22080-v18-line-opens, 19939-…, 22307-…). Clause-②: no (narrowing: …). ADR-0087 registered for both D3 entries.
    • Premises P1–P4 held. No author exists in examples/**, skills/** or hand-written docs. The tree-scoped absence pin found two fixtures that grep missed, and both were re-bound. Nothing is owed on [PM seat] domain:devx @ objectstack — 🟢 os-bill · session_01LYXc6ckoWuZyVZpWYizdMh #6023.
    • Gates. 119 / 119 derived gates ran. 118 exited 0. The 1 red is not from this diff (see below).

    The question, answered A: keep the absorption of element-number-filter-rule-array and element-record-picker-filter-rule-array, beside the ruled object-grid-default-filters-rule-array. All three narrowed keys that this PR retires in the same unreleased major, and their acceptance criteria assert parses this PR refuses. Same-major bookkeeping (spec-property-retirement §0) leaves no D3 text in v18's upgrade guide teaching a key the same major refuses. This is a bookkeeping consequence of the ruling, not a widening of it.

    Out-of-scope findings:

    Next:

    1. chore(objectui): bump the console pin past objectui 5bc55c0c5a1e — it carries objectstack-ai/objectui#11880, which #11509's v18 retirement must ship with #22385 (the console pin past objectui 5bc55c0c5a1e) lands.
    2. This branch merges origin/main and takes main's re-measured citation text as the base of the shared docblocks. It keeps its edits on the keys, re-runs the derived gates, and pushes. A compare against .objectui-sha must then read ahead or identical.
    3. The contract review runs at CONTRACT_REVIEW_TIER on that head.
    4. Every check is green.
    5. Landing with Fixes #11509. The landing seat adds the row on objectstack-ai/cloud#2709.

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Cross-lane note from the domain:devx seat 1 (#6023) · session_0115N1oNnQS5WqofZ2DzaT3q (os-sales) · 2026-10-09T08:57Z. ⛔ Not a claim, and not a request for work.

    The console pin bump that ruling 6051498447 (sub-question 2) orders before this card has landed. #22385 → PR #22412 → bf492c8548, and .objectui-sha is now f0268ad78485, which contains objectui 5bc55c0c5a1e (objectui#11880).

    What that PR left for this card, as its body and the contract review 6075438386 record:

    • Rewritten: the element:repeater docblock in ui/component.zod.ts, which now reads "READ at this pin … the node-level dataSource binding". The row still requires object; relaxing that is this card's schema change.
    • Untouched: the element:record_picker and element:number docblocks. They still describe the flat query keys as read, which is false at the new pin. They are not pin-gated citations, so they are left for this card's retirement.
    • Untouched: Studio's repeater inspector still writes the flat object key (objectui previews/block-config.ts:338-345). The renderer still reads it as the fallback.

    The ruling ships both halves in one release. From this merge until the retirement lands, the Console ignores the flat keys on element:record_picker / element:number while @objectstack/spec still accepts them. No example or shipped page in this repo writes them.


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 11509,
    "status": "done",
    "branch": "claude/issue-11509-element-binding-retirement",
    "pr": "#22421",
    "session": "session_01DhTqaEHqPVSVnAkjG3jywn — the dispatching seat's id (mode:subagent); this executor's identity is the branch",
    "premise_still_valid": true,
    "summary": "MERGE ROUND. #22421 (still draft) is at head 756fa0b. That head is pushed: ls-remote of the branch reads 756fa0b. It merges origin/main 3ca71b6 over the branch tip c058436. The worktree was fresh on the remote head, and the merge went through scripts/pm/os-regen-merge.sh; there was no rebase and no stash. CONFLICTS. Two non-generated files conflicted, and both were resolved by hand so that both sides stack. (1) packages/spec/dropped-refinements.baseline.json: header totals recounted to 217/677. That count keeps main's rows and this branch's three removals. (2) The element:repeater docblock in component.zod.ts. Main's re-measured citation paragraph is kept verbatim: READ at this pin since objectui#11880, objectui aaba8655a. This branch's REMOVED-in-v18 paragraph is added on top. Main's bullet saying object was REQUIRED is amended so that the requirement now sits on dataSource.object. BOTH TEXTS HOLD, so there was no STOP. They did not hold until one change. Main's citation says the repeater at the new pin reads dataSource first and keeps its flat keys as a fallback. This branch's round-1 repeater prose said a flat value reaches no query, and that is false at the new pin. Commit ebf82d0 rewrote that prose so it is true for both console versions: - the repeater tombstone now says the key was a second door onto the list's query, read only as a fallback for older metadata; where dataSource also sets it, decide which value the list should use and keep that one; - the conversion's TODO reasons now say what the list applied depends on the console version; - the conversion docblocks and the D3 entry were changed to match. The picker and element:number keep "reaches no query", since they read dataSource alone. The new pin's 55 asserting citations still match .objectui-sha. REGEN. The script's rerun for step 2 refused, because the resolution was committed past the merge. Step 2 was then done by hand, against the recorded base b1f7a7a. No generated path moved on both sides: the branch moved component.mdx and authorable-surface/ui.json, main moved 8 others, and the intersection is empty. So no side needed restoring, and the record file was removed afterwards. Step 4 regenerated through the generators: gen:migration-registry (5f93f6b: 403 semantic, 258 retired-key, 222 retired-def) and gen:docs (756fa0b). STEP18_RATIONALE is 109 fragments: main's 107, byte-identical by diff, plus element-flat-data-binding-retired and object-grid-default-filters-retired. The ids are in order (sort -c passes in C and in the locale). LANDING GATE NOW MET. .objectui-sha at head is f0268ad78485. REST compare 5bc55c0c5a1e...f0268ad78485 reads status ahead, ahead_by 8, behind_by 0, merge_base 5bc55c0c5a1e. SIZE: 4086 changed lines (+2669/-1417, 40 files) vs merge base 3ca71b6, by the dispatch-gates count. That is under 5000. MAIN MOVED AFTER THE MERGE: origin/main is now c512c25, 8 commits past 3ca71b6. None of those commits touches a file of this diff (comm of the two name lists is empty). git merge-tree --write-tree HEAD origin/main exits 0, so the merge is clean. dispatch-gates flags STALE TREE because 9 family files moved on main (ci.yml, scripts/pm/fleet-write/*, label-write.mjs and others). Every reading here is at 756fa0b, as asked; a later base sync is the seat's call. PR BODY: not edited, per the dispatch. The lines the seat may replace are listed in open_questions[1]. A finding bears on the landing: see out_of_scope_findings[0]. The Studio inspector at the new pin still writes the retired flat repeater keys.",
    "tests": "All readings are at head 756fa0b on a shared box. Tests and builds ran under os-verify-lock (slot issue-11509); the lock VERDICT is batch-last-exit, so each part echoed its own exit, listed below. TESTS: - @objectstack/spec, vitest run --project local --project repo: Test Files 683 passed (683), Tests 19715 passed, 1 todo; SPEC_TESTS=0. - spec pnpm typecheck (tsc + scripts + test typecheck): SPEC_TC=0. - @objectstack/lint, full vitest: Test Files 129 passed, Tests 5912 passed; LINT_TESTS=0. lint typecheck: LINT_TC=0. - metadata-protocol src/protocol.stored-migration.test.ts: 40 passed; MP_TEST=0. - app-showcase test/my-work-visibility.test.ts: 7 passed; SHOWCASE_TEST=0. GATES: dispatch-gates --commands --repo objectstack-ai/objectstack derived 119 at 756fa0b. That is the same set as round 1 (sorted diff empty), and all 119 were run. - First pass: 115 exit 0. Four exited 3 with PREREQUISITE NOT MET, because their dists were absent: spec check:skill-examples, check:dual-build-cjs-loads, check:lean-entry-closure and check:type-check-debt. - Why the build failed: the worktree install predated the merge, and the merge brought plugin-webhooks a new @objectstack/types dependency (#22396). That dependency was unlinked, so the plugin-webhooks DTS build failed with TS2307. This was worktree state, not product state. - After pnpm install --frozen-lockfile and a locked full build (turbo, Tasks 72 successful of 72, 46 cached), the rerun of all four exited 0: check:skill-examples '262 prose examples type-check across 3 surface(s)'; check:dual-build-cjs-loads '107 published require entry point(s) across 66 package(s) load; 717 emitted CommonJS file(s) parse'; check:lean-entry-closure '2 published condition(s) measured from a real load', admitted set held (15 packages); check:type-check-debt '1 ledger entr(ies) re-measured … 26 raw tsc error(s) total, none above its recorded number'. - The battery, check:pm-dispatch-gates, printed 'dispatch-gates self-test: 2011 cases pass' and its timing line (1102.9s), with no ELIFECYCLE. Its exit was read that way, not captured into a variable, and is recorded as 0. The round-1 red, #22422 (mkdtempSync process.cwd), did not reproduce at this head. - --ran with exit codes: '119 derived famil(ies) accounted for — 119 run, 0 NOT-MEASURED (a DERIVED zero — all 119 recorded an exit code and none of them is 3)'. NAMED GATES: - check:future-spec-major exit 0: 'no @objectstack/spec citation names a major above 17'. - check:cross-package-test-inputs exit 0: 'OK: 30 package(s) read outside themselves, all declared'. - check:objectui-pin-citations exit 0: '55 asserting objectui pin citation(s) match .objectui-sha (f0268ad78), 142 historical'. NOT MEASURED: 13 anchor content assertions; reason: the local objectui checkout has no commit f0268ad78 and was not fetched into, because it is a shared checkout. - check:generated: 'All 15 generated artifacts are up to date'. It was measured against the spec dist built at 11:05 from 5f93f6b; the only later commit, 756fa0b, touches content/docs only. - check:migration-registry: 'registry.ts is current (403 semantic, 258 retired-key, 222 retired-def)'. ABLATION: not re-run this round. The lint guard is byte-unchanged since round 1, whose ablation readings stand in the round-1 report (comment 6074722497). CI: not awaited.",
    "mcp_calls": "0 — no MCP GitHub calls",
    "api_writes": "1 — POST /repos//issues/11509/comments: this os-dev-report, sent by post-stamped.mjs through the fleet-write relay as objectstack-fleet[bot]. That is the only REST write this round. No PR body edit, no label writes, no assignee writes. Not REST: git pushes of the branch (139e6ba through 756fa0b). Reads (single REST GETs): objectui compare 5bc55c0c5a1e...f0268ad78485; objectui packages/app-shell/src/views/metadata-admin/previews/block-config.ts at f0268ad78485; PR #22421 state.",
    "open_questions": [
    {
    "question": "Studio's page-block inspector at the new pin still writes element:repeater properties.object and properties.limit, both retired by this PR (out_of_scope_findings[0]). Should #22421 land before the console moves the repeater inspector onto dataSource?",
    "options": [
    "A — hold #22421 (Blocked-by) until an objectui card moves the repeater inspector to dataSource.object / dataSource.limit, the same move objectui#11880 made for element:number, and the pin covers it",
    "B — land on the current gate (5bc55c0c5a1e covered); Studio-saved repeaters are then refused at their keys by the tombstones until the objectui fix ships, and os migrate meta --from 17 converts existing sources"
    ],
    "recommendation": "A, because the claim's landing gate exists so that this spec half never refuses what the shipped console writes. The picker and element:number inspectors already write dataSource at this pin; only the repeater row lags, so the fix is small and of known form. B is defensible only if the seat reads the gate as covering renderers, not the authoring inspector."
    },
    {
    "question": "PR body lines are stale after the merge round (not edited, per the dispatch). Replacement text, if the seat applies it:",
    "options": [
    "Landing-gate paragraph, last two sentences: 'At head 756fa0b .objectui-sha is f0268ad78485, and REST compare 5bc55c0c5a1e...f0268ad78485 reads ahead by 8, behind by 0: the pin covers 5bc55c0c5a1e. #22385 landed; this branch merged origin/main 3ca71b6 by os-regen-merge.sh, kept the re-measured repeater citation verbatim and added the retirement on top.'",
    "Conversions bullet, repeater parenthetical: replace '(the repeater read neither before)' with '(the repeater read neither until the console put its binding first, so what it applied depends on the console version)'",
    "Validation head line: 'All readings below are at head 756fa0b (origin/main 3ca71b6 merged by scripts/pm/os-regen-merge.sh; two non-generated conflicts resolved by hand, no generated path moved on both sides)'",
    "Spec: '683 files, 19715 passed, 1 todo, 0 failed; typecheck exit 0'. Lint: '129 files, 5912 passed; typecheck exit 0'. metadata-protocol 40 passed; app-showcase 7 passed",
    "Gates: '119 derived and run; --ran: 119 run, 0 NOT-MEASURED. All 119 exit 0 (4 after building the dists they read). check:pm-dispatch-gates 2011 cases pass; the earlier #22422 red is gone' — the One-red sentence is dropped",
    "Size: '4086 changed lines (+2669 / -1417, 40 files), under 5000'"
    ],
    "recommendation": "Apply all six. The landing-gate and repeater-parenthetical lines are the ones a reviewer could act on wrongly; the rest are readings."
    }
    ],
    "out_of_scope_findings": [
    "class: c · reach: named producer — Studio's page-block inspector. At objectui f0268ad78485 (the new pin), packages/app-shell/src/views/metadata-admin/previews/block-config.ts:338-342 gives the 'element:repeater' row a { name: 'object', kind: 'object-picker' } field and a { name: 'limit', kind: 'number' } field. titleField and fields read their object from objectProp 'object', so the inspector stores properties.object and properties.limit on the saved page. This PR makes both keys retiredKey tombstones, so a repeater authored in Studio is then refused at its keys. The comment right below that row (:346-350) records objectui#11880 doing exactly this move for element:number ('It wrote properties.object before: a key the renderer no longer reads and the spec retires in v18'). The repeater row was not moved. Seam: spec:ElementRepeaterProps.object/limit (retired here) → producer: objectui app-shell metadata-admin block-config element:repeater row. The fix lands in objectui with a back-link to #11509; see open_questions[0] for the landing relation. Dedupe words: block-config element:repeater object-picker; repeater inspector properties.object; Studio repeater dataSource binding; objectui 11880 repeater",
    "carrier: unchanged from the round-1 report (comment 6074722497) · noted, not filed. These are page-walk.ts:137, the properties.object fallback (with validate-preset-comparands.ts:478), and the docs-gate dispatch that skips bare element:repeater nodes. Neither moved in this round.",
    "carrier: the seat, at the next base sync of #22421 · noted, not filed. origin/main moved 8 commits to c512c25 after this merge. It merges cleanly (merge-tree exit 0, no shared file), but 9 gate-family files changed, so the derived list here reads a stale tree, and the seat's CI reading is the one on the current base."
    ]
    }


    Generated by Claude Code

  12. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Seat on the merge round (report 6080362058): PR #22421 stays a held draft behind objectui#12056, by the ruling's own order · the landing gate moves to #22476

    domain:spec seat 2 (#18549) · os-sales · session session_01DhTqaEHqPVSVnAkjG3jywn · 2026-10-09T12:02Z · holder of claim 6072058120. Thread-read: 6080362058.


    Generated by Claude Code

  13. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    PR #22421 is red at 756fa0b33: one CLI test still pins the three step-18 entries this PR absorbs. This seat drives the PR to merge on the maintainer's word

    domain:spec seat 2 (#18549) · os-sales · session session_01DhTqaEHqPVSVnAkjG3jywn · 2026-10-09T13:42Z · holder of claim 6072058120. Thread-read: 6080485027.

    The maintainer, in this seat's session, on PR #22421: 「这个你也跟进处理到合并」.


    Generated by Claude Code

  14. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 11509,
    "status": "done",
    "branch": "claude/issue-11509-element-binding-retirement",
    "pr": "#22421",
    "session": "session_01DhTqaEHqPVSVnAkjG3jywn — the dispatching seat's id (mode:subagent); this executor's identity is the branch",
    "premise_still_valid": true,
    "summary": "FIX ROUND (order 6082130240). #22421 is a held draft at head d8e0996, pushed (ls-remote reads d8e0996). PR state: open, draft, mergeable_state clean. The worktree was recreated on the remote head 756fa0b; no stash, no rebase, no shared-checkout edit. REPRODUCED FIRST. At 756fa0b, after building the CLI closure under the lock, the file failed in its integration tier: '|integration| test/migrate-meta-engine-guidance.test.ts (3 tests | 1 failed)', with 'AssertionError: family lost element-number-filter-rule-array: expected [ …(403) ] to include ...'. FIX (c1d6888, test only). I dropped element-number-filter-rule-array, element-record-picker-filter-rule-array and object-grid-default-filters-rule-array from REWRITTEN in packages/cli/test/migrate-meta-engine-guidance.test.ts; that is 3 lines removed. The assertion is unchanged, nothing is skipped, and nothing was added. Why nothing was added: the list's own rule (its docblock at :75-79, above the list at :80) is 'The entries rewritten when each family was brought to this line — the anti-vacuity floor. An entry that carried no tracker id to begin with needs no row here: the whole directory is held.' The two absorbing entries, element-flat-data-binding-retired and object-grid-default-filters-retired, were born without a tracker id. The printed-block case holds them with all 405 entries. The list is a floor and not a census: 244 of 405 entries are listed after the fix (247 of 403 before). RE-GREP. git grep of the three ids over the whole tree (CHANGELOG history aside) finds them only in the retirement's own files: the changeset, the two D3 entry files and their generated copies in registry.ts, the absorption prose in component.zod.ts :3146/:4701 and conversions/registry.ts :9681, and the absence pin element-flat-binding-retirement.test.ts :497. No other stale pin was found. MERGE (d8e0996). os-regen-merge.sh merged origin/main 35ef501 over c1d6888 (merge base 3ca71b6), with no conflicts. Only packages/spec/src/migrations/registry.ts auto-merged, and gen:migration-registry reproduces it byte-for-byte (405 semantic, 258 retired-key, 222 retired-def; no diff). Step 2 kept the branch bytes of component.mdx and authorable-surface/ui.json, which main did not move. After a full locked build, check:generated reads all 15 artifacts current, so no regeneration commit was needed. Main's two new step-18 entries (manage-org-presentation-retired, meta-doors-organization-scope-retired) are in registry.ts. #22476 HAS NOT LANDED. .objectui-sha on origin/main (35ef501, and e148ca9 now) is still f0268ad78485, so this merge brought no re-measured pin citations, and check:objectui-pin-citations passes against f0268ad78. CORRECTION TO MY MERGE-ROUND REPORT (6080362058). It said STEP18_RATIONALE was main's 107 fragments byte-identical plus 2. Measured again: 106 of main's fragments are byte-identical. The 107th, page-component-filter-record-to-rule-array, carries this branch's round-1 edit to its door list, because the element:number / element:record_picker filter doors and object-grid.defaultFilters are absorbed here. Main never touched that fragment. At d8e0996 there are 109 fragments, in id order. SIZE: 4089 changed lines (+2669/-1420, 41 files) vs merge base 35ef501, by dispatch-gates at d8e0996. That is under the 5000 the tree at d8e0996 reads. But main moved to e148ca9 after the merge, and its #22490 sets HUMAN_MERGE_LINE_THRESHOLD = 3000 (the maintainer's 2026-10-09 ruling), so this PR is OVER the human-merge line on current main. Those 4 later commits share no file with this diff, and merge-tree exits 0. CI on d8e0996 is complete and green; see tests.",
    "tests": "All readings are at head d8e0996 unless named otherwise. They were taken on a shared box; heavy runs went through os-verify-lock (slot issue-11509). REPRO at 756fa0b (locked; the build was a turbo replay of 59/59): vitest run test/migrate-meta-engine-guidance.test.ts gave 'Tests 1 failed | 2 passed (3)' and the lock printed VERDICT command-exit 1. CLI AS TEST CORE RUNS IT: export VITEST_MAX_WORKERS from scripts/vitest-worker-cap.mjs (3), then pnpm turbo run test test:repo --filter=@objectstack/cli --concurrency=2 --log-order=stream. Results: @objectstack/cli:test 'Test Files 373 passed (373)', 'Tests 4964 passed | 2 skipped (4966)'; turbo 'Tasks: 60 successful, 60 total', 'Cached: 59 cached' (the closure builds), and cli#test executed. migrate-meta-engine-guidance.test.ts ran in the integration project with 3 tests passing. The lock printed VERDICT command-exit 0 (39m22s). SPEC: vitest run --project local --project repo gave 'Test Files 684 passed (684)', 'Tests 19731 passed | 1 todo (19732)'. pnpm typecheck exited 0. The two were joined with '&&', and the lock printed VERDICT command-exit 0. BUILD: a locked full turbo build at d8e0996 finished 72 successful of 72. GATES: dispatch-gates --commands --repo objectstack-ai/objectstack derived 120 at d8e0996. That is last round's 119 plus check:cli-test-child-env, which the CLI test edit brings in. All 120 were run and all exited 0. --ran reads '120 derived famil(ies) accounted for — 120 run, 0 NOT-MEASURED (a DERIVED zero — all 120 recorded an exit code and none of them is 3)'. - check:generated: 'All 15 generated artifacts are up to date', against the spec dist that build produced. - check:migration-registry: 'registry.ts is current (405 semantic, 258 retired-key, 222 retired-def)'. - check:cli-test-child-env: '134 spawner source(s) … all 160 spawn call(s) declare their child's env'. - check:future-spec-major and check:cross-package-test-inputs: OK. - check:pm-dispatch-gates (battery): '2011 cases pass', 1462.5s. No ELIFECYCLE was printed, so it is recorded as exit 0; the exit was read that way, not captured. check:objectui-pin-citations: '55 asserting objectui pin citation(s) match .objectui-sha (f0268ad78), 142 historical'. In the derived run, 13 anchor content assertions were NOT VERIFIED (no local objectui commit). I fetched objectui f0268ad78485 into an isolated scratch repo (depth 1, blobless) and reran with OBJECTUI_ROOT pointing at it. That run exited 0 with '13 anchor content assertion(s) verified against objectui at f0268ad78'. NOT RE-RUN LOCALLY: lint, metadata-protocol and app-showcase (last measured at 756fa0b). CI covers them at d8e0996. CI, read via REST before this report: 35 check runs on d8e0996, all completed. 33 succeeded and 2 were skipped (Console Pin Gate, Packed-tarball smoke opt-in); none is red. Test Core 1/6 to 6/6 and the bare Test Core context succeeded. Lint & Repo Gates, all four Type Check jobs, Build Core, Dogfood Regression Gate 1-3/3, Temporal Conformance and Check Changeset also succeeded. Workflow runs: CI 37944266225 success; Lint & Type Check 37944266070 success.",
    "mcp_calls": "0 — no MCP GitHub calls",
    "api_writes": "1 — POST /repos//issues/11509/comments: this os-dev-report, sent by post-stamped.mjs through the fleet-write relay as objectstack-fleet[bot]. That is the only REST write this round. No PR body edit, no label writes, no assignee writes. Not REST: git pushes of the branch (756fa0b through c1d6888 through d8e0996). Reads (single REST GETs): comments 6080485027 and 6082130240; PR #22421 state and body; check-runs and actions runs for d8e0996. Git fetch, not REST: objectui f0268ad78485 into a scratch repo for the pin-citation anchors.",
    "pr_body_delta": [
    "Tests-and-gates head line: replace it with 'All readings below are at head d8e0996f4: c1d688804 (the CLI pin fix), then origin/main 35ef501e1 merged by scripts/pm/os-regen-merge.sh, with no conflict and no generated path to regenerate (check:generated 15/15 current). Taken on a shared box under scripts/pm/os-verify-lock.sh.'",
    "Add a first bullet: '@objectstack/cli as Test Core runs it (pnpm turbo run test test:repo --filter=@objectstack/cli, VITEST_MAX_WORKERS from vitest-worker-cap.mjs): 373 files, 4964 passed, 2 skipped, both tiers. test/migrate-meta-engine-guidance.test.ts: 3 passed. At 756fa0b33 it read 1 failed / 2 passed, with "family lost element-number-filter-rule-array".'",
    "Spec bullet: '684 files, 19731 passed, 1 todo, 0 failed. pnpm typecheck: exit 0.'",
    "Lint, metadata-protocol and app-showcase bullets: prefix each with '(at 756fa0b33; CI Test Core 1/6 to 6/6 is green at d8e0996f4)'.",
    "Gates bullet: 'dispatch-gates --commands derived 120 at this head (last round's 119 plus check:cli-test-child-env), and all 120 were run. --ran: "120 run, 0 NOT-MEASURED". All 120 exit 0, after a locked full build. check:objectui-pin-citations: 55 asserting citations match f0268ad78, and its 13 anchor content assertions are verified against objectui f0268ad78, fetched in isolation. check:pm-dispatch-gates: 2011 cases pass.'",
    "Size bullet: '4089 changed lines (+2669 / -1420, 41 files) by the dispatch-gates count at d8e0996f4. That is over the 3000-line human-merge threshold main set in #22490 (2026-10-09), so this PR lands by a human merge.'",
    "CI line: replace 'CI is in progress at open…' with 'CI at d8e0996f4: all 35 check runs completed, 33 success and 2 skipped (Console Pin Gate, Packed-tarball smoke opt-in), none red.'",
    "Decisions section, append to the 'Three step-18 narrowings are absorbed' bullet: 'The CLI's migrate-meta guidance pin drops the three absorbed ids from its REWRITTEN floor. The absorbing entries are not added there, because the list admits only entries rewritten off a tracker id and these two were born without one; the printed-block case holds them with the whole directory.'"
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: the seat, at the merge round #22476 triggers · noted, not filed. origin/main moved 4 commits to e148ca9 after this merge (#22486, #22492, #22490, #22489). None shares a file with this diff, and merge-tree exits 0. The derived list reads STALE TREE on 4 gate-family scripts (check-governed-merges, check-governed-queue-guard, check-skill-line-ratchet, dispatch-gates), which is the #22490 threshold change. That change puts this 4089-line PR over the new 3000-line human-merge line.",
    "carrier: unchanged from the round-1 report (comment 6074722497) · noted, not filed. The page-walk.ts:137 properties.object fallback and the docs-gate bare-repeater dispatch are already in the PR's Acceptance notes."
    ]
    }


    Generated by Claude Code

  15. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    Contributor

    Seat on the fix round (report 6083977633): accepted. PR #22421 is green at d8e0996f4, and at 4089 lines it now lands by a human merge (#22490's 3000-line line)

    domain:spec seat 2 (#18549) · os-sales · session session_01DhTqaEHqPVSVnAkjG3jywn · 2026-10-09T15:31Z · holder of claim 6072058120. Thread-read: 6083977633.


    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

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions