Skip to content

skills/objectui teaches ObjectStackAdapter({ baseUrl: '/api/v1' }), which sends discovery to /api/v1/api/v1/discovery, so connect() fails and every adapter call with it #27774

Closed

Description

@objectstack-fleet

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

Filing gate ①: a wrong instruction in shipped text, with named locations. Found by the #27678 card thread (dev report 6510080703, out_of_scope_findings, carrier: seat) and verified from source by the contract review of PR #27764 (record 6510354851, ③). Filed by domain:skills seat 2 (#19287). ⛔ Not a claim. Filed without domain:*: the skill text is domain:skills; the adapter's discovery line is ui/**. Triage sets the lane or splits.

Business reason: a customer agent that loads the objectui skill and wires a real backend is told to write new ObjectStackAdapter({ baseUrl: '/api/v1' }). The adapter treats baseUrl as an origin for discovery, so the app's first call fails and every read and write fails after it. The skill teaches a configuration that cannot work. North Star 优先级 item 4 counts a shipped sentence that says something wrong.
Reader who acts: the lane triage assigns. One os-dev, one PR (or two after a split).
Dedupe: issues searched for ObjectStackAdapter baseUrl and api/v1/api/v1 → no card.

Measured (origin/main, read from source, not run live)

  1. skills/objectui/guides/data-integration.md teaches baseUrl: '/api/v1' at :133, :155, :218, :461 (line numbers at PR docs(skills): the objectui data-integration guide stops teaching the MSW plugin removed in 12.0 #27764's head a5cbb8fc; all four lines predate that PR).
  2. ui/packages/data-objectstack/src/index.ts:3432-3435 builds discovery as baseUrl + '/api/v1/discovery' with no suffix strip. The adapter's own search, data, export and meta paths (:3765-3769, :5162-5167, :5294-5298, :5463-5467) DO strip a trailing /api/vN, so the adapter disagrees with itself.
  3. packages/client/src/index.ts:1704, :1733: ObjectStackClient takes an origin and joins every route as ${this.baseUrl}${route}, where routes are absolute /api/v1/... paths.
  4. Every adapter read and write awaits connect() first (ui/packages/data-objectstack/src/index.ts:3656, :3844, :4378, …).
  5. The console passes an origin: ui/apps/console/src/App.tsx:105 (VITE_SERVER_URL || '').

Wanted

  • Measure the failure once (a live os dev plus the adapter with baseUrl: '/api/v1', or a unit pin on the discovery URL).
  • Skill half: teach the origin form the console uses ('' behind a same-origin proxy, or the server origin) at all four places, and add or adjust an eval so the wrong form is refused. Keep the skill's line budget neutral or negative.
  • Adapter half (ui/**), for triage to place: either the discovery line strips a trailing /api/vN like the four sibling paths do, or the adapter refuses a baseUrl that ends in /api/vN loudly. Contract-tightening is preferred over silent tolerance; triage or the maintainer picks.

Acceptance

  • git grep -n "baseUrl: '/api/v1'" -- skills → 0 hits.
  • The adapter either reaches discovery with the taught baseUrl, or refuses the wrong one with a named error, pinned by a test.

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 写给 AI 的文档与 skills 说错一句,等于产品缺陷 | none | P①

    Triage: p2 · domain:ui · area:api · cross-domain exception, one PR · 2026-10-29T22:56Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

    Claim: PM loop round 1
    Session: session_01Utp6CaJoinvGQSbHeDaWBe
    Account: os-bill
    Branch: claude/project-thread-83w07l (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27774
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: ui/packages/data-objectstack/src/** (discovery URL + tests; ⛔ seat 4 PR #27907 regions), skills/objectui/guides/data-integration.md (+ that skill's eval files if one applies), root .changeset/ (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: claude-fable-5-1 (MANDATORY: dispatch-gates --tier on ed0e71db, skills/** clause ①, no one-line exit), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the adapter disagrees with itself and the shipped skill teaches the failing form | triage: platform first, cross-domain exception, one PR | every agent that wires a real backend from the objectui skill
    Thread-read: 6510453993
    Premise: holds
    Serial constraints cleared: PR #27764 (#27678, same skill file) merged 2026-10-30T01:41Z

    Tier H: the file surface includes governed skills/objectui/guides/data-integration.md (the triage's granted cross-domain exception). Landing: seat ACCEPT, contract review at CONTRACT_REVIEW_TIER (PASS on head), then review requests to os-zhuang and hotlong. Serial predecessor PR #27764 merged 2026-10-30T01:41Z. Coordinated with domain:ui seat 4: its PR #27907 regions in data-objectstack/src/index.ts (field-access fields, dropInflightReads, getRecordFieldAccess) are off limits. Seat 2 released the card to seat 3.

    Dispatched 2026-10-30T04:56Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CXqKgaNYFmpss9BkRj
    os-dev-report

    Reading time 2026-10-30T05:36Z · head e73e6d45 · PR #27967 (draft) · worktree objectstack-issue-27774 off origin/main ed0e71db.

    {
      "issue": 27774,
      "status": "done",
      "branch": "claude/project-thread-83w07l",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27967",
      "session": "session_01Utp6CXqKgaNYFmpss9BkRj",
      "premise_still_valid": true,
      "summary": "ObjectStackAdapter now reads baseUrl as the server origin once, where it and its ObjectStackClient are built (a trailing slash and a trailing /api/vN are dropped), so '', an origin, '/api/v1' and 'origin/api/v1' all reach /api/v1/discovery and the same /api/v1/... routes through the client and the raw reads alike; the five per-call suffix checks are gone. skills/objectui guides/data-integration.md (4 sites) and guides/auth-permissions.md (1 site, the fifth hit of the acceptance grep, outside the declared surface) plus the package README teach baseUrl: '' (the origin form the console passes); evals/data-integration.json eval 2 refuses the old form. Changeset patch on @object-ui/data-objectstack and @objectstack/skills. MECHANISM ASSUMPTION DISPROVED: the order assumed a strip on the discovery line alone; read from source, the adapter spreads its config into new ObjectStackClient({...config}) and the client joins every conventional route onto its base as given, so a discovery-only strip would connect and then double every client-routed read — the normalisation sits in the constructor instead (same ruling, one step earlier), and the pin's last case reads a client-routed URL. Acceptance: git grep -n \"baseUrl: '/api/v1'\" -- skills is 0 hits on e73e6d45.",
      "tests": "New pin ui/packages/data-objectstack/src/connectBaseUrlApiSuffix-27774.test.ts (7 cases: origin, '' , relative /api/v1, absolute /api/v1, /api/v1/ with trailing slash, a non-version path prefix kept, one client-routed listMetadataItems read from an /api/v1 base). Red leg on the pre-fix index.ts restored from ed0e71db: `Tests 4 failed | 3 passed (7)`, `expected [ '/api/v1/api/v1/discovery' ] to deeply equal [ '/api/v1/discovery' ]`; restored with git checkout HEAD -- path, blob 25b604f7 equal before/after, git diff HEAD empty. Green leg on e73e6d45: `Tests 7 passed (7)`. Package: `pnpm --dir ui exec vitest run packages/data-objectstack/` → `Test Files 104 passed (104) · Tests 1228 passed (1228)` exit 0 (lock VERDICT command-exit 0); `pnpm --filter @object-ui/data-objectstack run type-check` exit 0. No ablation beyond the red/green pair: no dist is in the resolution path (the test imports ./index source). Lint `pnpm --filter @object-ui/data-objectstack lint` exit 0 (0 errors, pre-existing any warnings, none on changed lines); `pnpm --dir ui run check:new-line-citations` 0 new.",
      "gates": "Derived: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths, off the merge base, tree e73e6d45) → 58 families. Ran 57 locally, each `COMMAND :: exit CODE` line recorded before any pipe; all exit 0 except: `pnpm check:dual-build-cjs-loads :: exit 3` (PREREQUISITE NOT MET — reads every package's dist, this worktree holds only the adapter's dependency closure; declared to CI `Lint & Repo Gates`) = NOT MEASURED; `pnpm --filter @objectstack/spec run check:skill-examples` exit 3 on the first run (client-react dist absent), exit 0 after `pnpm --filter @objectstack/client-react build` (`275 prose examples type-check across 3 surface(s)`). `node scripts/check-sdui-manifest.mjs :: exit 0`, `node scripts/check-skills-token-ratchet.mjs :: exit 0` (data-integration.md 4328/4451, auth-permissions.md 3864/3866, evals/data-integration.json 470/471; no ceiling moved), `pnpm --dir ui exec vitest run scripts/ :: exit 0` (under the lock). `--ran` reconciliation: `58 derived famil(ies) accounted for — 57 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)`, 0 UNRUN. CI check-runs on PR #27967: in_progress at report time (not waited for).",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no GitHub MCP tool used, read or write",
      "api_writes": "3 — git push origin claude/project-thread-83w07l (not REST); relay pr_create via scripts/pm/fleet-write/dispatch.mjs → POST /repos/objectstack-ai/objectstack/dispatches (run 41009121925, read-back identical, PR #27967, no assignees, no review request — the harness's after-PR assign/review step skipped per the order); this comment via scripts/pm/post-stamped.mjs → POST /repos/objectstack-ai/objectstack/issues/27774/comments. REST reads only otherwise (issue, comments, pulls?head=, PR #27907 files).",
      "open_questions": [
        { "question": "Report comment first line: os-dev.md says the bare marker `os-dev-report` is line 1; post-stamped refuses any comment whose first non-empty line is not the seat signature (exit 2, nothing sent, measured once here). Written signature first, marker on line 2 — the tool's refusal, not the order, decided it.", "options": ["A accept marker on line 2 (done)", "B amend os-dev.md's first-line clause to match post-stamped"], "recommendation": "B, for the next dev — a rule the write door refuses cannot be followed." }
      ],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — skills/objectui/guides/project-setup.md teaches `VITE_API_BASE_URL=/api/v1` as an env example without wiring it into the adapter; with this PR that value works either way. Not a defect.",
        "carrier: none · noted, not filed — ui/packages/data-objectstack/README.md MetadataClient examples teach baseUrl '/api/v1'; that class already collapses the suffix itself (its own regex), so they work. A second copy of the same strip in the same package, left alone: different class, no defect.",
        "carrier: none · noted, not filed — the approvals reads and the analytics dataset query joined onto this.baseUrl without a trailing-slash trim; the constructor normalisation covers them now with no change of their own (analytics lost its local trim as dead code).",
        "declared-surface deviation — guides/auth-permissions.md edited (one line) though the claim declared only guides/data-integration.md: same defect, fifth hit of the card's acceptance grep, same governed skill; no other claim holds the file. Dedupe words: ObjectStackAdapter baseUrl, api/v1/api/v1, serverOriginOf, auth-permissions baseUrl."
      ]
    }

    Files changed (7): .changeset/27774-adapter-base-url-origin.md, skills/objectui/evals/data-integration.json, skills/objectui/guides/auth-permissions.md, skills/objectui/guides/data-integration.md, ui/packages/data-objectstack/README.md, ui/packages/data-objectstack/src/connectBaseUrlApiSuffix-27774.test.ts, ui/packages/data-objectstack/src/index.ts. Line budget: 186 changed lines (+143 / −43) vs 3000. Skill readings (lines · ratchet tokens): data-integration.md 480 → 480 · 4303 → 4328; auth-permissions.md 416 → 416 · 3866 → 3864; evals/data-integration.json 54 → 55 · 466 → 470; whole skills/objectui 5416 → 5417 lines; catalog "ratcheted (authored)" 208049 → 208079 of 217809. Seat 4's regions in index.ts untouched (PR #27907's file list holds no data-objectstack file).

  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

    ACCEPT → PR #27967 comment 6516379691 (Tier H; contract PASS 6515998431; review requested from os-zhuang and hotlong) · 2026-10-30T06:19Z


    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:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingdocumentationImprovements or additions to documentationdomain:uifindingpm:dispatchedpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions