Repository navigation
Seam: one request opens a record — a record-page payload (record + related counts and first rows + field access + lock) and an app-scoped metadata bundle, so a record open is 2–3 requests instead of 23–45 serialized in three stages #27627
Description
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff
Filed from the record-page epic #26676 as a sub-issue after the maintainer's 「别人的界面很丝滑,但是我们的界面总觉得卡顿,云端更卡」 and the seat's measurement (2026-10-29). Ruling: 「立…B(接缝卡:记录页一次取齐 + 元数据打包)两张卡,p1」. A Seam: card: the producer is the REST surface (packages/rest / plugin-hono-server, the data and metadata routes), the consumer is the console's data layer (ui/packages/data-objectstack) and the record page; the seat that claims it declares both ends. The client-side waste on the same path is #27626.
Measured
Local (console main 273137d227, dev mode, HotCRM on localhost:4001): opening one contact = 45 requests cold / 23 warm, in three serial stages — ① the record (GET /data/crm_contact?populate=…) + security/explain ×2 + approvals/requests; ② after the record arrives (+130 ms of client work): one GET /meta/object/<child> per related object (9 on a contact), field-access ×4, the approvals lock; ③ after the metadata arrives: one GET /data/<child>?top=1&filter=… count probe per related list (10 on a contact) + attachments + the related rows query + the account. Locally each stage is tens of milliseconds; the drawer is visible at 300 ms.
Cloud (huayan.objectos.app, Cloudflare colo ARN, h2, prod bundle 2.2 MB JS in 93 scripts): the same endpoints cost 0.5–1.4 s each when called alone (GET /api/v1/runtime/config, 293 bytes: 555 / 604 / 729 / 1068 / 1377 ms over five sequential calls; GET /meta/app 0.9–1.8 s; GET /meta/view 1.8–3.8 s; no cache-control, no server-timing). The HotCRM contacts list route fired 42 API calls on load, of which auth/me/localization 8.2 s, packages 7.9 s, sys_inbox_message 7.5 s, meta/dashboard 6.1 s, meta/object/sys_user 5.3 s, data/crm_contact 5.3 s — the same calls that take ~1 s alone take 5–8 s when fifteen of them run at once, and the list had not rendered after 50 s. A three-stage, 23-request record open on that path is a multi-second wait by arithmetic alone.
Linear, Attio and Twenty open a record with one aggregated request (counts and permissions ride with the record), load metadata once at boot, and prefetch on hover.
Target
- A record-page payload endpoint (shape to be designed by the claiming seat and recorded under
packages/spec/contracts/**):GET /api/v1/data/<object>/<id>/page(or aquerybody) returns in ONE response — the record with its populated lookups; for every related list the console would draw (the inbound lookups, in the object's declared order) the count and the first N rows (N = 3, the compact panel's face) with the related-list columns; the caller's field access for the record; the approval lock state; the record's security verdict (explain) for the actions the header draws. One request, one round trip, one server-side transaction. - An app-scoped metadata bundle:
GET /api/v1/meta/app/<appId>/bundlereturns the app, its navigation, every object the app's navigation and those objects' inbound relations reach, their views, pages and dashboards, with an ETag; the console loads it once per session and sendsIf-None-Matchafter. Today's per-objectGET /meta/object/<name>stays for Studio and for objects outside the bundle. - The console consumes both: the record page (split pane, overlay, full page, Record page v4: same-shaped related panels with no collapse, a persistent tab row under the header (the enlarged state is the active tab), Activity as the first panel and a tab, one top bar on every face, tiers by container width #27524 / Record drawer v4: a bounded peek over the list — md cap instead of the field-count bucket, no dim overlay, the list stays readable and clickable, ⤢ maximizes in place at the same URL; the full page is reached only from the row ↗ and the header ⋯ #27545) opens from the page payload with no second stage; stepping ↓ ↑ prefetches the next and previous records' payloads; the per-related
top=1count probes, the per-open child metadata loads and the separatefield-access/lock/explaincalls on open retire (startup posture: no dual path kept). - Server-side observability for the cloud reading: the REST layer emits
Server-Timing(db, meta, total) on every response, so the next measurement separates origin time from the network path; metadata responses carryCache-Control+ETag. - Clause-②: yes (new REST routes, declared in the spec contracts); Metadata-protocol: added (the bundle's shape).
File surface
Producer: packages/rest/src/** (routes), packages/plugin-hono-server/** (wiring), packages/spec/contracts/** (the two shapes), packages/objectql only if a batched count query is needed, tests beside, changeset. Consumer: ui/packages/data-objectstack/src/index.ts, ui/packages/app-shell/src/views/RecordDetailView.tsx + recordDrawerStack.tsx (prefetch), ui/packages/plugin-detail/src/renderers/recordBinding.tsx + RelatedCardStack.tsx (counts and rows from the payload), tests beside, changeset.
Acceptance
- Contract tests for both shapes; a console test that a record open issues exactly one page-payload request (plus at most one metadata bundle on a cold session) and zero
top=1probes. - The cloud reading re-run by the epic seat on
huayan.objectos.appafter landing: record open under 1 s warm, list route under 3 s cold, withServer-Timingin the PR body. - The epic seat verifies in the console preview before ACCEPT (maintainer: 「车队开发完后你审核效果」).
Activity
objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim: PM loop round 6 · 2026-10-31T02:57Z
Session:
session_01L9qibwb6hBqszPTYJobitmAccount:
os-teslaBranch:
claude/project-thread-dd5lh4(card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead ofclaude/issue-27627-<slug>)Worktree:
objectstack-issue-27627-timingDomain:
domain:specSeat:
domain:spec#1Card thread: session
session_01L9qibz5qPfjVU7Mns3iE1H; Target 4 (metadata caching headers + Server-Timing coverage),Part of #27627; the dispatch order is in the seat's project, frame + card file.Ruling-ref: the maintainer's 「27627 插队」 (2026-10-31T02:51Z) and the epic ruling quoted in the card body
File surface:
packages/rest/src/**(list routes,runtime/config, shared header helper),packages/plugin-hono-server/**(timing middleware if there), tests, changeset; never the bundle route (stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT,effort: highClause-②: no
Metadata-protocol: none
Responsibility: metadata list routes and
runtime/configanswer withoutETag/Cache-Control, and Server-Timing does not cover every REST route | add both under the item routes' per-caller folds and the existing gate | console sessions on the cloud pathThread-read: 6533483101
Premise: to be measured first by the dev on
main69ce01d (per-route ETag / Cache-Control / 304 table); PR 1 #27713's body says the item routes already send all threeSerial constraints cleared: PR 1 #27713 merged 2026-10-30T21:06Z; the sibling bundle-producer thread owns the bundle route only; the dev re-checks open PRs on
meta-item-read-routes.ts/meta-collection-routes.tsobjectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim: PM loop round 6 · 2026-10-31T02:58Z
Session:
session_01L9qibwb6hBqszPTYJobitmAccount:
os-teslaBranch:
claude/project-thread-hw8j7d(card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead ofclaude/issue-27627-<slug>)Worktree:
objectstack-issue-27627-bundleDomain:
domain:specSeat:
domain:spec#1Card thread: session
session_01L9qibwM9YxDuiRDQYmA1Yd; PR 2, Target 2 producer (GET /api/v1/meta/app/{appId}/bundle+ per-callerETag),Part of #27627; the console half is ui seat 2's, landing after this PR; the dispatch order is in the seat's project, frame + card file.Ruling-ref: the maintainer's 「27627 插队」 (2026-10-31T02:51Z) and the epic ruling quoted in the card body
File surface:
packages/rest/src/**(the bundle route),packages/plugin-hono-server/**wiring if needed,packages/speccontracts + generated artifacts, rest census tests, thecheck-route-enveloperow,content/docs/references/api, dogfood fixture if the census needs it, tests, changeset (stop on breach; explain in the report)Container & model:
L,mode:thread,model: TIER_DEFAULT(new REST route, so a contract review is owed),effort: highClause-②: yes (widening)
Metadata-protocol: added
Responsibility: a record open still loads
/meta/object/<object>per object after PR 1, and there is no app-scoped metadata bundle | one per-caller bundle with anETag, built through the item read gate | console sessions on the cloud pathThread-read: 6533483101
Premise: holds — on
main69ce01d no/meta/app/{id}/bundleroute exists, and PR 1 #27713's body names the remaining second-wave/meta/objectread as PR 2'sSerial constraints cleared: PR 1 #27713 merged 2026-10-30T21:06Z; the sibling Target 4 thread (
claude/project-thread-dd5lh4) never touches the bundle routeobjectstack-fleet commentedon Oct 31, 2026
domain:ui#2 · os-tesla · session_01L9qibxgfM8p8t3fo6y9eFK
Claim: PM loop round 1 · 2026-10-31T02:59Z · console half (Target 3 metadata), split out by
domain:spec#1beside its producer claim 6538108232Session:
session_01L9qibxgfM8p8t3fo6y9eFK(seat; card threadsession_01L9qibzFu8iUogiZhxL9tAo)Account:
os-teslaBranch:
claude/project-thread-xoio4p(card thread; the platform assigns the thread's branch)Worktree:
objectstack-27627-consoleDomain:
domain:ui(the consumer half of adomain:specSeam card)Seat:
domain:ui#2File surface:
ui/packages/data-objectstack/**,ui/packages/app-shell/**(app entry, record views),ui/packages/plugin-detail/**only if it reads child metadata, tests, root changeset (stop on breach; explain in the report)Container & model:
M/L,mode:thread,model: TIER_DEFAULT (default judgment tier),effort: xhighClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6538108232
Premise: holds
Serial constraints cleared: lands after the producer PR of claim 6538108232 (consumer-after-producer); serial after PR #28116 (#27524 ②) on
RecordDetailView.tsx/ plugin-detail — the dev mergesorigin/mainafter it mergesPart of #27627 (PR 3); the maintainer's 「27627 插队」 makes it this seat's top card.
objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim correction · 2026-10-31T03:04Z · amends claim 6538102504 (branch
claude/project-thread-dd5lh4), append-onlyFile surface, amended by seat ruling:
packages/cloud-connection/src/runtime-config-plugin.tsand its tests.GET /runtime/configgets a body-hashETagwithprivate, no-cache, andIf-None-Matchanswers 304. It stays anonymous. The caller is resolved only whenX-OS-Debug-Timingis sent, so the existing timing gate can open there.GET /auth/me/localization(plugin-hono-server, already in surface), which gets the sameETagwithprivate, no-cache.main69ce01d) is the premise.objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim correction · 2026-10-31T03:10Z · amends claim 6538108232 (branch
claude/project-thread-hw8j7d), append-onlyFile surface, amended by seat ruling: also
packages/client(meta.getAppBundle(appId)), so the route ledger row takes dispositionsdk. PR 1'sdata.recordPageis the precedent. PR: #28287 (draft,Part of #27627). Shape:packages/spec/src/api/app-bundle.zod.tsAppMetadataBundleResponseSchema.objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim correction · 2026-10-31T03:11Z · amends claim 6538102504 (branch
claude/project-thread-dd5lh4), append-onlyFile surface, amended by seat ruling. Both additions are forced by the dependency graph, and the PR body should name both:
packages/types/src/representation-validator.ts(new), plus one export line inpackages/types/src/index.ts. This is the one copy of the body-hash ETag /If-None-Matchrule.rest,plugin-hono-serverandcloud-connectionall depend ontypes, and onlyrestkeeps the/metawrapper.packages/cloud-connection/package.jsongains@objectstack/observability(workspace:*), plus its lockfile lines. It is needed for the existing admin perf-disclosure gate onruntime/config.objectstack-fleet commentedon Oct 31, 2026
domain:ui#2 · os-tesla · session_01L9qibzFu8iUogiZhxL9tAo
os-dev-report
Console half of #27627 (PR 3, metadata bundle consumer): draft #28321, head
c6e775cf, reported 2026-10-31T04:33Z. Lands after #28287.{ "card": 27627, "pr": 28321, "branch": "claude/project-thread-xoio4p", "head": "c6e775cf5b508d2f3a6e4cd878eada5584c8a7a8", "draft": true, "lands_after": [28287], "declarations": { "clause_2": "no", "metadata_protocol": "none" }, "gates": { "derived": 67, "run": 67, "exit_0": 67, "not_measured": 0, "unrun": 0, "reconcile_exit": 0, "extra": ["check:new-line-citations :: exit 0", "check:nul-bytes :: exit 0"] }, "type_check": { "data-objectstack": 0, "app-shell": 0 }, "tests": { "card_files": 3, "card_tests": 20, "importer_files_run": 695, "importer_files_green_after_fix": 695 }, "acceptance": { "warm_record_open": { "page_requests": 1, "metadata_requests": 0 }, "cold_record_open": { "page_requests": 1, "bundle_requests": 1, "by_name_metadata": 0, "waves": 1 } }, "ablations": [ { "off": "bundle read in fetchObjectSchemaFresh", "red": 7 }, { "off": "AppContent loadAppBundle call", "red": 2 }, { "off": "write-door staleness", "red": 1 } ], "line_budget": { "limit": 3000, "used": 894, "additions": 864, "deletions": 30 }, "files_changed": 12, "deviations": [ "withheld vs outside: the bundle names nothing withheld, so an absent name keeps its by-name read (seat and spec seat 1 agreed)", "adapter fetches the bundle directly: client meta.getAppBundle had no If-None-Match/304; switch when the conditional method lands on #28287", "AppMetadataBundleResponse type not imported until #28287 is on main", "live boot NOT MEASURED: the route exists only on #28287's branch" ], "writes": { "relay": 2, "mcp_calls": 0 } }objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibz5qPfjVU7Mns3iE1H
os-dev-report
{ "issue": 27627, "status": "done", "branch": "claude/project-thread-dd5lh4", "pr": "https://github.com/objectstack-ai/objectstack/pull/28320", "session": "session_01L9qibz5qPfjVU7Mns3iE1H", "premise_still_valid": true, "summary": "Target 4 only (Part of). The /meta type list, every /meta/:type list, the uncached item exit (app/dashboard/doc/book, drafts, ?package=, member-scoped), /auth/me/localization and /runtime/config answer a weak body-hash ETag over the served bytes, Cache-Control private, no-cache and a bodiless 304; the rule is one module in @objectstack/types. Every timed response carries db and meta beside total (zero members when nothing ran); /runtime/config opens the per-request gate for an admin only when X-OS-Debug-Timing is sent. Step 1 correction: the app/dashboard/doc/book item doors had no ETag on main. Dispatcher /meta twin: private, no-cache, no ETag, no 304.", "tests": "head 6d31fbb1 under os-verify-lock VERDICT command-exit 0: rest 360 files / 7127 passed (351 skipped); cloud-connection 62 / 765; plugin-hono-server 36 / 457; types 35 / 846. runtime meta/timing targeted 31 / 1451 (before the gate fix, which touched no runtime/rest logic). New: representation-validator.test.ts 10, meta-representation-etag.test.ts 13, server-timing-seeded-marks.test.ts 4, localization validator block 5, runtime-config-etag.test.ts 7. Ablation: list chain hashing the pre-gate list (metaRepresentationCaching(raw, cacheControl)) -> 1 failed / 12 passed, exactly 'two callers whose gate differs get different tags'; restored, blob == HEAD. Live HotCRM: main 0/58 lists+bootstrap ETag; branch 58/58 ETag, 57/58 304 (flow 200 by design, same on main), db/meta/total on 58/58 for the admin header.", "gates": "local: dispatch-gates --commands on the final tree -> 94 commands, each run with </dev/null, '<command> :: exit <code>' recorded first; --ran -> 94 run, 0 NOT-MEASURED, 0 UNRUN, all exit 0. First sweep (76) reds fixed in 6d31fbb1: check:route-envelope (helper declared {}; localization/runtime-config bodies kept as call-site literals) and check:test-source-alias (observability alias in cloud-connection). check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure exit 0 after a full dts build. check-governed-merges --branch HEAD: 0 of 23 governed, 1025 lines. CI: PR check-runs not yet concluded at report time; the seat reads them.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "line_budget": "23 files, +991 / -34 (1025 changed lines incl. 3 lockfile lines)", "files_changed": 23, "deviations": [ "Rebase onto main could not be force-pushed (auto-mode classifier refused --force-with-lease); history kept as merge origin/main + fix commit, tree byte-identical to the rebased tree.", "PR body footer: the session-URL `_Generated by_` line is present but without the preceding `---` rule line; dev writes the body once, so the seat may add the rule line if the platform needs the whole block.", "Branch live re-measure was taken before the main merge (head e7bd43ac); the merge brought no overlapping file." ], "mcp_calls": "13 — all reads: issue_read x5, list_pull_requests x3, search_pull_requests x3, pull_request_read x2 (transcript grep); 0 write tools", "api_writes": "2 relay writes so far — pr_create (fleet-write run 41168920329, #28320) and this os-dev-report comment via post-stamped --comment=27627; plus git push (not REST)", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed — the flow item answers an ETag that never revalidates (registration read live beside the document is in no validator); by design per meta-item-read-routes.ts, recorded in the PR body only" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwM9YxDuiRDQYmA1Yd
os-dev-report
{ "issue": 27627, "part": "PR 2 of #27627 (bundle producer)", "pr": "https://github.com/objectstack-ai/objectstack/pull/28287", "draft": true, "branch": "claude/project-thread-hw8j7d", "head": "28ac68c20651a0ac549956e52c8e3c85de16ab7c", "base_merged": "53749673ba7a0005d09e8a79544da10d5faa10bc", "claim": 6538108232, "gates": { "derived": 125, "run": 125, "exit_0": 125, "not_measured": 0, "unrun": 0, "reconcile": "dispatch-gates --ran: 125 derived, 125 run, 0 NOT-MEASURED, 0 UNRUN (exit 0)", "reruns_after_prerequisite": [ "node scripts/check-plugin-teardown-shape.mjs --self-test (pinned fixture commit fetched into the shallow clone)", "pnpm --filter @objectstack/spec run check:skill-examples (after pnpm build)", "pnpm check:dual-build-cjs-loads (after pnpm build)" ], "finding_fixed": "pnpm check:doc-authoring: tracker id in the ledger row note string, moved to a // comment, rerun exit 0" }, "tests": { "rest_bundle_route": "14/14", "client_suite": "685/685 (53 files)", "spec_shape": "3/3", "rest_census_set": "307 passed (10 files)", "dogfood_authz": "70/70", "typecheck": { "rest": 0, "client": 0, "spec": 0 } }, "ablation": { "mutation": "bundleValidator(JSON.stringify(body)) -> bundleValidator(JSON.stringify(Object.keys(body)))", "tool": "scripts/ablation-replace.mjs", "red": "2/14", "restored_blob_equals_head": true, "green_after": "14/14" }, "line_budget": { "limit": 3000, "changed": 1215, "additions": 1202, "deletions": 13 }, "files_changed": [ ".changeset/27627-app-metadata-bundle.md", "content/docs/references/api/app-bundle.mdx", "content/docs/references/api/index.mdx", "content/docs/references/api/meta.json", "content/docs/references/index.mdx", "docs/audits/2026-07-unknown-key-strictness-ledger.counts/api.md", "packages/client/src/index.ts", "packages/client/src/meta-app-bundle.test.ts", "packages/rest/src/meta-app-bundle-routes.test.ts", "packages/rest/src/meta-app-bundle-routes.ts", "packages/rest/src/rest-config-mount-table.pin.test.ts", "packages/rest/src/rest-route-ledger.ts", "packages/rest/src/rest-server-canonical-query-ast.test.ts", "packages/rest/src/rest-server-docblock-position.test.ts", "packages/rest/src/rest-server-registrar-files.ts", "packages/rest/src/rest-server.ts", "packages/spec/api-surface/api.json", "packages/spec/authorable-surface/api.json", "packages/spec/declaration-map/api.json", "packages/spec/export-origins/api.json", "packages/spec/json-schema.manifest/api.json", "packages/spec/llms.txt", "packages/spec/src/api/app-bundle.test.ts", "packages/spec/src/api/app-bundle.zod.ts", "packages/spec/src/api/index.ts", "scripts/check-route-envelope.mjs" ], "deviations": [ "ETag = SHA-256 of the served body after every gate instead of folding per-dimension fingerprints (seat-confirmed; the Target 4 rule; switch to its helper if it lands first)", "meta.getAppBundle(appId, { ifNoneMatch }) answers a conditional {notModified, data?, etag} in getCached's spelling rather than bare data (seat note from the ui seat 2 consumer); private fetch gains opt-in admitNotModified", "metaItemAnswerSources gains an optional 5th type argument defaulting to req.params.type" ], "out_of_scope_findings": [ { "class": "a", "what": "meta.getCached 304 branch in packages/client is unreachable: private fetch throws on non-ok before it runs", "dedupe": [ "getCached", "notModified", "304", "If-None-Match", "client fetch" ] } ], "writes": { "relay": 3, "relay_ops": [ "pr_create #28287", "issue_patch #28287 body", "comment #27627 (this report)" ], "mcp_calls": { "writes": 0, "reads": "issue_read, pull_request_read only" } }, "contract_review_subagent": false, "ready_flip": false, "automerge": false }objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim correction · 2026-10-31T04:35Z · amends claim 6538102504 (branch
claude/project-thread-dd5lh4, PR #28320), append-onlyFile surface, amended by seat ruling: plus two doc edits the docs-drift list surfaced, both incomplete after this change rather than wrong.
docs/OBSERVABILITY.md: the Server-Timing members table gains themetarow, and notes thatdbandmetaare sent as zero members.content/docs/api/metadata-api.mdx:GET /metaandGET /meta/:typegain theETag,private, no-cacheand304answer.objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwM9YxDuiRDQYmA1Yd
os-dev-report
{ "issue": 27627, "part": "PR 2 of #27627 (bundle producer)", "pr": "https://github.com/objectstack-ai/objectstack/pull/28287", "draft": true, "branch": "claude/project-thread-hw8j7d", "head": "1e7a1b104ea5f7afccee6cb52f21b1c5fc01c501", "base_merged": "53749673ba7a0005d09e8a79544da10d5faa10bc", "claim": 6538108232, "gates": { "derived": 125, "run": 125, "exit_0": 125, "not_measured": 0, "unrun": 0, "reconcile": "dispatch-gates --ran: 125 derived, 125 run, 0 NOT-MEASURED, 0 UNRUN (exit 0)", "reruns_after_prerequisite": [ "node scripts/check-plugin-teardown-shape.mjs --self-test (pinned fixture commit fetched into the shallow clone)", "pnpm --filter @objectstack/spec run check:skill-examples (after pnpm build)", "pnpm check:dual-build-cjs-loads (after pnpm build)" ], "finding_fixed": "pnpm check:doc-authoring: tracker id in the ledger row note string, moved to a // comment, rerun exit 0", "taken_at": "28ac68c2", "after_head_commits": "2 commits, packages/client and the changeset only: the derived set is unchanged (diffed); client tsc 0; check:doc-authoring, issue-citations, nul-bytes, test-source-alias, agent-test-spelling, route-envelope, closed-ceremony-text, type-check-coverage, undeclared-dep-imports, empty-changeset, changeset-no-major all exit 0" }, "tests": { "rest_bundle_route": "14/14", "client_suite": "687/687 (53 files) at 1e7a1b10", "spec_shape": "3/3", "rest_census_set": "307 passed (10 files)", "dogfood_authz": "70/70", "typecheck": { "rest": 0, "client": 0, "spec": 0 }, "client_react": "34/34" }, "ablation": { "mutation": "bundleValidator(JSON.stringify(body)) -> bundleValidator(JSON.stringify(Object.keys(body)))", "tool": "scripts/ablation-replace.mjs", "red": "2/14", "restored_blob_equals_head": true, "green_after": "14/14" }, "line_budget": { "limit": 3000, "changed": 1240, "additions": 1226, "deletions": 14 }, "files_changed": [ ".changeset/27627-app-metadata-bundle.md", "content/docs/references/api/app-bundle.mdx", "content/docs/references/api/index.mdx", "content/docs/references/api/meta.json", "content/docs/references/index.mdx", "docs/audits/2026-07-unknown-key-strictness-ledger.counts/api.md", "packages/client/src/index.ts", "packages/client/src/meta-app-bundle.test.ts", "packages/rest/src/meta-app-bundle-routes.test.ts", "packages/rest/src/meta-app-bundle-routes.ts", "packages/rest/src/rest-config-mount-table.pin.test.ts", "packages/rest/src/rest-route-ledger.ts", "packages/rest/src/rest-server-canonical-query-ast.test.ts", "packages/rest/src/rest-server-docblock-position.test.ts", "packages/rest/src/rest-server-registrar-files.ts", "packages/rest/src/rest-server.ts", "packages/spec/api-surface/api.json", "packages/spec/authorable-surface/api.json", "packages/spec/declaration-map/api.json", "packages/spec/export-origins/api.json", "packages/spec/json-schema.manifest/api.json", "packages/spec/llms.txt", "packages/spec/src/api/app-bundle.test.ts", "packages/spec/src/api/app-bundle.zod.ts", "packages/spec/src/api/index.ts", "scripts/check-route-envelope.mjs" ], "deviations": [ "ETag = SHA-256 of the served body after every gate instead of folding per-dimension fingerprints (seat-confirmed; the Target 4 rule; switch to its helper if it lands first)", "meta.getAppBundle(appId, { ifNoneMatch }) answers a conditional {notModified, data?, etag} in getCached's spelling rather than bare data (seat note from the ui seat 2 consumer); private fetch gains opt-in admitNotModified", "metaItemAnswerSources gains an optional 5th type argument defaulting to req.params.type", "meta.getCached passes admitNotModified, so its 304 answers { notModified: true } instead of throwing (spec seat 1 asked for this; the class (a) finding is now fixed in this PR)" ], "out_of_scope_findings": [], "writes": { "relay": 5, "relay_ops": [ "pr_create #28287", "issue_patch #28287 body", "comment #27627 (first report)", "issue_patch #28287 body (getCached)", "comment #27627 (this report)" ], "mcp_calls": { "writes": 0, "reads": "issue_read, pull_request_read only" } }, "contract_review_subagent": false, "ready_flip": false, "automerge": false, "ablation_getcached": { "mutation": "drop { admitNotModified: true } from getCached's fetch", "red": "1/5", "restored_blob_equals_head": true }, "supersedes_report_comment": 6539061874 }objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwM9YxDuiRDQYmA1Yd
os-dev-report
{ "issue": 27627, "part": "PR 2 of #27627 (bundle producer)", "pr": "https://github.com/objectstack-ai/objectstack/pull/28287", "draft": true, "branch": "claude/project-thread-hw8j7d", "head": "170b86ad19fb0e32fa0fc1462ece83ab32ed28d0", "base_merged": "f49b4787 (main with #28320)", "claim": 6538108232, "gates": { "derived": 125, "run": 125, "exit_0": 125, "not_measured": 0, "unrun": 0, "taken_at": "170b86ad", "derived_set_changed": false, "reconcile": "dispatch-gates --ran: 125 derived, 125 run, 0 NOT-MEASURED, 0 UNRUN (exit 0)", "reruns_after_prerequisite": [ "spec dist-reading checks + check:docs/check:generated after check:generated --fix rebuilt spec and regenerated app-bundle.mdx", "check:skill-examples after client + client-react builds", "check:type-check-debt after pnpm install --frozen-lockfile (cloud-connection's new observability link)" ] }, "tests": { "rest_bundle_route": "15/15", "client_suite": "687/687 (53 files) at 1e7a1b10", "spec_shape": "3/3", "rest_census_set": "307 passed (10 files)", "dogfood_authz": "70/70", "typecheck": { "rest": 0, "client": 0, "spec": 0 }, "client_react": "34/34", "rest_full_suite": "7148 passed (361 files)" }, "ablation": { "mutation": "metaRepresentationCaching(body, undetermined) -> metaRepresentationCaching(Object.keys(body), undetermined)", "tool": "scripts/ablation-replace.mjs", "red": "3/15", "restored_blob_equals_head": true, "green_after": "15/15" }, "line_budget": { "limit": 3000, "changed": 1230, "additions": 1216, "deletions": 14 }, "files_changed": [ ".changeset/27627-app-metadata-bundle.md", "content/docs/references/api/app-bundle.mdx", "content/docs/references/api/index.mdx", "content/docs/references/api/meta.json", "content/docs/references/index.mdx", "docs/audits/2026-07-unknown-key-strictness-ledger.counts/api.md", "packages/client/src/index.ts", "packages/client/src/meta-app-bundle.test.ts", "packages/rest/src/meta-app-bundle-routes.test.ts", "packages/rest/src/meta-app-bundle-routes.ts", "packages/rest/src/rest-config-mount-table.pin.test.ts", "packages/rest/src/rest-route-ledger.ts", "packages/rest/src/rest-server-canonical-query-ast.test.ts", "packages/rest/src/rest-server-docblock-position.test.ts", "packages/rest/src/rest-server-registrar-files.ts", "packages/rest/src/rest-server.ts", "packages/spec/api-surface/api.json", "packages/spec/authorable-surface/api.json", "packages/spec/declaration-map/api.json", "packages/spec/export-origins/api.json", "packages/spec/json-schema.manifest/api.json", "packages/spec/llms.txt", "packages/spec/src/api/app-bundle.test.ts", "packages/spec/src/api/app-bundle.zod.ts", "packages/spec/src/api/index.ts", "scripts/check-route-envelope.mjs" ], "deviations": [ "ETag = the /meta reads' shared validator (#28320: metaRepresentationCaching + sendMetaRepresentation, weak representationEtag of the served body) instead of folding per-dimension fingerprints; the route's own SHA-256 rule is gone", "meta.getAppBundle(appId, { ifNoneMatch }) answers a conditional {notModified, data?, etag} in getCached's spelling rather than bare data (seat note from the ui seat 2 consumer); private fetch gains opt-in admitNotModified", "metaItemAnswerSources gains an optional 5th type argument defaulting to req.params.type", "meta.getCached passes admitNotModified, so its 304 answers { notModified: true } instead of throwing (spec seat 1 asked for this; the class (a) finding is now fixed in this PR)" ], "out_of_scope_findings": [], "writes": { "relay": 7, "relay_ops": [ "pr_create #28287", "issue_patch #28287 body", "comment #27627 (first report)", "issue_patch #28287 body (getCached)", "comment #27627 (this report)", "issue_patch #28287 body (helper switch)", "comment #27627 (this report)" ], "mcp_calls": { "writes": 0, "reads": "issue_read, pull_request_read only" } }, "contract_review_subagent": false, "ready_flip": false, "automerge": false, "ablation_getcached": { "mutation": "drop { admitNotModified: true } from getCached's fetch", "red": "1/5", "restored_blob_equals_head": true }, "supersedes_report_comment": 6539142744, "delta_since_review": { "reviewed_head": "1e7a1b10", "record": 6539412174, "files": [ "packages/rest/src/meta-app-bundle-routes.ts", "packages/rest/src/meta-app-bundle-routes.test.ts", "packages/rest/src/rest-route-ledger.ts", "packages/rest/src/rest-server-docblock-position.test.ts", "packages/spec/src/api/app-bundle.zod.ts", "scripts/check-route-envelope.mjs", ".changeset/27627-app-metadata-bundle.md", "content/docs/references/api/app-bundle.mdx" ], "served_members_changed": false, "etag": "strong SHA-256 -> weak W/ representationEtag", "enableCache_false": "no validator, as the item reads" } }objectstack-fleet commentedon Oct 31, 2026
domain:ui#2 · os-tesla · session_01L9qibxgfM8p8t3fo6y9eFK
Claim amendment (same console-half claim, same branch
claude/project-thread-xoio4p, PR #28321) · 2026-10-31T10:02Z8441a01277, which clears the consumer-after-producer constraint.Part of #27627toFixes #27627(spec seat 1 agreed; the card stays open until feat(console): entering an app loads its metadata bundle once, and a record open reads no metadata #28321 merges).origin/main, switch to the conditionalgetAppBundle(appId, { ifNoneMatch }), and bind the spec typeAppMetadataBundleResponseSchema(name approved by the maintainer). Clause-② is re-measured on the built declarations after the type binding.objectstack-fleet commentedon Oct 31, 2026
domain:ui#2 · os-tesla · session_01L9qibzFu8iUogiZhxL9tAo
os-dev-report
Console half of #27627, final pass: draft #28321, head
07e67218, reported 2026-10-31T10:58Z. Producer #28287 is on main; the PR body now saysFixes #27627(claim amendment 6541997127). Supersedes report 6539052883.{ "card": 27627, "pr": 28321, "branch": "claude/project-thread-xoio4p", "head": "07e672183d2728b1ac2d51cae149ab00772f7ece", "draft": true, "closing": "Fixes #27627", "declarations": { "clause_2": "yes (widening)", "metadata_protocol": "none", "changeset_level": "patch" }, "clause_2_measure": { "on": "built ui/packages/data-objectstack/dist/index.d.ts", "new_public_members": ["ObjectStackAdapter.loadAppBundle(appId: string): Promise<void>"], "app_shell_new_declarations": 0, "dispatch_expected": "no" }, "gates": { "derived": 67, "run": 67, "exit_0": 67, "not_measured": 0, "unrun": 0, "reconcile_exit": 0, "extra": ["check:new-line-citations :: exit 0", "check:nul-bytes :: exit 0"] }, "type_check": { "data-objectstack": 0, "app-shell": 0, "app-shell-tests": 0 }, "tests": { "card_files": 3, "card_tests": 21, "wide_run_files": 419, "wide_run_tests": 3336, "failed": 0 }, "acceptance": { "warm_record_open": { "page_requests": 1, "metadata_requests": 0 }, "cold_record_open": { "page_requests": 1, "bundle_requests": 1, "by_name_metadata": 0, "waves": 1 } }, "ablations": [ { "off": "weak flag in the rebuilt validator", "red": 4 }, { "off": "no-ETag (no-store) branch", "red": 1 }, { "off": "bundle read in fetchObjectSchemaFresh", "red": 7 }, { "off": "AppContent loadAppBundle call", "red": 2 }, { "off": "write-door staleness", "red": 1 } ], "line_budget": { "limit": 3000, "used": 955, "additions": 923, "deletions": 32 }, "files_changed": 12, "deviations": [ "Clause-② measured yes (widening), dispatch expected no: loadAppBundle is a new public member of the exported adapter", "withheld vs outside: the bundle names nothing withheld, so an absent name keeps its by-name read (seat and spec seat 1 agreed)", "no-store detected as a 200 with no ETag: the client does not expose Cache-Control", "live boot NOT MEASURED" ], "writes": { "relay": 6, "mcp_calls": 0 } }objectstack-fleet commentedon Oct 31, 2026
domain:ui#2 · os-tesla · session_01L9qibxgfM8p8t3fo6y9eFK
Claim amendment (same console-half claim, same branch
claude/project-thread-xoio4p, PR #28321 head07e67218) · 2026-10-31T10:59ZAppMetadataBundleResponse, replacing the claim'sno: the exported ObjectStack adapter of@object-ui/data-objectstackgains one public member,loadAppBundle(appId: string): Promise<void>; app-shell's declarations add nothing. The PR owes a contract review atTIER_DEFAULT; it carriesneeds:contract-review.Fixes #27627(amendment 6541997127).relay: 6reads 5).objectstack-fleet commentedon Oct 31, 2026
domain:ui#2 · os-tesla · session_01L9qibxgfM8p8t3fo6y9eFK
Landed — console half (PR 3, last part) · 2026-10-31T14:46Z
07e67218(PASS 6542690057, ACCEPT 6542699351), merge commita9f1452192; after producer #28287 (8441a01277)origin/maina9f1452192(git merge-base --is-ancestor)Delivered: entering an app loads its metadata bundle once (conditional on the weak
ETag); a warm record open reads no metadata, a cold one adds one bundle request in the page's first wave. Card closed byFixes;pm:dispatchedremoved. Not owed before landing, recorded per the contract review's boundary flag: one live open on a cloud box when a seat next has one.objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Ruled: keep the Server-Timing gate · 2026-10-31T15:13Z
The maintainer said 「同意」 at 2026-10-31T15:10Z. That was the reply to the consolidated decision list (
decisions/2026-10-31-director-rulings.md, item 8, recommendation 保持), which he accepted in full as recommended. It answers the seat's question of 2026-10-31T02:56Z.Server-Timingkeeps being sent only whenOS_SERVER_TIMING=trueis set, or when an admin caller sendsX-OS-Debug-Timing. It is not opened to every caller. That is the behaviour PR #28320 shipped, so nothing more is owed on this card.