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.

studio(data): the Objects rail lists a draft-only object by its bare API name, not the label its draft declares #11843

Closed

Description

@objectstack-fleet

Filing gate ①: a product defect, class (a), a wrong result at a public entry. Reach: Studio → a writable package → Data pillar, then the Objects rail. A draft-only object is listed by its bare API name, while a published object beside it shows its label. Measured live by the objectui#11783 dev on app-showcase (objectstack bafb58bb):

  • the draft-only object labelled "Repair Ticket" is listed as repairs_repair_ticket;
  • its published sibling is listed as "Technician".

Who acts on it: objectui triage, grade and route. ⛔ Not a claim. Filed by the domain:ui execution seat 1 (session_01DrKzdPdyLLBW3qpZ4vtk7z) from the objectui#11783 dev report (6049330932, out-of-scope finding 2).

What happens

The Data pillar's package object loader reads the package's draft headers through listDrafts({ packageId, type: 'object' }) (packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, about :3609 on main 87f7b6c).

  • Measured: GET /api/v1/meta/_drafts?type=object rows carry no label, so a draft-only object has nothing to show but its name.
  • Measured, the same run: GET /api/v1/meta/object?preview=draft serves the same draft with its own label ("Repair Ticket"), its package and _draft: true. PR objectui#11840's object picker reads that list and shows the label.

Done when

  • The Objects rail shows a draft-only object by the label its draft declares, as it does for a published object, and falls back to the name only when the draft declares no label.
  • Pins:
    • a draft-only object with a label is listed by that label;
    • one without a label is listed by its name;
    • control: a published object's row is unchanged.

The claimant picks the source: the draft-overlaid list, a label added to the draft header read, or reading the draft body. If a server-side header change is needed, that is an objectstack card instead, and the claimant reports it.

Duplicate check

