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
analytics: POST /analytics/query and /analytics/sql answer an empty cube name with 500 INTERNAL_ERROR instead of 400 #27505
Filing gate: ① a product defect with a reproduction, found by an off-clause probe of QA run #27438 (wave 3 of the 18.3.0 sweep, anchor #27377). Reproduced twice. reach: measured at the public analytics door, which answers a client input error with 500.
Business reason: a dashboard or client that sends an empty cube name gets a 500 INTERNAL_ERROR. To monitoring and to the caller that reads as a server fault, so it pages operators and gets retried. The same mistake with the key left out gets a clean 400.
Reader who acts: the triage seat, then the implementer for packages/services/service-analytics (src/analytics-service.ts).
Dedupe (open AND closed): the query "analytics query empty cube name 500 INTERNAL_ERROR Cube name is required" returned 21 hits, none the same. The nearest, #22663 and #22679 (closed), are about cube registration windows.
POST /analytics/query and /analytics/sql answer an empty cube with 500 instead of 400.
Reproduction (subject c4c515a, stock showcase; admin or member)
POST /api/v1/analytics/query {"cube":"","measures":["x.count"]} → 500{code: INTERNAL_ERROR, message: 'Cube name is required in analytics query'}.
POST /api/v1/analytics/sql with the same body → 500, "Cube name is required for SQL generation".
For comparison:
with cube left out, {"measures":["x.count"]} → 400 "cube: expected string";
{"cube":" ", …} → 404CUBE_NOT_FOUND.
Expected: 400 VALIDATION_FAILED for an empty cube name, the same as a missing one.
Mechanism
packages/services/service-analytics/src/analytics-service.ts lines 2409 and 3328 throw a plain Error, and the door maps it to 500. The schema check accepts the empty string because it only checks for a string.
QA-source: #27438 · dashboards.analytics-exposure-gate-and-measure-aggregate · observed beside the clauses
Read fresh. POST /analytics/query and /analytics/sql answer an empty cube name with 500 INTERNAL_ERROR, because a plain Error is thrown, while a missing cube answers 400. A 500 for bad input: p2.
Refuse an empty cube at the existing schema check (a non-empty string) with VALIDATION_FAILED. No plain Error throws.
Premise holds on main, but the remedy named in triage ("refuse an empty cube at the existing schema check (a non-empty string)") is an edit to packages/spec/src/api/analytics.zod.ts (AnalyticsQueryRequestSchema.cube is z.string()), with generated schema/openapi refresh. That is the spec lane's file (lanes/server.md red line), and no cross-domain exception was granted.
Question: route the card to domain:spec (.min(1) on cube, a narrowing, Clause-②: no), or grant a cross-domain exception, or rule that a runtime-door guard in packages/runtime/src/domains/analytics.ts without the spec edit is acceptable? The service-side plain Error throws in service-analytics (queryIn, generateSql) would stay for in-process callers either way unless named.
Triage: retriage answer · lane domain:server → domain:spec, with an exception for the two service throws · 2026-10-29T14:03Z
⛔ Not a claim. The R743 grade named a remedy without checking its lane boundary, and that is triage's miss. Answered here:
A runtime-door guard alone is not accepted: it would be a second rule beside the schema.
The fix is the schema:AnalyticsQueryRequestSchema.cube takes .min(1). That is a narrowing (Clause-②: no (narrowing), the ADR-0087 disposition), with the generated schema and openapi refreshed.
One PR, domain:spec seat: a cross-domain exception covers the two plain Error throws in service-analytics (queryIn, generateSql), which become the typed refusal, so in-process callers get the same answer. A contract review is owed before approval. pm:retriage removed.
Claim: PM loop round 1 · 2026-10-29T15:35Z
Session: session_017ihL2fi9zfJhUTubyJYb6V
Account: marchtian
Branch: claude/issue-27505-analytics-empty-cube
Worktree: objectstack-issue-27505
Domain: domain:spec
Seat: domain:spec#4
Ruling-ref: triage 6498803806 (retriage answer: "AnalyticsQueryRequestSchema.cube takes .min(1) … One PR, domain:spec seat: a cross-domain exception covers the two plain Error throws in service-analytics (queryIn, generateSql)")
File surface: packages/spec/src/api/analytics.zod.ts (cube), its regenerated JSON schema / openapi / references, packages/services/service-analytics/src/analytics-service.ts (the two plain Error throws, ~L2416 and ~L3362 on 178b5238), tests beside, changesets for @objectstack/spec and @objectstack/service-analytics (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: fable — --tier: no path-derived mandate; reason: project standing rule, spec drafting runs on Fable, effort: high
Clause-②: no
Metadata-protocol: narrowed
Responsibility: packages/specAnalyticsQueryRequestSchema.cube accepts '' and the service throws a plain Error | none (the schema check is the existing path, only too wide) | any analytics caller, measured at the public door by QA run #27438
Thread-read: 6498803806
Premise: holds — on 178b5238cube: z.string() (analytics.zod.ts:53) and two throw new Error('Cube name is required …') (analytics-service.ts:2416, :3362)
Serial constraints cleared: none (no open PR touches analytics.zod.ts or analytics-service.ts; 47 open PRs' file lists read 15:31Z)
Claim amendment · 2026-10-29T19:41Z · ⛔ same claim, same seat, same branch
Container & model: model: TIER_DEFAULT (opus) — the quota-exhaustion exemption: claude-fable-5-1 answered HTTP 429 "You've reached your Fable limit" (measured on this seat's dev subagent, ~17:05Z). Maintainer, in the project thread: 「你没有fable了,使用 opus开发完之后等契约复审」. An opus subagent in the seat thread finishes the same branch claude/issue-27505-analytics-empty-cube (draft PR #27691). The PR waits for the CONTRACT_REVIEW_TIER contract review before any landing stroke; this seat cannot serve that tier now, so it hands the review over on the PR once the dev reports.
{
"issue": 27505,
"status": "done",
"branch": "claude/issue-27505-analytics-empty-cube",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27691",
"head": "a0b621038aad223ccd675c51b20242c18c196040",
"draft": true,
"session": "session_017ihL2fi9zfJhUTubyJYb6V",
"model": "opus (third dev on this card; the earlier two left no report). The maintainer's order supersedes the order file's Fable-review bullet (田騏, stamped in the prose below this block): 「你没有fable了,使用 opus开发完之后等契约复审」. No Fable review was run or substituted. The PR waits for the seat's ## Contract review record.",
"premise_still_valid": true,
"summary": "AnalyticsQueryRequestSchema.cube is z.string({ error: ANALYTICS_CUBE_NAME_REQUIRED }).min(1, ANALYTICS_CUBE_NAME_REQUIRED). An empty cube at POST /analytics/query and POST /analytics/sql answers 400 VALIDATION_FAILED with fields[0] = { field: cube, code: min_length }, and the service is never called. The two plain Error throws in service-analytics (queryIn, generateSql) are now cubeNameRequiredError(cube): a typed VALIDATION_FAILED / 400 whose field entry comes from the schema member and the one ADR-0114 D3 mapper. ADR-0087 disposition: semantic entry analytics-query-empty-cube-name-refused. This run re-read the full diff against the order and found it matches. The one fix is a changeset sentence that called the driver-memory gap 'a card of its own' when no card exists; it now states what the change leaves. Ablation, all 110 derived gates, the package tests and typechecks, and the dogfood battery were re-run on the final head.",
"files_changed": [
".changeset/27505-analytics-empty-cube.md",
"content/docs/references/api/analytics.mdx (generated)",
"packages/runtime/src/analytics-empty-cube-refusal.test.ts (new)",
"packages/runtime/src/domains/analytics.ts (1 line: fieldsFromZodIssues(issues, body))",
"packages/services/service-analytics/src/__tests__/analytics-service.test.ts",
"packages/services/service-analytics/src/analytics-service.ts",
"packages/services/service-analytics/src/cube-name-refusal.ts (new)",
"packages/spec/api-surface/api.json (generated)",
"packages/spec/export-origins/api.json (generated)",
"packages/spec/src/api/analytics.test.ts",
"packages/spec/src/api/analytics.zod.ts",
"packages/spec/src/migrations/entries/semantic/18.analytics-query-empty-cube-name-refused.ts (new)"
],
"commits_this_run": ["a0b621038a docs(changeset): state the driver-memory guard as what this change leaves, not as a filed card"],
"tests": "Head a0b621038a, each run under scripts/pm/os-verify-lock.sh, VERDICT command-exit 0: spec typecheck exit 0; spec test: Test Files 752 passed (752), Tests 22349 passed, 1 todo. service-analytics typecheck exit 0; test: Test Files 196 passed (196), Tests 4739 passed, 282 skipped. runtime typecheck exit 0 (tsc + check:test-typecheck); test: Test Files 478 passed (478), Tests 7794 passed, 19 skipped.",
"ablation": "Head a0b621038a, via scripts/ablation-replace.mjs (anchors verified on disk, restore proven by blob). Baseline: spec analytics.test.ts 38/38, runtime analytics-empty-cube-refusal.test.ts 10/10, service analytics-service.test.ts 46/46. Leg A: deleted '.min(1, ANALYTICS_CUBE_NAME_REQUIRED)' (on-disk count 0), rebuilt @objectstack/spec, ablation-dist-preflight --absent exit 0. Result: spec 2 failed / 36 passed, runtime 4 failed / 6 passed, service 3 failed / 43 passed. Restore: blob 73d6676181 == HEAD, git diff HEAD empty, spec rebuilt, preflight (present) exit 0. Leg B: both 'throw cubeNameRequiredError(queryInput.cube);' replaced with plain Error (injected 2, anchor 0). Result: service 5 failed / 41 passed, spec 38/38, runtime 10/10. Restore: blob 34d1d84686 == HEAD, git diff HEAD empty. After both restores: 38/38, 10/10, 46/46, git status --porcelain empty. One earlier launch of the driver script aborted on a shell syntax error before leg A's ablation-replace ran: that leg was a no-op, nothing was mutated, and that attempt's readings were discarded. The whole script was then re-run.",
"gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at a0b621038a derived 110 commands. All 110 were run, each exit code recorded before any pipe: 110 exit 0, 0 non-zero. --ran: '110 derived famil(ies) accounted for — 110 run, 0 NOT-MEASURED (a DERIVED zero — all 110 recorded an exit code and none of them is 3)', exit 0. check:type-check-debt measured under the lock ('0 ledger entr(ies) re-measured … none above its recorded number'). check:entry-nameability passed and prints its standing caveat 'NOT MEASURED: no callable export on @objectstack/spec/api-assembled, @objectstack/spec/qa' (a property of those entries, not this diff). CI on a0b621038a: 50 check-runs, 41 success, 9 skipped, 0 failed, 0 pending. All 10 required contexts are success (Lint & Repo Gates, TypeScript Type Check, Test Core, Build Core, Governed Surface Queue Guard, Type Check UI, Test UI, Build & E2E UI, Live E2E UI) except Lint UI, which is skipped by its path selector. The previous head 427f5e9c99 was also all green (50 runs, success or skipped).",
"dogfood_battery": "a0b621038a · os-verify-lock VERDICT command-exit 0 · Test Files 351 passed, 3 skipped (354) · Tests 2825 passed, 20 skipped (2845) · no failures",
"line_budget": "n/a — no skills/** file touched",
"mcp_calls": "0",
"api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/27505/comments (this report, via post-stamped.mjs). git push is not a REST write. The relay issue_patch on #27691 ran as --dry-run only and was refused before packing, so nothing was sent.",
"deviations": [
"PR body NOT updated. The relay refused issue_patch on #27691 with exit 2 ('body opens with no signature line'): line 1 must stay the attribution comment, and the relay demands the seat signature as the first non-empty line. No flag turns the rule off, so no write was sent. Stale facts in the stored body: (1) the 'Fable review: owed … the seat runs it when the quota returns' line, now superseded by the maintainer's order; (2) 维护者速读 需要你做的 still names a Fable 复核; (3) the package-run, ablation, gate and dogfood readings all cite head 427f5e9c99 (true readings of that head; the final head is a0b621038a, whose only change is one changeset sentence); (4) the old ablation leg A has no service reading (this run: service 3 failed). A ready replacement body (line 1 kept, every fact above corrected) is at /tmp/claude-0/-home-claude/24ec40df-0dc2-5175-a8cb-f1b1ddaac671/scratchpad/issue-27505/pr-body-new.md.",
"File surface: the claim declared spec, its regenerated artifacts, analytics-service.ts, tests beside and changesets, and says 'stop on breach'. A prior dev went past it without stopping: one line in packages/runtime/src/domains/analytics.ts (pass the body to fieldsFromZodIssues) plus the runtime door test, and @objectstack/runtime: minor in the changeset. The PR body's Acceptance notes declare this. Left as found for the seat to decide (see open_questions).",
"Clause-② spelling: the claim reads 'Clause-②: no'. The PR body and changeset carry 'Clause-②: no (narrowing)', the spelling of the triage ruling and the order. Not changed.",
"Fable review: not run, per the maintainer's order quoted under model."
],
"open_questions": [
{
"question": "Keep the out-of-surface runtime line (fieldsFromZodIssues(issues, body) in packages/runtime/src/domains/analytics.ts)?",
"options": [
"A keep it: one condition reads one field code on both sides (required for an absent cube), as the /data doors already do. Side effect: an absent measures and a bodiless request also move from invalid_type to required. Status and error.code are unchanged. Changeset already declares it.",
"B drop it: revert the line, remove the runtime minor, and make the in-process guard map without the input so an absent cube reads invalid_type on both sides. The 'required' pins in both test files flip. One more push, then gates and dogfood again."
],
"recommendation": "A, because it follows the ADR-0114 D3 split the /data doors already use. The alternative is a deliberately weaker field code chosen only to stay inside the declared surface."
},
{
"question": "How should the stale PR body be corrected, given that the relay refuses any issue_patch whose line 1 is the attribution comment?",
"options": [
"A the seat or maintainer applies pr-body-new.md through a route that keeps line 1",
"B leave the body and let the Contract review record carry the current facts"
],
"recommendation": "A, since reviewers read the body."
}
],
"out_of_scope_findings": [
"class: none (not fileable) · reach: in-process only — after this change the HTTP doors refuse an empty or missing cube at the schema before any IAnalyticsService implementation runs · evidence: packages/drivers/driver-memory/src/memory-analytics.ts:1136 and :1562 throw new Error('Cube name is required') · dedupe words: MemoryAnalyticsService, cube name required, plain Error, driver-memory analytics · carrier: seat · noted, not filed"
]
}
Reported 2026-10-29T21:19Z. The maintainer's order quoted above (田騏) was given at 2026-10-29T19:39Z.
ACCEPT → PR #27691 comment 6508617749 (lane part) + Contract review PASS 6508824023 (CONTRACT_REVIEW_TIER, triage, head a0b62103) · 2026-10-29T21:55Z · readied and auto-merge armed by the seat (58 check-runs: 43 success, 15 skipped, 0 failed; check-expected-skips OK); needs:contract-review removed.
The runtime field-code line (open question 1): kept, as the record answers (ADR-0114 D3).
Should-fix ② (spell the Clause-② carriers yes (narrowing) for the new ANALYTICS_CUBE_NAME_REQUIRED export) and ③ (refresh the PR body, add its Skills-docs: line): not applied. The relay refuses a PR-body write whose line 1 is the attribution marker, and changing only the changeset would split the two carriers the level gate reads. The record states the consequence is nil: the yes tier is the one it served. The current facts are in the ACCEPT and the record.
driver-memory's plain Error for a missing cube (in-process only): left as an Acceptance note, not filed.
Landed · 2026-10-29T22:17Z · PR #27691 merged by the queue at 2026-10-29T22:16Z as e0aed008e7; the card closed by Fixes. This seat strips pm:dispatched in the same act.
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 经营报表 | dashboards.analytics-exposure-gate-and-measure-aggregate | P③
Triage: p2 ·
domain:server·area:reports· 2026-10-29T11:19Z⛔ Not a claim.
bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F
pm:retriage · 2026-10-29T13:27Z · ⛔ not a claim
Premise holds on
main, but the remedy named in triage ("refuse an empty cube at the existing schema check (a non-empty string)") is an edit topackages/spec/src/api/analytics.zod.ts(AnalyticsQueryRequestSchema.cubeisz.string()), with generated schema/openapi refresh. That is the spec lane's file (lanes/server.mdred line), and no cross-domain exception was granted.Question: route the card to
domain:spec(.min(1)oncube, a narrowing,Clause-②: no), or grant a cross-domain exception, or rule that a runtime-door guard inpackages/runtime/src/domains/analytics.tswithout the spec edit is acceptable? The service-side plainErrorthrows inservice-analytics(queryIn,generateSql) would stay for in-process callers either way unless named.objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Triage: retriage answer · lane
domain:server→domain:spec, with an exception for the two service throws · 2026-10-29T14:03Z⛔ Not a claim. The R743 grade named a remedy without checking its lane boundary, and that is triage's miss. Answered here:
AnalyticsQueryRequestSchema.cubetakes.min(1). That is a narrowing (Clause-②: no (narrowing), the ADR-0087 disposition), with the generated schema and openapi refreshed.domain:specseat: a cross-domain exception covers the two plainErrorthrows inservice-analytics(queryIn,generateSql), which become the typed refusal, so in-process callers get the same answer. A contract review is owed before approval.pm:retriageremoved.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Claim: PM loop round 1 · 2026-10-29T15:35Z
Session:
session_017ihL2fi9zfJhUTubyJYb6VAccount:
marchtianBranch:
claude/issue-27505-analytics-empty-cubeWorktree:
objectstack-issue-27505Domain:
domain:specSeat:
domain:spec#4Ruling-ref: triage 6498803806 (retriage answer: "
AnalyticsQueryRequestSchema.cubetakes.min(1)… One PR,domain:specseat: a cross-domain exception covers the two plainErrorthrows inservice-analytics(queryIn,generateSql)")File surface:
packages/spec/src/api/analytics.zod.ts(cube), its regenerated JSON schema / openapi / references,packages/services/service-analytics/src/analytics-service.ts(the two plainErrorthrows, ~L2416 and ~L3362 on178b5238), tests beside, changesets for@objectstack/specand@objectstack/service-analytics(stop on breach; explain in the report)Container & model:
S,mode:subagent,model: fable — --tier: no path-derived mandate; reason: project standing rule, spec drafting runs on Fable,effort: highClause-②: no
Metadata-protocol: narrowed
Responsibility:
packages/specAnalyticsQueryRequestSchema.cubeaccepts''and the service throws a plain Error | none (the schema check is the existing path, only too wide) | any analytics caller, measured at the public door by QA run #27438Thread-read: 6498803806
Premise: holds — on
178b5238cube: z.string()(analytics.zod.ts:53) and twothrow new Error('Cube name is required …')(analytics-service.ts:2416, :3362)Serial constraints cleared: none (no open PR touches
analytics.zod.tsoranalytics-service.ts; 47 open PRs' file lists read 15:31Z)objectstack-fleet commentedon Oct 29, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Claim amendment · 2026-10-29T19:41Z · ⛔ same claim, same seat, same branch
Container & model:
model: TIER_DEFAULT(opus) — the quota-exhaustion exemption:claude-fable-5-1answered HTTP 429 "You've reached your Fable limit" (measured on this seat's dev subagent, ~17:05Z). Maintainer, in the project thread: 「你没有fable了,使用 opus开发完之后等契约复审」. An opus subagent in the seat thread finishes the same branchclaude/issue-27505-analytics-empty-cube(draft PR #27691). The PR waits for theCONTRACT_REVIEW_TIERcontract review before any landing stroke; this seat cannot serve that tier now, so it hands the review over on the PR once the dev reports.objectstack-fleet commentedon Oct 29, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
os-dev-report
{ "issue": 27505, "status": "done", "branch": "claude/issue-27505-analytics-empty-cube", "pr": "https://github.com/objectstack-ai/objectstack/pull/27691", "head": "a0b621038aad223ccd675c51b20242c18c196040", "draft": true, "session": "session_017ihL2fi9zfJhUTubyJYb6V", "model": "opus (third dev on this card; the earlier two left no report). The maintainer's order supersedes the order file's Fable-review bullet (田騏, stamped in the prose below this block): 「你没有fable了,使用 opus开发完之后等契约复审」. No Fable review was run or substituted. The PR waits for the seat's ## Contract review record.", "premise_still_valid": true, "summary": "AnalyticsQueryRequestSchema.cube is z.string({ error: ANALYTICS_CUBE_NAME_REQUIRED }).min(1, ANALYTICS_CUBE_NAME_REQUIRED). An empty cube at POST /analytics/query and POST /analytics/sql answers 400 VALIDATION_FAILED with fields[0] = { field: cube, code: min_length }, and the service is never called. The two plain Error throws in service-analytics (queryIn, generateSql) are now cubeNameRequiredError(cube): a typed VALIDATION_FAILED / 400 whose field entry comes from the schema member and the one ADR-0114 D3 mapper. ADR-0087 disposition: semantic entry analytics-query-empty-cube-name-refused. This run re-read the full diff against the order and found it matches. The one fix is a changeset sentence that called the driver-memory gap 'a card of its own' when no card exists; it now states what the change leaves. Ablation, all 110 derived gates, the package tests and typechecks, and the dogfood battery were re-run on the final head.", "files_changed": [ ".changeset/27505-analytics-empty-cube.md", "content/docs/references/api/analytics.mdx (generated)", "packages/runtime/src/analytics-empty-cube-refusal.test.ts (new)", "packages/runtime/src/domains/analytics.ts (1 line: fieldsFromZodIssues(issues, body))", "packages/services/service-analytics/src/__tests__/analytics-service.test.ts", "packages/services/service-analytics/src/analytics-service.ts", "packages/services/service-analytics/src/cube-name-refusal.ts (new)", "packages/spec/api-surface/api.json (generated)", "packages/spec/export-origins/api.json (generated)", "packages/spec/src/api/analytics.test.ts", "packages/spec/src/api/analytics.zod.ts", "packages/spec/src/migrations/entries/semantic/18.analytics-query-empty-cube-name-refused.ts (new)" ], "commits_this_run": ["a0b621038a docs(changeset): state the driver-memory guard as what this change leaves, not as a filed card"], "tests": "Head a0b621038a, each run under scripts/pm/os-verify-lock.sh, VERDICT command-exit 0: spec typecheck exit 0; spec test: Test Files 752 passed (752), Tests 22349 passed, 1 todo. service-analytics typecheck exit 0; test: Test Files 196 passed (196), Tests 4739 passed, 282 skipped. runtime typecheck exit 0 (tsc + check:test-typecheck); test: Test Files 478 passed (478), Tests 7794 passed, 19 skipped.", "ablation": "Head a0b621038a, via scripts/ablation-replace.mjs (anchors verified on disk, restore proven by blob). Baseline: spec analytics.test.ts 38/38, runtime analytics-empty-cube-refusal.test.ts 10/10, service analytics-service.test.ts 46/46. Leg A: deleted '.min(1, ANALYTICS_CUBE_NAME_REQUIRED)' (on-disk count 0), rebuilt @objectstack/spec, ablation-dist-preflight --absent exit 0. Result: spec 2 failed / 36 passed, runtime 4 failed / 6 passed, service 3 failed / 43 passed. Restore: blob 73d6676181 == HEAD, git diff HEAD empty, spec rebuilt, preflight (present) exit 0. Leg B: both 'throw cubeNameRequiredError(queryInput.cube);' replaced with plain Error (injected 2, anchor 0). Result: service 5 failed / 41 passed, spec 38/38, runtime 10/10. Restore: blob 34d1d84686 == HEAD, git diff HEAD empty. After both restores: 38/38, 10/10, 46/46, git status --porcelain empty. One earlier launch of the driver script aborted on a shell syntax error before leg A's ablation-replace ran: that leg was a no-op, nothing was mutated, and that attempt's readings were discarded. The whole script was then re-run.", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at a0b621038a derived 110 commands. All 110 were run, each exit code recorded before any pipe: 110 exit 0, 0 non-zero. --ran: '110 derived famil(ies) accounted for — 110 run, 0 NOT-MEASURED (a DERIVED zero — all 110 recorded an exit code and none of them is 3)', exit 0. check:type-check-debt measured under the lock ('0 ledger entr(ies) re-measured … none above its recorded number'). check:entry-nameability passed and prints its standing caveat 'NOT MEASURED: no callable export on @objectstack/spec/api-assembled, @objectstack/spec/qa' (a property of those entries, not this diff). CI on a0b621038a: 50 check-runs, 41 success, 9 skipped, 0 failed, 0 pending. All 10 required contexts are success (Lint & Repo Gates, TypeScript Type Check, Test Core, Build Core, Governed Surface Queue Guard, Type Check UI, Test UI, Build & E2E UI, Live E2E UI) except Lint UI, which is skipped by its path selector. The previous head 427f5e9c99 was also all green (50 runs, success or skipped).", "dogfood_battery": "a0b621038a · os-verify-lock VERDICT command-exit 0 · Test Files 351 passed, 3 skipped (354) · Tests 2825 passed, 20 skipped (2845) · no failures", "line_budget": "n/a — no skills/** file touched", "mcp_calls": "0", "api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/27505/comments (this report, via post-stamped.mjs). git push is not a REST write. The relay issue_patch on #27691 ran as --dry-run only and was refused before packing, so nothing was sent.", "deviations": [ "PR body NOT updated. The relay refused issue_patch on #27691 with exit 2 ('body opens with no signature line'): line 1 must stay the attribution comment, and the relay demands the seat signature as the first non-empty line. No flag turns the rule off, so no write was sent. Stale facts in the stored body: (1) the 'Fable review: owed … the seat runs it when the quota returns' line, now superseded by the maintainer's order; (2) 维护者速读 需要你做的 still names a Fable 复核; (3) the package-run, ablation, gate and dogfood readings all cite head 427f5e9c99 (true readings of that head; the final head is a0b621038a, whose only change is one changeset sentence); (4) the old ablation leg A has no service reading (this run: service 3 failed). A ready replacement body (line 1 kept, every fact above corrected) is at /tmp/claude-0/-home-claude/24ec40df-0dc2-5175-a8cb-f1b1ddaac671/scratchpad/issue-27505/pr-body-new.md.", "File surface: the claim declared spec, its regenerated artifacts, analytics-service.ts, tests beside and changesets, and says 'stop on breach'. A prior dev went past it without stopping: one line in packages/runtime/src/domains/analytics.ts (pass the body to fieldsFromZodIssues) plus the runtime door test, and @objectstack/runtime: minor in the changeset. The PR body's Acceptance notes declare this. Left as found for the seat to decide (see open_questions).", "Clause-② spelling: the claim reads 'Clause-②: no'. The PR body and changeset carry 'Clause-②: no (narrowing)', the spelling of the triage ruling and the order. Not changed.", "Fable review: not run, per the maintainer's order quoted under model." ], "open_questions": [ { "question": "Keep the out-of-surface runtime line (fieldsFromZodIssues(issues, body) in packages/runtime/src/domains/analytics.ts)?", "options": [ "A keep it: one condition reads one field code on both sides (required for an absent cube), as the /data doors already do. Side effect: an absent measures and a bodiless request also move from invalid_type to required. Status and error.code are unchanged. Changeset already declares it.", "B drop it: revert the line, remove the runtime minor, and make the in-process guard map without the input so an absent cube reads invalid_type on both sides. The 'required' pins in both test files flip. One more push, then gates and dogfood again." ], "recommendation": "A, because it follows the ADR-0114 D3 split the /data doors already use. The alternative is a deliberately weaker field code chosen only to stay inside the declared surface." }, { "question": "How should the stale PR body be corrected, given that the relay refuses any issue_patch whose line 1 is the attribution comment?", "options": [ "A the seat or maintainer applies pr-body-new.md through a route that keeps line 1", "B leave the body and let the Contract review record carry the current facts" ], "recommendation": "A, since reviewers read the body." } ], "out_of_scope_findings": [ "class: none (not fileable) · reach: in-process only — after this change the HTTP doors refuse an empty or missing cube at the schema before any IAnalyticsService implementation runs · evidence: packages/drivers/driver-memory/src/memory-analytics.ts:1136 and :1562 throw new Error('Cube name is required') · dedupe words: MemoryAnalyticsService, cube name required, plain Error, driver-memory analytics · carrier: seat · noted, not filed" ] }Reported 2026-10-29T21:19Z. The maintainer's order quoted above (田騏) was given at 2026-10-29T19:39Z.
objectstack-fleet commentedon Oct 29, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
ACCEPT → PR #27691 comment 6508617749 (lane part) + Contract review PASS 6508824023 (
CONTRACT_REVIEW_TIER, triage, heada0b62103) · 2026-10-29T21:55Z · readied and auto-merge armed by the seat (58 check-runs: 43 success, 15 skipped, 0 failed;check-expected-skipsOK);needs:contract-reviewremoved.yes (narrowing)for the newANALYTICS_CUBE_NAME_REQUIREDexport) and ③ (refresh the PR body, add itsSkills-docs:line): not applied. The relay refuses a PR-body write whose line 1 is the attribution marker, and changing only the changeset would split the two carriers the level gate reads. The record states the consequence is nil: theyestier is the one it served. The current facts are in the ACCEPT and the record.driver-memory's plainErrorfor a missing cube (in-process only): left as an Acceptance note, not filed.objectstack-fleet commentedon Oct 29, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Landed · 2026-10-29T22:17Z · PR #27691 merged by the queue at 2026-10-29T22:16Z as
e0aed008e7; the card closed byFixes. This seat stripspm:dispatchedin the same act.