You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
MCP list_objects takes 44 s for an environment owner on hosted (describe_object 1.7 s): close to the common 60 s client timeout #33179
Filing gate: ① a defect with a named producer, measured on staging while reading cloud#4384 row 2 (PR #4415, pin 18.4.0 181ad7d4), on the account owner's approval to run it.
Reader: the MCP area (packages/runtime/src/domains/mcp.ts, the list_objects tool). priority:p2. Triage decides.
Dedupe (open and closed, objectstack): list_objects slow 5 hits, list_objects MCP latency 4, list_objects timeout 4. All are QA-run or seat cards; none is about this tool's latency.
Measured (staging, environment test1016 os-4e4qa4, Team plan, cloud PR #4415 head 153d10ca, objectstack 18.4.0)
Caller. The environment owner, through an MCP client registered by DCR and authorized with PKCE (scope openid offline_access data:read). Bearer token, Streamable HTTP. The environment holds 13 installed or AI-built apps.
initialize 200 and tools/list 200 (9 tools), both fast.
tools/call describe_object {objectName: hcpl_book}: 200 in 1.7 s.
tools/call list_objects {}: 200 in 43.7 s. Two earlier attempts with a 40 s client timeout never received response headers. The Worker logged both as canceled at about 39,980 ms wall time.
For comparison: the same tool called by a plain member's API key in the same environment, minutes earlier, answered within one browser fetch. That member sees far fewer objects (no organization membership at the time). So the cost appears to grow with what the caller can see. I did not time that call.
What to look at
Whether list_objects judges access, or reads field counts, per object, with one or more round trips each. The hosted tenant DB is remote Turso, so each round trip costs tens of ms. That is my inference, not read in code.
A baseline on the previous pin (5b1fe45f) or on main, to tell a regression from an old cost.
Acceptance
list_objects for an owner of an environment of this size answers in a few seconds on hosted.
A test or benchmark pins that its round trips do not grow linearly with the object count.
Claim: PM loop round 13, card thread · 2026-11-14T00:22Z · MCP p2 under the maintainer's 「mcp 相关 p2 任务也可以派发处理」 (2026-11-13T15:50:52Z); filed 2026-11-14T00:11Z, not yet triaged
Session: session_01L9qibzmMRNkjCwvFhzunNc
Account: os-tesla
Branch: claude/project-thread-zezcrr
Worktree: objectstack-issue-33179
Domain: domain:server
Seat: domain:server#7
File surface: packages/runtime/src/domains/mcp.ts (the list_objects read path and its per-caller view); the object masker / posture resolver it calls only for a pure batching seam, named before editing; their tests; one root changeset. Stop on breach.
Container & model: M, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate; PM default), effort: high
Clause-②: no — the same answer for every caller, fewer round trips; an answer change stops the work
Metadata-protocol: none
Responsibility: the per-object cost sits in the MCP bridge's list_objects read (packages/runtime), objectstack | describe_object on the same view answers in 1.7 s | every hosted MCP client of an owner with many objects nears its 60 s timeout today
Thread-read: none
Premise: re-measure — 43.7 s measured on staging by director#1 (hosted, remote DB); the dev counts round trips per object count on a real-layer harness at origin/main first
Serial constraints cleared: runtime/src/domains/mcp.ts is shared with this seat's #32163 (listActions); edits stay on the list_objects read path
Claim amendment to this seat's claim 6868398958 on #33179 · 2026-11-14T00:33Z: the file surface adds, for one pure per-request memo only,
packages/plugins/plugin-security/src/security-plugin.ts: a private memo of the delegator resolution, kept per live context object and keyed and retired exactly like the existing permission-set memo (the write epoch, plus a key of the delegator id, the tenant and the org peer set);
security-plugin-object-admission.ts and security-plugin-field-readers.ts: the two schema-read call sites switch to that memo. They only read the resolved delegator context.
their tests, and @objectstack/plugin-security added to the changeset at patch.
Why: measured at origin/main68972cd (out/33179-measure.md), a caller acting on behalf of a person (the OAuth MCP door) sends 26 more SELECTs for each listed object, 2 security calls × 13 delegator reads. Callers that act for themselves send a constant count. The MCP bridge cannot remove these reads, because the security API answers one object at a time.
Bounds the seat set for this amendment:
Nothing outlives the context object or any write. The other seven delegator call sites are unchanged.
Every answer stays the same for every caller, including the delegated caller. The answer-identity golden covers that caller.
Triage: audit of a pre-labeled card · p2 confirmed · domain:server · 2026-11-14T00:50Z
⛔ Not a claim.
Row: on hosted, list_objects answers in 44 s for an environment owner, close to the common 60 s client timeout (measured on staging). It works today but is slow (p2).
Would regrade to p1: a measured case past a common client timeout. Then the agent is stuck with no remedy at the MCP door (rule 8 raise).
{
"issue": 33179,
"status": "done",
"branch": "claude/project-thread-zezcrr",
"pr": "https://github.com/objectstack-ai/objectstack/pull/33202",
"session": "session_01L9qibzmMRNkjCwvFhzunNc",
"premise_still_valid": true,
"summary": "Measured first at origin/main 68972cd2 on a full kernel: signed-in sessions and API-key-shaped callers list in constant statements, but an OAuth MCP client (ADR-0090 D10 onBehalfOf) pays resolveDelegatorContext twice per object (canReadObject + computeReadableFields), 11 statements each, so list_objects grew 22 statements per object (ownerAgent 1540 -> 4620 statements, 1057 -> 2059 ms at 10 -> 150 app objects). Fix on the seat-agreed plugin-security seam: a private SecurityPlugin.resolveDelegatorForContext memoizes the resolution per live context object on the permissionSetMemo discipline (WeakMap on the context, write epoch + key onBehalfOf.userId/tenantId/org_user_ids; none/missing/resolved all memoized; rejection dropped; resolution frozen), wired only at the two object-schema read sites; delegatedOrganizationRefusal still runs at each. After: 11 statements at both sizes (31/40 ms), describe_object 22 -> 11; every caller answer byte-identical to main. Seat conditions 1-5 met (onBehalfOf contexts only from /mcp per request and REST forward-agent per req; nowMs note and #11971 ruling note in the PR; no open PR on the plugin-security files).",
"tests": "At 04753f4b: new runtime mcp-list-objects-statements.pin.test.ts 19/19 (round-trip pin owner/member/ownerAgent/memberAgent 10 vs 150 within 2; delegated-once pin; answer-identity golden from main; CONTROL describe_object; invalidation pin). pnpm --filter @objectstack/plugin-security test 267 files, 6605 passed 45 skipped, exit 0; pnpm --filter @objectstack/runtime test 598 files, 10620 passed 19 skipped, exit 0; plugin-security + runtime typecheck exit 0. Ablations rebuilt through dist: A (memo hook-up removed) 3 failed (3080 > 2, 2520 > 2, 4620 > 22) with the golden still matching; B (epoch check removed) 1 failed (invalidation: expected 23 < 23); restored 19/19, preflight --absent exit 0. Census pin in delegated-organization-membership.test.ts now counts the memo asks.",
"gates": "dispatch-gates --commands at the merge f8b2d950 (same 70 at 04753f4b): 70 families, stdin closed, exits on disk; --ran: 70 derived, 70 run, 0 NOT-MEASURED. teardown self-test 3 -> 0 after fetching 621a4876; check:i18n and check:dual-build-cjs-loads 3 -> 0 after a full build; check:test-source-alias 1 -> 0 after moving the @objectstack/metadata load to module top. pnpm lint exit 0.",
"timings": "Local in-memory sqlite only; hosted not reachable. Remote figure is an inference: ~22 round trips/object x ~170 objects on a remote database = tens of seconds, matching the 44 s report.",
"dogfood_battery": "n/a: no ! in the PR title and Clause-② is no",
"mcp_calls": "0 (0 writes); GitHub reads via gh api REST",
"api_writes": "2: relay pr_create (#33202, assignee os-tesla, read back 11054/11054 bytes identical) and this os-dev-report comment via post-stamped",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Claim: PM loop round 13, card thread · 2026-11-14T00:22Z · MCP p2 under the maintainer's 「mcp 相关 p2 任务也可以派发处理」 (2026-11-13T15:50:52Z); filed 2026-11-14T00:11Z, not yet triaged
Session:
session_01L9qibzmMRNkjCwvFhzunNcAccount:
os-teslaBranch:
claude/project-thread-zezcrrWorktree:
objectstack-issue-33179Domain:
domain:serverSeat:
domain:server#7File surface:
packages/runtime/src/domains/mcp.ts(thelist_objectsread path and its per-caller view); the object masker / posture resolver it calls only for a pure batching seam, named before editing; their tests; one root changeset. Stop on breach.Container & model:
M,mode:thread,model: default (dispatch-gates --tier: no path-derived mandate; PM default),effort: highClause-②: no — the same answer for every caller, fewer round trips; an answer change stops the work
Metadata-protocol: none
Responsibility: the per-object cost sits in the MCP bridge's
list_objectsread (packages/runtime), objectstack |describe_objecton the same view answers in 1.7 s | every hosted MCP client of an owner with many objects nears its 60 s timeout todayThread-read: none
Premise: re-measure — 43.7 s measured on staging by director#1 (hosted, remote DB); the dev counts round trips per object count on a real-layer harness at
origin/mainfirstSerial constraints cleared:
runtime/src/domains/mcp.tsis shared with this seat's #32163 (listActions); edits stay on thelist_objectsread pathobjectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Claim amendment to this seat's claim 6868398958 on #33179 · 2026-11-14T00:33Z: the file surface adds, for one pure per-request memo only,
packages/plugins/plugin-security/src/security-plugin.ts: a private memo of the delegator resolution, kept per live context object and keyed and retired exactly like the existing permission-set memo (the write epoch, plus a key of the delegator id, the tenant and the org peer set);security-plugin-object-admission.tsandsecurity-plugin-field-readers.ts: the two schema-read call sites switch to that memo. They only read the resolved delegator context.@objectstack/plugin-securityadded to the changeset at patch.Why: measured at
origin/main68972cd (out/33179-measure.md), a caller acting on behalf of a person (the OAuth MCP door) sends 26 more SELECTs for each listed object, 2 security calls × 13 delegator reads. Callers that act for themselves send a constant count. The MCP bridge cannot remove these reads, because the security API answers one object at a time.Bounds the seat set for this amendment:
no.objectstack-fleet commentedon Nov 14, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: audit of a pre-labeled card · p2 confirmed ·
domain:server· 2026-11-14T00:50Z⛔ Not a claim.
list_objectsanswers in 44 s for an environment owner, close to the common 60 s client timeout (measured on staging). It works today but is slow (p2).objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzmMRNkjCwvFhzunNc
os-dev-report
{ "issue": 33179, "status": "done", "branch": "claude/project-thread-zezcrr", "pr": "https://github.com/objectstack-ai/objectstack/pull/33202", "session": "session_01L9qibzmMRNkjCwvFhzunNc", "premise_still_valid": true, "summary": "Measured first at origin/main 68972cd2 on a full kernel: signed-in sessions and API-key-shaped callers list in constant statements, but an OAuth MCP client (ADR-0090 D10 onBehalfOf) pays resolveDelegatorContext twice per object (canReadObject + computeReadableFields), 11 statements each, so list_objects grew 22 statements per object (ownerAgent 1540 -> 4620 statements, 1057 -> 2059 ms at 10 -> 150 app objects). Fix on the seat-agreed plugin-security seam: a private SecurityPlugin.resolveDelegatorForContext memoizes the resolution per live context object on the permissionSetMemo discipline (WeakMap on the context, write epoch + key onBehalfOf.userId/tenantId/org_user_ids; none/missing/resolved all memoized; rejection dropped; resolution frozen), wired only at the two object-schema read sites; delegatedOrganizationRefusal still runs at each. After: 11 statements at both sizes (31/40 ms), describe_object 22 -> 11; every caller answer byte-identical to main. Seat conditions 1-5 met (onBehalfOf contexts only from /mcp per request and REST forward-agent per req; nowMs note and #11971 ruling note in the PR; no open PR on the plugin-security files).", "tests": "At 04753f4b: new runtime mcp-list-objects-statements.pin.test.ts 19/19 (round-trip pin owner/member/ownerAgent/memberAgent 10 vs 150 within 2; delegated-once pin; answer-identity golden from main; CONTROL describe_object; invalidation pin). pnpm --filter @objectstack/plugin-security test 267 files, 6605 passed 45 skipped, exit 0; pnpm --filter @objectstack/runtime test 598 files, 10620 passed 19 skipped, exit 0; plugin-security + runtime typecheck exit 0. Ablations rebuilt through dist: A (memo hook-up removed) 3 failed (3080 > 2, 2520 > 2, 4620 > 22) with the golden still matching; B (epoch check removed) 1 failed (invalidation: expected 23 < 23); restored 19/19, preflight --absent exit 0. Census pin in delegated-organization-membership.test.ts now counts the memo asks.", "gates": "dispatch-gates --commands at the merge f8b2d950 (same 70 at 04753f4b): 70 families, stdin closed, exits on disk; --ran: 70 derived, 70 run, 0 NOT-MEASURED. teardown self-test 3 -> 0 after fetching 621a4876; check:i18n and check:dual-build-cjs-loads 3 -> 0 after a full build; check:test-source-alias 1 -> 0 after moving the @objectstack/metadata load to module top. pnpm lint exit 0.", "timings": "Local in-memory sqlite only; hosted not reachable. Remote figure is an inference: ~22 round trips/object x ~170 objects on a remote database = tens of seconds, matching the 44 s report.", "dogfood_battery": "n/a: no ! in the PR title and Clause-② is no", "mcp_calls": "0 (0 writes); GitHub reads via gh api REST", "api_writes": "2: relay pr_create (#33202, assignee os-tesla, read back 11054/11054 bytes identical) and this os-dev-report comment via post-stamped", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }