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
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    and removed on Oct 24, 2026
  2. 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

  3. 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

  4. 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.

  5. 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.

  6. 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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions