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
console: a route whose object read was answered (5xx, or a 404 with an unknown code) says "check your connection" instead of the server's reason #29728
Filing gate: ② out-of-scope finding, class b (read, not yet measured), from #29704. The seat kept it out of that card's claim because the fix runs through appObjectScope.ts, the landing site of seat 2's #29681 and #29552 (claim amendment on #29704). Filed by domain:ui#5. ⛔ Not a claim. No grade: triage sets it.
Business reason. When an app route cannot load its object, the page asks the person to check their network, even though the server answered with a clear reason. That is the same defect #29704 fixes on the list, record and related-list states. The route-level state is the one left.
What happens (by reading at 7b55ea95; measure first)
MetadataProvider marks a by-name object read failed on an answered 5xx, or on a 404 whose code it does not know. The read happened; it was answered.
AppContent's RouteObjectReadFailed (~L2112) then draws the generic sentence "check your connection and try again". The route keeps only the failed names, not the error, so it cannot show the server's code or sentence.
Wanted
The same rule #29704 introduces, through the shared helper it adds to @object-ui/react (utils/error-message.ts). An answered failure shows the server's code and sentence, and the network sentence is only for a request that got no answer. To do that, the by-name read state keeps the error, or at least its status, code and message, beside the failed name.
Tests
Over the real MetadataProvider and route, with a recording adapter:
an answered 503 shows its code and sentence;
a request that got no answer shows the network sentence;
an ablation reds the first.
Serialize after #29704's PR, which adds the helper, and after #29681 and #29552's leg on appObjectScope.ts.
Reserved by domain:ui#2 · 2026-11-03T08:00Z · ⛔ Not yet a claim.
This card was held on purpose, not idle. It is serial after #29681 and #29552 leg 1 on appObjectScope.ts, as its filing says. Both have now landed: PR #29697 as be6b15c7 and PR #29846 as a9322700. #29704's helper (answeredLoadFailure, PR #2978069dbb3cc) is on main too. The seat starts it now. A card thread measures the route's answered-5xx state on current main first, and the Claim: naming its branch follows here.
Claim: PM loop round 12 · 2026-11-03T08:01Z
Session: session_01QsR2jTGjiGTnPZnatdavVb (card thread, os-dev); dispatched by seat session session_01QsR2jRFuJz9QBZqPVHYVhJ
Account: zhuangjianguo
Branch: claude/project-thread-kh01yn (platform-assigned to the card thread; it can push only this branch)
Worktree: objectstack-issue-29728
Domain: domain:ui
Seat: domain:ui#2
File surface: ui/packages/app-shell/src/providers/MetadataProvider.tsx (the by-name read state keeps the answer beside a failed name), ui/packages/app-shell/src/console/appObjectScope.ts (carry it beside the failed names), ui/packages/app-shell/src/console/AppContent.tsx (RouteObjectReadFailed), i18n rows only if #29704's words do not fit, tests, changeset(s). Design report to the seat before code; the seat amends this claim if a published member is added. Stop on breach; explain in the report
Container & model: S, mode:thread, model: default tier (dispatch-gates --tier on the final file list), effort: high
Clause-②: no (provisional: @object-ui/app-shell is private; a new @object-ui/react export makes it yes (widening), amended before code)
Metadata-protocol: none
Responsibility: the route's by-name object read keeps only the failed names, not the answer | an answered 5xx or unknown-code 404 on an app route draws "check your connection" instead of the server's code and sentence | people opening an app route while the server refuses the object read
Thread-read: none
Premise: the filing's reading at 7b55ea95, to be re-measured on current main in step 1; answeredLoadFailure (@object-ui/reactutils/error-message.ts) is on main via PR #2978069dbb3cc.
Serial constraints cleared: #29552 leg 1 (PR #29697be6b15c7) and #29681 (PR #29846a9322700) landed on appObjectScope.ts; #29704 (PR #29780) landed. The os-dev checks open PRs touching these three files and merges main before pr_create
Claim amendment (to 6598456131) · 2026-11-03T08:16Z · on the os-dev's step 1 measure; session, branch and seat unchanged.
Clause-②: no
Metadata-protocol: none
Premise corrected (measured on main99c06965, real ObjectStackAdapter under the real provider and route): an answered 503, an answered 500, an unknown-code 404, a network drop and a 403 all draw "Check your connection". The provider never sees the server's answer: getObjectSchema's non-404 catch rewraps it through createErrorFromResponse and keeps no reference. A 503 becomes CONNECTION_ERROR, a 500 becomes UNKNOWN_ERROR, and a network drop gets an invented status 500, so it would read as answered. The RESOURCE_NOT_FOUND and OBJECT_PACKAGE_DISABLED states are correct today and stay as they are.
File surface (added):ui/packages/data-objectstack/src/index.ts, only getObjectSchema's non-404 catch. The wrapped error carries details.originalError, as the 404 path and three other wrap sites already do. The wrapper's class, code, statusCode and message are unchanged. createErrorFromResponse (exported) keeps its signature. There is one test beside it and a @object-ui/data-objectstack patch changeset.
Clause-② stays no: no export, type or signature changes. details is already Record<string, unknown>, and originalError is the key the package's other wrap sites set.
Design ruled: the provider unwraps details.originalError for any ObjectStackError, and its verdicts are unchanged. Per name, the scope keeps answeredLoadFailure(err), except for forbidden or unauthorized, where a 403 keeps today's state. appObjectScope carries the first failed name's answer, and RouteObjectReadFailed draws the server's sentence and a code chip in PageView's shape. A no-answer read keeps the network sentence. No i18n rows are added, and retry is unchanged.
{
"issue": 29728,
"status": "done",
"branch": "claude/project-thread-kh01yn",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29883",
"head": "effe42c8",
"session": "session_01QsR2jTGjiGTnPZnatdavVb",
"premise_still_valid": true,
"premise_correction": "Step 1 on main 99c06965, real ObjectStackAdapter under real MetadataProvider + AppContent. The provider never saw the server answer: getObjectSchema's non-404 catch rewrapped it via createErrorFromResponse (503 -> CONNECTION_ERROR, 500 -> UNKNOWN_ERROR, network drop -> invented status 500). Surface amended by the seat (claim amendment 6598716684) to add data-objectstack's getObjectSchema catch.",
"summary": "getObjectSchema's non-404 rewrap now keeps the transport error as details.originalError (class/code/statusCode/message unchanged). MetadataProvider unwraps it for any ObjectStackError and stores answeredLoadFailure(err) per failed name (none for forbidden/unauthorized). appObjectScope carries failedAnswer on the object, page and dashboard paths, and RouteObjectReadFailed draws the server sentence plus a code chip. The network sentence is kept only for a read with no answer. Retry is unchanged and no i18n rows were added.",
"tests": "New: AppContent.disabledPackageDeepLink-13052.test.tsx top-level describe over the REAL adapter (9 pins: 503/500/unknown-404 answered, page-route 503, network/403/RESOURCE_NOT_FOUND/OBJECT_PACKAGE_DISABLED controls, two Retry pins); file 18/18 green. getObjectSchema.test.ts new describe (4 pins: 503, 500, network, 404 control), 8/8. Ablations at committed head 2a886b17 via ablation-replace.mjs (restored blob == HEAD): drop provider unwrap -> 5/9 red (unknown-404 stays green: 404 still unwrapped); drop answers record -> 6/9 red. Related sweep: 301 app-shell test files in 6 batches, all green; data-objectstack 114/114 files green. turbo type-check app-shell + data-objectstack 66/66. eslint on 6 touched files: 0 errors.",
"gates": "dispatch-gates --commands at ff352f41: 36 derived, 36 run, all exit 0; --ran reconciled 36/36, 0 NOT-MEASURED. Includes check-sdui-manifest (exit 0), pnpm --dir ui exec vitest run scripts/ (exit 0, locked), check:type-check-debt (exit 0, locked). PR-body gates (closing-keyword-parity, adr-0087-registration, changeset-no-major) exit 0 on the final body. --tier: no path-derived mandate. effe42c8 adds only a merge of one unrelated main commit (cloud-connection). CI check-runs: in_progress at report time.",
"line_budget": "417 changed lines at ff352f41 (+391/-26, 7 files) vs 3000 threshold: under",
"files_changed": [
".changeset/29728-route-object-read-answer.md",
"ui/packages/data-objectstack/src/index.ts",
"ui/packages/data-objectstack/src/getObjectSchema.test.ts",
"ui/packages/app-shell/src/providers/MetadataProvider.tsx",
"ui/packages/app-shell/src/console/appObjectScope.ts",
"ui/packages/app-shell/src/console/AppContent.tsx",
"ui/packages/app-shell/src/console/__tests__/AppContent.disabledPackageDeepLink-13052.test.tsx"
],
"deviations": [
"Surface amended before code (data-objectstack getObjectSchema catch + its test), by seat claim amendment 6598716684.",
"withoutRefusal in MetadataProvider generalised and renamed to withoutName<T> (it now also clears answers): 3 call sites, same file.",
"Verdict edge: with the unwrap, a non-404 status carrying RESOURCE_NOT_FOUND / OBJECT_PACKAGE_DISABLED is now read by its code (absence/refusal) rather than as a failure; no known server path answers that way. Noted in the PR's acceptance notes.",
"failedAnswer is the first failed name that carries an answer (as in the design), not strictly the first failed name."
],
"dogfood_battery": "n/a - no ! in the PR title and no (narrowing) arm",
"mcp_calls": "5 - reads only: issue_read get x1, issue_read get_comments x2, pull_request_read get_files x2 (open-PR overlap check on #29861 and #29842: no overlap)",
"api_writes": "pr_create x1 via fleet-write relay (run 41611658890, body read back byte-identical, no assignees); this report comment x1 via post-stamped; git push x5 to claude/project-thread-kh01yn",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"class: a · reach: public door - a getObjectSchema read that gets no answer (network drop) throws ObjectStackError statusCode 500, so any caller grading the wrapper by status reads it as an answered 500 · evidence: createErrorFromResponse (ui/packages/data-objectstack/src/errors.ts) defaults status to 500 when the error has none; measured: TypeError Failed to fetch -> UNKNOWN_ERROR statusCode 500; its one in-tree caller is getObjectSchema, read by 43 source files / 58 call sites under ui/ (createErrorFromResponse is also exported) · dedupe words: createErrorFromResponse 500, getObjectSchema network drop status, Failed to fetch UNKNOWN_ERROR · carrier: seat files it"
]
}
Landed · 2026-11-03T10:13Z · PR #29883 merged through the queue as aad5ee0f. The merge commit carries all 7 files of the accepted head effe42c8 (+391/−26).
Delivered in full: when the server answers an app route's object read with a 5xx, or with a 404 carrying an unknown code, the route now shows the server's sentence and its code. "Check your connection" is drawn only when no server answered. A 403, not-found and package-disabled keep their states. getObjectSchema keeps the transport error as details.originalError.
The root cause in createErrorFromResponse (status-less error → 500) is filed as #29885. The card closed by Fixes; pm:dispatched is removed with this note.
Activity
objectstack-fleet commentedon Nov 3, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p2 ·
domain:uikept ·pm:triage→pm:queue· 2026-11-03T03:55Z⛔ Not a claim.
appObjectScope.tsafter console: a packaged app's record route with no declared record page downloads the whole object registry (553 KB) #29681 and Console: a console-created (package-less) app's record route reads the whole /meta/page list, and its root the whole object registry #29552.Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:ui#2 · zhuangjianguo · session_01QsR2jRFuJz9QBZqPVHYVhJ
Reserved by
domain:ui#2· 2026-11-03T08:00Z · ⛔ Not yet a claim.This card was held on purpose, not idle. It is serial after #29681 and #29552 leg 1 on
appObjectScope.ts, as its filing says. Both have now landed: PR #29697 asbe6b15c7and PR #29846 asa9322700. #29704's helper (answeredLoadFailure, PR #2978069dbb3cc) is on main too. The seat starts it now. A card thread measures the route's answered-5xx state on current main first, and theClaim:naming its branch follows here.objectstack-fleet commentedon Nov 3, 2026
domain:ui#2 · zhuangjianguo · session_01QsR2jRFuJz9QBZqPVHYVhJ
Claim: PM loop round 12 · 2026-11-03T08:01Z
Session:
session_01QsR2jTGjiGTnPZnatdavVb(card thread, os-dev); dispatched by seat sessionsession_01QsR2jRFuJz9QBZqPVHYVhJAccount:
zhuangjianguoBranch:
claude/project-thread-kh01yn(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-29728Domain:
domain:uiSeat:
domain:ui#2File surface:
ui/packages/app-shell/src/providers/MetadataProvider.tsx(the by-name read state keeps the answer beside a failed name),ui/packages/app-shell/src/console/appObjectScope.ts(carry it beside the failed names),ui/packages/app-shell/src/console/AppContent.tsx(RouteObjectReadFailed), i18n rows only if #29704's words do not fit, tests, changeset(s). Design report to the seat before code; the seat amends this claim if a published member is added. Stop on breach; explain in the reportContainer & model: S,
mode:thread,model: default tier (dispatch-gates --tier on the final file list),effort: highClause-②: no (provisional:
@object-ui/app-shellis private; a new@object-ui/reactexport makes it yes (widening), amended before code)Metadata-protocol: none
Responsibility:
the route's by-name object read keeps only the failed names, not the answer | an answered 5xx or unknown-code 404 on an app route draws "check your connection" instead of the server's code and sentence | people opening an app route while the server refuses the object readThread-read: none
Premise: the filing's reading at
7b55ea95, to be re-measured on currentmainin step 1;answeredLoadFailure(@object-ui/reactutils/error-message.ts) is on main via PR #2978069dbb3cc.Serial constraints cleared: #29552 leg 1 (PR #29697
be6b15c7) and #29681 (PR #29846a9322700) landed onappObjectScope.ts; #29704 (PR #29780) landed. The os-dev checks open PRs touching these three files and mergesmainbeforepr_createobjectstack-fleet commentedon Nov 3, 2026
domain:ui#2 · zhuangjianguo · session_01QsR2jRFuJz9QBZqPVHYVhJ
Claim amendment (to 6598456131) · 2026-11-03T08:16Z · on the os-dev's step 1 measure; session, branch and seat unchanged.
Clause-②: no
Metadata-protocol: none
main99c06965, realObjectStackAdapterunder the real provider and route): an answered 503, an answered 500, an unknown-code 404, a network drop and a 403 all draw "Check your connection". The provider never sees the server's answer:getObjectSchema's non-404 catch rewraps it throughcreateErrorFromResponseand keeps no reference. A 503 becomesCONNECTION_ERROR, a 500 becomesUNKNOWN_ERROR, and a network drop gets an invented status 500, so it would read as answered. TheRESOURCE_NOT_FOUNDandOBJECT_PACKAGE_DISABLEDstates are correct today and stay as they are.ui/packages/data-objectstack/src/index.ts, onlygetObjectSchema's non-404 catch. The wrapped error carriesdetails.originalError, as the 404 path and three other wrap sites already do. The wrapper's class, code, statusCode and message are unchanged.createErrorFromResponse(exported) keeps its signature. There is one test beside it and a@object-ui/data-objectstackpatch changeset.detailsis alreadyRecord<string, unknown>, andoriginalErroris the key the package's other wrap sites set.details.originalErrorfor anyObjectStackError, and its verdicts are unchanged. Per name, the scope keepsansweredLoadFailure(err), except for forbidden or unauthorized, where a 403 keeps today's state.appObjectScopecarries the first failed name's answer, andRouteObjectReadFaileddraws the server's sentence and a code chip in PageView's shape. A no-answer read keeps the network sentence. No i18n rows are added, and retry is unchanged.objectstack-fleet commentedon Nov 3, 2026
domain:ui#2 · zhuangjianguo · session_01QsR2jTGjiGTnPZnatdavVb
os-dev-report
{ "issue": 29728, "status": "done", "branch": "claude/project-thread-kh01yn", "pr": "https://github.com/objectstack-ai/objectstack/pull/29883", "head": "effe42c8", "session": "session_01QsR2jTGjiGTnPZnatdavVb", "premise_still_valid": true, "premise_correction": "Step 1 on main 99c06965, real ObjectStackAdapter under real MetadataProvider + AppContent. The provider never saw the server answer: getObjectSchema's non-404 catch rewrapped it via createErrorFromResponse (503 -> CONNECTION_ERROR, 500 -> UNKNOWN_ERROR, network drop -> invented status 500). Surface amended by the seat (claim amendment 6598716684) to add data-objectstack's getObjectSchema catch.", "summary": "getObjectSchema's non-404 rewrap now keeps the transport error as details.originalError (class/code/statusCode/message unchanged). MetadataProvider unwraps it for any ObjectStackError and stores answeredLoadFailure(err) per failed name (none for forbidden/unauthorized). appObjectScope carries failedAnswer on the object, page and dashboard paths, and RouteObjectReadFailed draws the server sentence plus a code chip. The network sentence is kept only for a read with no answer. Retry is unchanged and no i18n rows were added.", "tests": "New: AppContent.disabledPackageDeepLink-13052.test.tsx top-level describe over the REAL adapter (9 pins: 503/500/unknown-404 answered, page-route 503, network/403/RESOURCE_NOT_FOUND/OBJECT_PACKAGE_DISABLED controls, two Retry pins); file 18/18 green. getObjectSchema.test.ts new describe (4 pins: 503, 500, network, 404 control), 8/8. Ablations at committed head 2a886b17 via ablation-replace.mjs (restored blob == HEAD): drop provider unwrap -> 5/9 red (unknown-404 stays green: 404 still unwrapped); drop answers record -> 6/9 red. Related sweep: 301 app-shell test files in 6 batches, all green; data-objectstack 114/114 files green. turbo type-check app-shell + data-objectstack 66/66. eslint on 6 touched files: 0 errors.", "gates": "dispatch-gates --commands at ff352f41: 36 derived, 36 run, all exit 0; --ran reconciled 36/36, 0 NOT-MEASURED. Includes check-sdui-manifest (exit 0), pnpm --dir ui exec vitest run scripts/ (exit 0, locked), check:type-check-debt (exit 0, locked). PR-body gates (closing-keyword-parity, adr-0087-registration, changeset-no-major) exit 0 on the final body. --tier: no path-derived mandate. effe42c8 adds only a merge of one unrelated main commit (cloud-connection). CI check-runs: in_progress at report time.", "line_budget": "417 changed lines at ff352f41 (+391/-26, 7 files) vs 3000 threshold: under", "files_changed": [ ".changeset/29728-route-object-read-answer.md", "ui/packages/data-objectstack/src/index.ts", "ui/packages/data-objectstack/src/getObjectSchema.test.ts", "ui/packages/app-shell/src/providers/MetadataProvider.tsx", "ui/packages/app-shell/src/console/appObjectScope.ts", "ui/packages/app-shell/src/console/AppContent.tsx", "ui/packages/app-shell/src/console/__tests__/AppContent.disabledPackageDeepLink-13052.test.tsx" ], "deviations": [ "Surface amended before code (data-objectstack getObjectSchema catch + its test), by seat claim amendment 6598716684.", "withoutRefusal in MetadataProvider generalised and renamed to withoutName<T> (it now also clears answers): 3 call sites, same file.", "Verdict edge: with the unwrap, a non-404 status carrying RESOURCE_NOT_FOUND / OBJECT_PACKAGE_DISABLED is now read by its code (absence/refusal) rather than as a failure; no known server path answers that way. Noted in the PR's acceptance notes.", "failedAnswer is the first failed name that carries an answer (as in the design), not strictly the first failed name." ], "dogfood_battery": "n/a - no ! in the PR title and no (narrowing) arm", "mcp_calls": "5 - reads only: issue_read get x1, issue_read get_comments x2, pull_request_read get_files x2 (open-PR overlap check on #29861 and #29842: no overlap)", "api_writes": "pr_create x1 via fleet-write relay (run 41611658890, body read back byte-identical, no assignees); this report comment x1 via post-stamped; git push x5 to claude/project-thread-kh01yn", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "class: a · reach: public door - a getObjectSchema read that gets no answer (network drop) throws ObjectStackError statusCode 500, so any caller grading the wrapper by status reads it as an answered 500 · evidence: createErrorFromResponse (ui/packages/data-objectstack/src/errors.ts) defaults status to 500 when the error has none; measured: TypeError Failed to fetch -> UNKNOWN_ERROR statusCode 500; its one in-tree caller is getObjectSchema, read by 43 source files / 58 call sites under ui/ (createErrorFromResponse is also exported) · dedupe words: createErrorFromResponse 500, getObjectSchema network drop status, Failed to fetch UNKNOWN_ERROR · carrier: seat files it" ] }objectstack-fleet commentedon Nov 3, 2026
domain:ui#2 · zhuangjianguo · session_01QsR2jRFuJz9QBZqPVHYVhJ
Landed · 2026-11-03T10:13Z · PR #29883 merged through the queue as
aad5ee0f. The merge commit carries all 7 files of the accepted headeffe42c8(+391/−26).Delivered in full: when the server answers an app route's object read with a 5xx, or with a 404 carrying an unknown code, the route now shows the server's sentence and its code. "Check your connection" is drawn only when no server answered. A 403, not-found and package-disabled keep their states.
getObjectSchemakeeps the transport error asdetails.originalError.The root cause in
createErrorFromResponse(status-less error → 500) is filed as #29885. The card closed byFixes;pm:dispatchedis removed with this note.