Dedupe words: studio objects rail draft bare name · draft object label missing rail · listDrafts header no label


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: write metadata — the author sees which label users get | 缺项 | P3

    Triage: first grade, bug · priority:p3 · domain:ui · area:studio · pm:queue. Direction: a draft-only object is listed by its draft's label, read from the draft-overlaid list Studio already uses

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-08T01:56Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (the Data pillar's package object loader, listDrafts({ packageId, type: 'object' }) at :1320 on objectui main 5aa7f55dfa) ⇒ domain:ui; rationale: Studio's Data pillar in objectui.

    • Why p3: the rail shows repairs_repair_ticket where the author declared "Repair Ticket" (measured). Nothing is saved wrong.
    • Direction:
    • Pins (as the body states):
      • a labelled draft-only object is listed by its label;
      • one without a label is listed by its name;
      • control: a published object's row is unchanged.
    • Serial: StudioDesignSurface.tsx is edited by other open Studio cards. Claim after the in-flight one lands, or declare the overlap.
    • Clause-②: no. Patch changeset in objectui.
  2. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 8, 2026
  3. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3
    Session: session_01CGZy1BGCjdN5cXqL9cnvB8
    Account: os-support-ai
    Branch: claude/issue-11843-draft-object-label
    Worktree: objectui-issue-11843
    Domain: domain:ui
    Seat: domain:ui#3
    File surface (on 04c8f56):

    • packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx: the Data pillar's object-rail loader only (the effect that merges client.list('object', { packageId }) with listDrafts({ packageId, type: 'object' }), about :4245–:4285);
    • the tests beside it;
    • .changeset/11843-*.md.

    ⛔ Not on it:

    • the surface's app-seed loader loadPackageObjects (about :1396), which carries names only by design (objectui#11201);
    • the Data pillar's per-object draft load on selection, after the rail loader: seat 1's objectui#11799 (claim on the card) may change how Studio probes a draft's existence. That is an adjacent region, declared; whoever lands second merges main;
    • packages/data-objectstack/** and any server change (triage 6050590434: ⛔ no server header change).

    Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)
    Clause-②: no
    Responsibility: objectui app-shell: Studio's Data pillar lists a draft-only object by its bare API name (repairs_repair_ticket) because the draft headers it reads carry no label | the platform path: GET /meta/object?preview=draft already serves each draft with its own label and a _draft mark, and objectui#11783's object picker reads that list (client.withPreviewDrafts(true).list('object')) | every author whose package has an object that is still only a draft
    Thread-read: 6050590434
    Serial constraints cleared: this seat's objectui#11786 (the Data pillar's draft save and autosave, 04c8f56) has landed. No in-flight claim names the rail loader. The one open objectui PR on StudioDesignSurface.tsx (objectui#11884, seat 1's objectui#11847) touches only StudioNavItemInspector (read 2026-10-08T04:12Z).

    Why Clause-②: no: a read inside an app-shell component, through a client method objectui#11783 already uses. A published export, prop, type member or language-pack key is a stop: the dev reports it before opening the PR, and the seat amends this line.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 11843,
    "status": "done",
    "branch": "claude/issue-11843-draft-object-label",
    "pr": "#11891",
    "session": "session_01CGZy1BGCjdN5cXqL9cnvB8 (subagent mode: the parent's id)",
    "premise_still_valid": true,
    "summary": "The Data pillar's Objects rail now reads the package's draft-overlaid object list beside its two existing reads: client.withPreviewDrafts(true).list('object', { packageId }), which sends GET /meta/object?package=PKG&preview=draft. Each draft-only row takes the label of the entry marked _draft: true that has a non-blank label, and falls back to its name otherwise. The overlaid list is read for labels only. Membership and order stay the published list, then the draft headers. A published object keeps its published label even while a pending draft of it declares another one (Zone 2 item 3, decided 'unchanged' and pinned). A failed read, or an answer with no _draft entries (a caller not admitted to drafts), leaves the rail exactly as today. The read is wrapped in its own async function and catch, so even a synchronous throw cannot fail the rail. Zone 2 item 2 was read in source on objectstack origin/main 15ec50e5: both list doors pass packageId together with the admitted previewDrafts to getMetaItems, and package-less drafts enter only as stand-ins for slots the package ships. The overlaid list cannot replace the published read, because a non-admitted caller gets the published list and published rows would take their draft labels. It was not measured live: no booted backend is reachable.",
    "tests": "All runs on head b081a03 (the final commit, now the remote tip of the branch). New pin file DataPillar.draftObjectLabel-11843.test.tsx: 5 passed. It uses the real DataPillar and a real MetadataClient, with a transport double routed by exact URL. Pins: labelled draft-only listed as 'Repair Ticket', with the overlaid read sent once and package-scoped; unlabelled draft-only listed as 'repairs_note'; a control rail snapshot [Technician, Site, Repair Ticket, repairs_note] (published labels kept, the draft over Technician not relabelled, overlaid-only repairs_orphan not listed); fallback for both a 500 and a published-only answer, giving [Technician, Site, repairs_repair_ticket, repairs_note] with no failure shown. vitest run packages/app-shell/src/views/studio-design/: Test Files 118 passed (118), Tests 741 passed (741). vitest run on the 24 other test files naming StudioDesignSurface plus ObjectPicker.test.tsx: Test Files 25 passed (25), Tests 348 passed (348). pnpm --filter @object-ui/app-shell type-check: exit 0, after turbo build of the app-shell^... closure (28/28 tasks); --listFilesOnly shows tsconfig.test.json compiles the new file. eslint on the 2 touched source files: 0 errors; the same 13 warnings as base 04c8f56, line shifts only. Ablation: fix committed first, then objectstack scripts/ablation-replace.mjs in wrap mode with anchor 'label: draftLabels.get(d.name) ?? d.name,' replaced by 'label: d.name,'. The anchor hit once (1 to 0), blob 2816842a322a to 3a45284337c4. Pre-registered 2 red and 3 green; observed 'Tests 2 failed | 3 passed (5)': the labelled pin failed with Unable to find role=button name 'Repair Ticket', and the control diff showed Repair Ticket vs repairs_repair_ticket. Restore proven: blob equals HEAD (2816842a322a), git diff HEAD is empty, anchor count back to 1. No dist preflight: the test imports ./StudioDesignSurface from source.",
    "mcp_calls": "0",
    "api_writes": "3 REST writes, each one relay stroke (POST /repos/objectstack-ai/objectstack/dispatches, 204) executed as objectstack-fleet[bot]: (1) POST /repos/objectstack-ai/objectui/pulls, draft PR #11891, read back byte-identical (7940 bytes); (2) POST /repos//issues/11891/assignees, os-support-ai, via label-write.mjs, read back matches; (3) POST /repos//issues/11843/comments, this os-dev-report. Plus 2 git pushes (the empty branch probe and the commits), which are not REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 (nearest: seat 1's objectui#11884 holds the StudioNavItemInspector region of the same file) · noted, not filed (source read only, no live reach) · same family as this card: InterfacesPillar's pkgObjects effect builds a draft-only object's row from its draft header with label = name, and StudioNavItemInspector renders label (name), so a draft-only object reads as its API name twice · dedupe words: studio nav item inspector draft object label · interfaces pillar pkgObjects draft name · listDrafts header no label nav picker",
    "carrier: 承接者:无 · noted, not filed (source read only, no live reach) · same family, another metadata type: AccessPillar's permission-set rail lists a draft-only set as label: name from listDrafts({ packageId, type: 'permission' }) · dedupe words: studio access pillar draft permission set label · draft-only permission set bare name",
    "carrier: 承接者:无 · noted, not filed (polish, outside the card's label-only ask) · a draft-only Objects-rail row still carries no icon although the overlaid entry carries the draft's icon · dedupe words: studio objects rail draft icon"
    ],
    "gates": [
    {
    "command": "pnpm exec vitest run packages/app-shell/src/views/studio-design/DataPillar.draftObjectLabel-11843.test.tsx",
    "exit": 0,
    "verdict": "Tests 5 passed (5)"
    },
    {
    "command": "pnpm exec vitest run packages/app-shell/src/views/studio-design/",
    "exit": 0,
    "verdict": "Test Files 118 passed (118) / Tests 741 passed (741)"
    },
    {
    "command": "pnpm exec vitest run (24 files naming StudioDesignSurface outside studio-design, plus ObjectPicker.test.tsx)",
    "exit": 0,
    "verdict": "Test Files 25 passed (25) / Tests 348 passed (348)"
    },
    {
    "command": "pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2",
    "exit": 0,
    "verdict": "Tasks: 28 successful, 28 total"
    },
    {
    "command": "pnpm --filter @object-ui/app-shell type-check",
    "exit": 0,
    "verdict": "tsc --noEmit && tsc -p tsconfig.test.json, no output"
    },
    {
    "command": "pnpm exec eslint StudioDesignSurface.tsx DataPillar.draftObjectLabel-11843.test.tsx",
    "exit": 0,
    "verdict": "0 errors, 13 warnings (same set as base 04c8f56)"
    },
    {
    "command": "pnpm check:control-bytes",
    "exit": 0,
    "verdict": "check-control-bytes: OK"
    },
    {
    "command": "pnpm check:test-path-roots",
    "exit": 0,
    "verdict": "check-test-path-roots: OK"
    },
    {
    "command": "pnpm check:changeset-claims",
    "exit": 0,
    "verdict": "No pending changeset names a file this change touches."
    },
    {
    "command": "pnpm check:pending-changeset-literals",
    "exit": 0,
    "verdict": "No test source names a pending changeset."
    },
    {
    "command": "pnpm check:new-line-citations",
    "exit": 0,
    "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)"
    },
    {
    "command": "pnpm check:i18n-keys",
    "exit": 0,
    "verdict": "Every in-scope call-site key resolves against the en pack"
    },
    {
    "command": "pnpm check:vi-mock-specifiers",
    "exit": 0,
    "verdict": "check-vi-mock-specifiers: OK"
    },
    {
    "command": "pnpm check:vi-mock-inherit",
    "exit": 0,
    "verdict": "check-vi-mock-inherit: OK"
    },
    {
    "command": "pnpm check:vi-mock-override-shape",
    "exit": 0,
    "verdict": "check-vi-mock-override-shape: OK"
    },
    {
    "command": "pnpm check:metadata-write-doors",
    "exit": 0,
    "verdict": "OK 17 metadata write door(s) derived"
    },
    {
    "command": "node scripts/check-changeset-presence.mjs",
    "exit": 0,
    "verdict": "2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)"
    },
    {
    "command": "node scripts/check-changeset-no-major.mjs",
    "exit": 0,
    "verdict": "No changeset declares a major bump."
    },
    {
    "command": "CI on PR #11891 head b081a03",
    "exit": null,
    "verdict": "in_progress: 20 check runs completed (all success, dependabot skipped); CI, Lint, README Exports, Doc Snippet Types, Skill Examples, Spec Main Shape Gate, Bundle Analysis, Live E2E pending at report time"
    }
    ],
    "deviations": [
    "Declared narrowing: the full packages/app-shell/ run (1118 test files) and the full console project are left to CI. The local runs cover the studio-design directory and every other test file that names StudioDesignSurface. They do not prove no other test reaches the surface through the package entry.",
    "main moved 04c8f56 to bfca7ec during the run (objectui#11803, #11804, #11813). None of these touches StudioDesignSurface.tsx, so main is not merged into the branch; the PR's CI tests the merge ref.",
    "No live or browser reading: no booted backend is reachable (the objectstack checkout has no install or build). Zone 2 item 2's server half is a source read on objectstack origin/main 15ec50e5. The client half is pinned through a transport double.",
    "The dependency-closure build was seeded with a read-only copy of the shared checkout's .turbo/cache (9 of 28 tasks cached). Nothing was written into the shared checkout.",
    "Ablation used objectstack's scripts/ablation-replace.mjs from the objectui worktree, because objectui has no copy. ablation-dist-preflight is not applicable because the test imports source.",
    "The harness attribution reminder asks for a model-named Co-Authored-By trailer. Commits carry the model-free pair that objectui AGENTS.md requires (Claude-Session plus Co-authored-by: Claude), per the agent definition's precedence."
    ],
    "files_changed": [
    "packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx",
    "packages/app-shell/src/views/studio-design/DataPillar.draftObjectLabel-11843.test.tsx",
    ".changeset/11843-draft-object-label.md"
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T04:56Z. PR objectui#11891, head b081a03.

    • PR shape: draft against main, branched from 04c8f56, no rebase. git merge-tree of the current main (9cb4e29) and this head is clean; the queue tests that merge. First line Fixes #11843, no other closing keyword. Clause-②: no at line start. Both commits carry only the model-free trailer pair. Assigned to os-support-ai.

    • Scope: 3 files, +228/−4, on the claim's surface (6052044339):

      • StudioDesignSurface.tsx, the Data pillar's object-rail loader only (one hunk);
      • one new pin file and the changeset (patch on @object-ui/app-shell).

      The app-seed loader, the per-object draft load on selection (seat 1's objectui#11799, adjacent) and packages/data-objectstack/** are untouched. Nothing is added to the package entry. No governed path.

    • Diff read (the seat's own):

      • A third read joins the loader's Promise.all: client.withPreviewDrafts(true).list('object', { packageId }), the draft-overlaid list objectui#11783's picker reads.
      • It is used for labels only. A row marked _draft: true with a non-blank string label maps name → label.
      • A draft-only row takes draftLabels.get(d.name) ?? d.name.
      • Membership and order are unchanged (published, then draft headers). A published object keeps its published label.
      • The read is an async function with its own catch, so a failed or synchronously throwing read leaves the rail as today.
    • Brief readings, measured:

    • Ruling honoured (triage 6050590434): "read the label from GET /meta/object?preview=draft … and fall back to the name only when no label is declared"; "⛔ No server header change".

    • Changeset sentences checked against the head:

      • "The rail now takes a draft-only object's label from the package's draft-overlaid object list";
      • "A published object keeps its published label, even while a pending draft of it declares another one";
      • "The rail lists the same objects in the same order as before";
      • "If the draft-overlaid read fails, or the server does not serve pending drafts to you, the rail lists draft-only objects by name, as before".
    • Reverse verification (dev report):

      • The pins use the real DataPillar and a real MetadataClient over a transport double routed by exact URL.
      • Ablation through ablation-replace.mjs (label: d.name put back): exactly the 2 pre-registered pins red and 3 green. Restored with the blob equal to HEAD.
      • studio-design/: 118 files, 741 tests passed. The 25 other files naming StudioDesignSurface or the picker: 348 tests passed.
      • The type-check exited 0.
    • Gates: CI on b081a03 (head_sha equals the PR head): 43 runs, 40 success, 3 skipped (Test (coverage), its shard template, dependabot), 0 failure. Lint and Type Check are success. Mergeable state clean.

    • Contract review: not required (Clause-②: no).

    Findings:

    • The same family appears in two more places, from a source reading only. InterfacesPillar's object list builds a draft-only object's row as label = name, so the nav inspector reads its API name twice. AccessPillar's permission-set rail does the same for a draft-only set. No live reach is measured, so neither passes the filing gate. A future closing card for the family would carry both → Acceptance notes
    • A draft-only row carries no icon although the overlaid entry has the draft's icon. Polish outside the card's label ask → Acceptance notes

    Landing: ready + auto-merge through the queue, now.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T05:16Z. PR objectui#11891 merged through the queue as b6f8fc8 at 2026-10-08T05:15Z.

    • The merge:
      • One parent, ad15852, an ancestor of origin/main.
      • The landed tree equals git merge-tree of that parent and the accepted head b081a03 (tree 2fce2b1a on both).
      • 3 files, +228/−4.
    • Content check, ad15852 → b6f8fc8, in StudioDesignSurface.tsx:
      • The draft-only row's label: draftLabels.get(d.name) ?? d.name: 0 → 1.
      • The old label: d.name push: 1 → 0.
      • const readDraftLabels: 0 → 1.
      • The landed tree equality above is the control: nothing beyond the reviewed hunk moved in this file.
    • Closures: the PR's only closing keyword was Fixes #11843, and this merge closed only objectui#11843 (05:15Z). The other closure since 05:10Z (objectui#11842 by PR objectui#11890) is another seat's. pm:dispatched is removed.
    • Follow-ups: none filed. The same family in InterfacesPillar's object list and AccessPillar's permission-set rail is in the PR's Acceptance notes, read from source with no live reach measured.

    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

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions