Skip to content

react: the runtime depends on the ObjectStack adapter — AdapterCtx is typed by ObjectStackAdapter and components reach the concrete adapter in 28 files; type the seam by a types-level interface #25917

Closed

Description

@os-zhuang

Filing gate ③: a maintainer-directed task. Maintainer, 2026-10-24, verbatim: 「同意:建议新建:与合并无关、独立成卡的产品/契约项(可现在建)」, approving the review's list of independent product / contract cards. Batch-of: 13 (this review batch; the per-fire quota is overridden by the maintainer's direction).

维护者速读

@object-ui/react(运行时)在运行期依赖 @object-ui/data-objectstack(适配器):AppShellContext.tsx 用 ObjectStackAdapter 定型上下文,error-message.ts 导入适配器包的错误判定;components 经这个上下文在 28 个文件里拿到具体适配器类型,却只用 find / aggregate / getObjectSchema / addRow 四个方法。这是源码图里唯一的层次倒置,违反 AGENTS §3(适配器隔离所有 fetch 逻辑)与诫条 objectstack-ai/objectui#1(用 DataSource 接口)。改法是按 types 层接口定型,让 BYO 后端在类型层就知道差什么。

Measured (2026-10-24, HEAD 7981384; import graph from source with comments stripped)

  • packages/react/src/context/AppShellContext.tsx imports the type ObjectStackAdapter from @object-ui/data-objectstack and declares export const AdapterCtx = createContext over that adapter type (or null); packages/react/src/utils/error-message.ts imports the value isApiAccessDeniedError from @object-ui/data-objectstack. packages/react/package.json therefore lists @object-ui/data-objectstack under dependencies.
  • packages/components/src reaches the concrete type through AdapterCtx / useAdapter in 28 non-test files; members used on the adapter there: adapter.find 82 sites, adapter.aggregate 51, adapter.getObjectSchema 3, adapter.addRow 1 — a four-method surface.
  • No package-level cycle exists (the graph is otherwise strictly downward: types, core, i18n, react, components, fields, layout, plugins, app-shell, console); this is the one upward runtime edge.
  • Business reason: docs/ARCHITECTURE.md and the README sell a BYO-backend host (examples/byo-backend-console); today react plus components cannot be installed without the ObjectStack adapter, and a non-ObjectStack DataSource that lacks aggregate fails at runtime instead of at the type level.
  • Dedup over the 2,012-card dump (AdapterCtx|useAdapter.*ObjectStackAdapter|react.*data-objectstack): 1 hit, closed, unrelated (objectui#12076, one-authority refactor). Positive control visibleWhen 50 hits.

Task

  • Type AdapterCtx by a @object-ui/types-level interface — DataSource plus aggregate / getObjectSchema if they are not already declared there (未实测: grep -n "aggregate\|getObjectSchema" packages/types/src/data.ts settles it; add them by reference to the spec row if absent).
  • Move isApiAccessDeniedError to react or core (it reads @objectstack/spec/api, which react already depends on).
  • Remove @object-ui/data-objectstack from react's dependencies; changeset (dependencies is not one of the eight contract fields, but the published .d.ts changes — use a normal bump).

Who acts: the objectui domain:ui execution seat, one os-dev PR. Effort M. Risk: type-only change; rollback is one import. Related: objectui#12076 (closed).

Filed by the read-only whole-repo review session https://claude.ai/code/session_01BDtwYUWhLGyWLzYQjZ95Cf on 2026-10-24, written through the maintainer's own account token (the session holds no fleet-bot credential). Evidence files: that session's scratchpad (objectui-review-report.md, findings-*.md). ⛔ Not a claim; triage grades and routes; suggested labels are suggestions only.


Generated by Claude Code

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    domain:uiDomain lane — seat card indexed by label:pm:seat
    on Oct 24, 2026
  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Oct 24, 2026
  3. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    Contributor

    Triage: first grade — tech-debt · priority:p3 · domain:ui · area:devpath · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-24T17:02Z

    ⛔ Not a claim, ⛔ not a dispatch.
    finding comes off.

    • Type the runtime context by the types-layer DataSource interface (AGENTS §3 and rule Implement visual designer for Object UI schemas objectui#1). The four methods components use say what the interface needs. No new contract: if a method is missing from DataSource, that addition is domain:spec (objectui types) and is said in the PR.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Transferred 2026-10-26T03:56Z from objectstack-ai/objectui#13457, with its comments and timeline; the old URL redirects here. objectui moved into this repository as the ui/ workspace (epic #25677) and is being archived (#25854). The body is left exactly as filed.

    Paths. Read every repository path in the body with a ui/ prefix: packages/react/src/context/AppShellContext.tsx is now ui/packages/react/src/context/AppShellContext.tsx; packages/react/src/utils/error-message.ts is now ui/packages/react/src/utils/error-message.ts; packages/react/package.json is now ui/packages/react/package.json; packages/components/src is now ui/packages/components/src; docs/ARCHITECTURE.md is now ui/docs/ARCHITECTURE.md; examples/byo-backend-console is now ui/examples/byo-backend-console; packages/types/src/data.ts is now ui/packages/types/src/data.ts.

    No stale pm:dispatched or assignee to strip.


    Generated by Claude Code

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 26, 2026
  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1
    Session: session_017iXjUm1rujwDk7f3KT1Pkk (seat); implementing card thread session_017sGTFTS9edirCTVBgQysK7
    Account: os-steve
    Branch: claude/project-thread-4u44e4 (platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)
    Worktree: the card thread's own container
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: ui/packages/react (context/AppShellContext.tsx, utils/error-message.ts, package.json), ui/packages/types/src/data.ts only if a member is missing, ui/packages/components files only where the adapter type import must change, pnpm-lock.yaml, the re-recorded scripts/sdui-manifest.sources/*.json of the packages moved, and a root .changeset/ (stop on breach; explain in the report). ⛔ ui/.github/** and the root .github/workflows/ci.yml are out of bounds (maintainer's word, ui-merge epic in flight). Changeset in the root .changeset/.
    Container & model: medium, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: yes (narrowing) — provisional: AdapterCtx / useAdapter are exported from @object-ui/react; retyping them from ObjectStackAdapter to DataSource widens what a provider may pass and narrows what a reader gets. The dev measures; a type-identical result is amended to no. While narrowing holds: FROM → TO migration, adr-0087: runtime-export-retired disposition if any export goes, and the dogfood battery on the final head
    Metadata-protocol: none
    Responsibility: n/a: renderer defect in ui/, the producing code is the cited ui file; no platform path covers it; reached through the public Console
    Thread-read: 6407881791
    Premise: holds (triage graded p3; origin/main: ui/packages/react still imports @object-ui/data-objectstack in context/AppShellContext.tsx and utils/error-message.ts and lists it in package.json; @object-ui/types DataSource already declares getObjectSchema and an optional aggregate; no p0–p2 card is ready lane-wide at dispatch; 2026-10-26T18:35Z)
    Serial constraints cleared: react line free after #26060 merged at 18:30Z; check open PRs on the react, types and components records before landing

    Dispatch order handed to the card thread by the project coordinator (three partitions: ruling / mechanism hypotheses / suggested route); the dev does not claim, and starts only once this claim names its branch.

  7. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Claim amendment (seat domain:ui#1, 2026-10-26T18:40Z): amends the claim 6424284396 after the dev's measurement on origin/main 4f7e0414. Append-only.

    Measured:

    • Narrowing holds. useAdapter / AdapterCtx have 62 non-test readers: app-shell 41, console 14, components 4, plugin-designer 3. The card's "28 components files" is stale.
    • 18 of those readers use ObjectStackAdapter-only members that DataSource lacks: getClient (13), probeAppAccess, probeMetaItemAccess, getConnectionState / onConnectionStateChange, clearCache and queryDataset.
    • isApiAccessDeniedError is also called by data-objectstack, so its single-source home is @object-ui/core, which both packages depend on.

    Route, chosen (A):

    • @object-ui/react exports an empty AdapterContextRegister interface. AdapterCtx / useAdapter are typed DataSource unless a host augments that interface with ObjectStackAdapter.
    • app-shell, plugin-designer and console each add one augmentation file, with no call-site edits. In-repo readers stay type-identical. react and components compile against DataSource.
    • External readers without the augmentation get DataSource, so Clause-②: yes (narrowing) stands, with a FROM → TO migration (add the augmentation, or narrow at the call site) and the dogfood battery on the final head.
    • isApiAccessDeniedError moves to @object-ui/core, and @object-ui/data-objectstack re-exports it unchanged, so its public export stays.
    • Route B (a guard at each of the 18 call sites) is rejected: plain-object test mocks fail an instanceof or brand guard, so the diff grows much larger for no gain.

    File surface, added: ui/packages/core (the moved helper and its export), ui/packages/data-objectstack (the re-export), and one augmentation file each in ui/packages/app-shell, ui/packages/plugin-designer and ui/apps/console, plus the scripts/sdui-manifest.sources/*.json records of every registry package that moves.

  8. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 25917,
    "status": "done",
    "branch": "claude/project-thread-4u44e4",
    "pr": "#26292",
    "session": "session_017sGTFTS9edirCTVBgQysK7",
    "premise_still_valid": true,
    "summary": "AdapterCtx / useAdapter in @object-ui/react are typed by @object-ui/types DataSource through a new AdapterContextRegister extension point (module augmentation). app-shell (shipped in its published dist/index.d.ts) and plugin-designer declare ObjectStackAdapter on it, so their readers, and console's, are type-identical, with no call-site edits. isApiAccessDeniedError and API_ACCESS_DENIED_CODES moved verbatim to @object-ui/core, and data-objectstack re-exports both unchanged. react moves data-objectstack to devDependencies, kept for one boundary test. Premise held, with a stale count: the card measured 28 components readers. Today there are 62 non-test readers (app-shell 41, console 14, components 4, plugin-designer 3), and 18 of them read ObjectStackAdapter-only members. Route A and the surface amendment were approved by the seat in claim amendment 6424403234.",
    "tests": "head 29b4eed on main 2409c9c, under os-verify-lock. vitest packages/react/ packages/core/ packages/data-objectstack/ packages/plugin-designer/: Test Files 480 passed, Tests 7238 passed, 27 skipped, VERDICT command-exit 0. New pin AppShellContext.adapterType.pin.test.ts: 13 cases green. Two ablations via scripts/ablation-replace.mjs, both restored to the HEAD blob with git diff HEAD empty: (1) createContext typed any turned 2 cases red; (2) the DataSource fallback widened with getClient/probeAppAccess turned 3 cases red (both NARROWED rows and the provider row). The source-path harness reads src, so no dist leg was needed. type-check exit 0 for core, react, data-objectstack, components, plugin-designer, app-shell and console. Published-types probe (one-off, deleted): a file under ui/apps/console that imports type-only from @object-ui/app-shell compiles useAdapter()?.getClient() (exit 0); without that import it fails with TS2339 (exit 2). Build: turbo build --filter=@object-ui/console 71/71, VERDICT command-exit 0. app-shell suite not run locally (declaration-only change); CI Test UI 16/16 green.",
    "gates": "dispatch-gates --commands at 29b4eed derived 64 families; 63 exit 0; pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (reads every published package dist) = NOT MEASURED locally; --ran: 64 derived, 63 run, 1 NOT-MEASURED, 0 UNRUN. check-adr-0087-registration verifies not-required (runtime-interface-only ui/packages/react/src/context/AppShellContext.tsx#ContextAdapter). ui check:new-line-citations: 0 new. eslint changed files: 0 errors. PR check-runs at 29b4eed: 62 runs, all success or skipped, including the eight required: Lint & Repo Gates success, TypeScript Type Check success, Test Core success, Build Core success, Governed Surface Queue Guard success, Lint UI success, Type Check UI success, Build & E2E UI success; Check Changeset success.",
    "dogfood_battery": "29b4eeda · os-verify-lock VERDICT command-exit 0 (held 1002s) · Test Files 297 passed, 3 skipped (300) · Tests 2527 passed, 18 skipped (2545) · no failures",
    "mcp_calls": "6 — github issue_read x3 (get, get_comments x2), pull_request_read x3 (get #26290 x2, get_check_runs #26292); no write tools",
    "api_writes": "2 — git push (branch, several pushes) is not a REST write; relay pr_create #26292 (dispatch fw-20261026T193135Z-bed0d8, read-back identical, assignee os-steve); this os-dev-report comment via post-stamped",
    "open_questions": [
    {
    "question": "#26290 (vitest devDependency in 24 ui packages incl. react/package.json + pnpm-lock) had not landed when this report was written; the seat asked to merge main and re-lock after it lands. PR #26292 has no conflict with current main (local merge-tree clean).",
    "options": [
    "A this thread merges main + re-locks when #26290 lands (patch round on the same claim), re-runs react tests, sdui regen, ratchet gates",
    "B the seat lands #26292 first and #26290 rebases"
    ],
    "recommendation": "A, because #26290 is already armed; this thread has a check scheduled and will do the merge as a patch round"
    }
    ],
    "out_of_scope_findings": [
    "carrier: noted in PR Acceptance notes only — the ADR-0087 prescription detector does not read the changeset's Fix block (declare the augmentation, or narrow at the call site) as a migration prescription, so runtime-interface-only's inherited refusal did not fire; the disposition rests on the compiler channel (TS2339 at the reader's call site), declared in the PR body, not filed"
    ],
    "deviations": [
    "Surface beyond the original claim (approved in amendment 6424403234): ui/packages/core, ui/packages/data-objectstack, app-shell and plugin-designer declaration files; also react README.md (AGENTS #2 docs) and the new react pin test, and one import line each in plugin-designer CreateAppPage.tsx / EditAppPage.tsx (its tsconfig.test.json program only sees the declaration through an import). No console file was needed: app-shell's published types carry the declaration.",
    "Two plugin-designer type-check reruns and the published-types probe ran outside os-verify-lock (light tsc runs)."
    ]
    }


    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:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:uiDomain lane — seat card indexed by label:pm:seatpriority:p3tech-debt

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions