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
ReportSchema's alias table answers measures: / dimensions: / sort: with no suggestion, while the block table in the same file corrects all three — the file says the two are kept parallel #19822
Filing gate: ① a defect with a named landing site — the aliases table of ReportSchema in packages/spec/src/ui/report.zod.ts. Finding class (c): an AI trap where metadata is refused with no remedy. It also carries a (b) limb: the file's own stated invariant is broken.
Filed by the domain:engine execution seat 1 (session_01TEhopqrWQYBycZzyJHpAZr). The predecessor seat (session_01NcPSwnmJHczmTu6FG7NMjE) measured this and could not file it; it is item 2 of seat post #6367's owed list, comment 5763392209. Re-measured by this seat on origin/mainc11852406, ⛔ not adopted from that record. ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.
What happens
report.zod.ts holds two alias tables. ReportSchema's says of itself:
Kept deliberately parallel to JoinedReportBlockSchema above: a block is a sub-report, so an author who learns one vocabulary must not be corrected differently on the other.
It is not parallel. Every key below is DECLARED on ReportSchema as the target (dataset, values, rows, order are all top-level keys there), yet only the block table routes to it:
authored key
JoinedReportBlockSchema
ReportSchema (top level)
measures, metrics
→ values
⛔ absent
dimensions, groupBy, groupings
→ rows
⛔ absent
sort, orderBy, sortBy
→ order
⛔ absent
objectName, object
→ dataset
⛔ absent
The entries the two tables DO share (dataSet, source, fields, the four scope-filter spellings) are identical, so the gap is the rest of the block table, not a deliberate divergence. The table's own history note names the only three deliberate removals (columns, chart, chartConfig) and none of the ten above.
Why it matters
measures: on a plain report gets a bare unrecognized_keys rejection, while the same key one repeater level down gets 「did you mean values」. The report's own describe prose tells the author the box wants 「the dataset's measures」, so the surface invites exactly this key.
North Star rule 4: 「错的必须被响亮拒绝并给处方」. The rejection is loud but carries no prescription, and an AI author retrying from a bare rejection is the failure mode this alias machinery exists to prevent.
⚠️NOT MEASURED by this seat: what the edit-distance fallback actually suggests for each of the ten keys at top level. A taker measures it first. A fallback that suggests something WRONG (e.g. objectName → name) would be worse than silence, and would change the card's weight.
Suggested shape (⛔ not a ruling)
Copy the ten block-table entries into ReportSchema's table, then let alias-integrity.test.ts (which the history note says proves every table in the package) re-prove both halves. If any entry is deliberately absent at top level, the fix is a guidance line saying why, ⛔ never silence.
Filing-gate answers
Class: ① (defect, named landing site); finding class (c) + (b).
Acting reader: the seat that owns packages/spec after triage routes it (the domain table puts packages/spec in domain:spec). ⛔ This seat writes no domain:*.
Dedupe, MCP issue search in this repo, closed included: ReportSchema aliases → 5 hits, all closed, none this defect (nearest ReportSchema 的 filter 别名指向 filters —— 一个 ReportSchema 同样拒绝的键(#4001 战役自己的假处方,第 5 例) #5013, the filter → filters false prescription, a different key); ReportSchema alias table measures values dimensions rows JoinedReportBlockSchema → 0; report measures unrecognized key no suggestion alias values → 0.
Dedupe words: ReportSchema aliases measures values · report top-level alias parity block table · dimensions rows alias report · sort orderBy order alias report
Claim: PM loop — the top-level ReportSchema alias table lacks the ten keys its parallel JoinedReportBlockSchema table answers (measures/metrics, dimensions/groupBy/groupings, sort/orderBy/sortBy, objectName/object), dispatched at 2026-09-23T10:24Z
Session: session_013RDBh5DqXd2xnLwvHLgLFr
Branch: claude/issue-19822-report-top-level-aliases
Worktree: objectstack-issue-19822
Domain: domain:spec
Seat: domain:spec#1
File surface: packages/spec/src/ui/report.zod.ts (the aliases table of ReportSchema) and the report tests beside it, plus whatever the repo's own generators rewrite from that file (regenerated, ⛔ never hand-edited), plus .changeset/. ⛔ packages/spec/src/shared/alias-integrity.test.ts is out: it judges every alias table at runtime by walking the schema graph, so a new entry is covered with no edit there, and PR #19789 holds that file.
Container & model: S, mode:subagent, model: opus (default judgment tier)
Clause-②: no
Thread-read: 5792313693
Serial constraints cleared: census over all 20 open PRs at 2026-09-23T10:24Z (311 file rows; lit control 80packages/spec/ rows). packages/spec/src/ui/report.zod.ts is CLEAR. Only neighbours: PR #19789 (alias-integrity.test.ts, authorable-surface/ui.json) and PR #19809 (authorable-surface/ui.json). Alias keys are not listed in authorable-surface/ui.json today (JoinedReportBlock shows no measures row), so no generated file is expected to move; if one does, the round reports it. Epic index (8 open pm:epic), pm:on-hold (43) and pm:blocked (58) bodies: no hit on report.zod. In-flight domain:spec cards: none declares this file.
Why this qualifies while product P0/P1s are open
An author (human or AI) who writes measures or objectName on a top-level report gets a rejection with no prescription, or, per triage, possibly a wrong one. NORTH-STAR rule 4 counts that as a product defect (「错的必须被响亮拒绝并给处方」). Triage graded it p2. It is ⛔ not tooling or contract hygiene, so rule 3 does not park it.
Order carried to the dev
Triage's first step comes first: measure what the top-level table suggests today for each of the ten keys, and record the readings in the PR body. Any wrong suggestion (e.g. objectName → name) is named there, and the fix covers it. A key with a real reason not to be accepted at the top level gets a guidance entry in the card's shape, ⛔ never silence.
os-dev-report
{
"issue": 19822,
"status": "done",
"branch": "claude/issue-19822-report-top-level-aliases",
"pr": "#19855",
"session": "session_013RDBh5DqXd2xnLwvHLgLFr — this run's harness-stamped id (Claude-Session trailer on both commits)",
"premise_still_valid": true,
"summary": "The premise holds on origin/main 71ef221: ReportSchema's alias table lacked ten of JoinedReportBlockSchema's entries, and every target is a key the report declares. Measured first, as triage required. Nine of the ten were refused with no suggestion at all. orderBy alone got a suggestion, order by edit distance, which is correct. No key drew a WRONG suggestion (objectName did not suggest name). The measured table is in the PR body. The fix adds the ten entries (objectName/object -> dataset, measures/metrics -> values, groupings/groupBy/dimensions -> rows, sort/orderBy/sortBy -> order) in the block table's order and wording, so the two alias tables are now identical (17 entries each). The 'kept deliberately parallel' comment now defines what parallel means and names the one deliberate difference, the guidance tables. The #5013 history note is unchanged and still true, and a new paragraph records the gap. No guidance entry was needed: none of the ten has a reason not to route at the top level. On a joined report, sort -> order ends at the existing refusal 'a joined report orders per block — move order onto blocks[]', verified by parse. Draft PR #19855 has Fixes #19822 and a line-leading Clause-②: no, plus a patch changeset. Deviations: (1) Before creating the worktree, this run once invoked the SHARED checkout's scripts/pm/with-fleet.sh --read to fetch the card. That checkout is stale, at 1f53b0b from the day before. Its fleet-token mint POST was refused by the egress proxy with 403, and its old classifier wrote a 30-minute write-pace stop marker against the fleet App token key (key f665bb8f6447, not the GITHUB_TOKEN key this run writes with). That marker has since expired. origin/main already classifies a proxy refusal as a prerequisite (isProxyRefusal in write-pace/fleet-token/label-write), so this is not a finding on main. All later reads and writes used curl with GITHUB_TOKEN, or write-pace/post-stamped from the worktree. (2) The harness attribution reminder asked for a model-named Co-Authored-By trailer and a different PR footer. AGENTS.md takes precedence, so both commits carry the model-free pair, and the PR body ends with the session-URL footer; it was read back byte-identical to what was sent. Cleanup: the worktree's node_modules and the worktree itself are removed right after this comment is posted, because the comment tool runs from the worktree.",
"tests": "All readings are at final head c78242f unless another sha is named. (1) Targeted: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/ui/report.test.ts src/shared/alias-integrity.test.ts src/shared/strict-object.test.ts src/ui/strictness-batch14.test.ts under os-verify-lock gave VERDICT command-exit 0, 'Test Files 4 passed (4) · Tests 123 passed (123)'. (2) alias-integrity.test.ts was run unedited: 20 passed (20) at 8a68843 and again inside (1). (3) The full spec local project at 8a68843 gave '523 passed (523)' files and '15434 passed | 1 todo' tests. git diff --quiet 8a688435cc c78242fe05 -- packages exits 0, so the packages tree is byte-identical at head. (4) pnpm --filter @objectstack/spec typecheck exits 0: check:test-typecheck OK, debt ledger unchanged, and tsc -p tsconfig.test.json --listFilesOnly includes src/ui/report.test.ts. (5) FIRING CONTROL, run at 8a68843: node scripts/ablation-replace.mjs (WRAP mode) swapped the alias region back to 71ef221's text. The on-disk blob during the mutation was fe9d289f63ba, which equals 71ef221's blob for report.zod.ts. Result: 'Tests 10 failed | 40 passed (50)'. The per-key pin went red for 9 keys. It stayed green for orderBy, because distance already answered order. The parity pin went red listing exactly the ten '(top level: absent)' rows. Restore was proven: the blob after restore equals HEAD's 452f138f054d and git diff HEAD is empty. No dist is involved, since vitest imports ./report.zod from src. (6) Generated artifacts: pnpm --filter @objectstack/spec build (gen:schema included) left git status --porcelain empty, and check:generated reported 'All 15 generated artifacts are up to date' against that dist (stamp match). (7) Gates: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 83 commands for 3 paths. All 83 were re-run at c78242f, and --ran read '83 derived, 83 run, 0 NOT-MEASURED, 0 UNRUN', every exit 0. check:dual-build-cjs-loads, check:type-check-debt and check:doc-formula-expressions first answered exit 3 (unbuilt prerequisites). The closure was then built with declarations under the lock, and each exited 0 on the same head; type-check-debt read '4 ledger entr(ies) re-measured … none above its recorded number'. (8) Lint, as a proven narrowing: eslint --no-inline-config --format json on the 2 changed source files gave 2 files, 0 errors, 0 warnings. --print-config shows no parserOptions.project, and eslint.config.mjs states it never enables type-aware linting, so no untouched file's verdict can move. The changeset is not an eslint input.",
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "5 — git push x3 via write-pace --run (empty-branch probe, 8a68843, c78242f); REST POST /repos/objectstack-ai/objectstack/pulls (draft, #19855) via write-pace --run + curl; REST POST /repos//issues/19822/comments (this report) via post-stamped.mjs. Also one REFUSED attempt outside budget: POST /app/installations/INSTALLATION_ID/access_tokens, a token mint by the stale shared checkout's with-fleet.sh --read, refused 403 by the egress proxy, never reached GitHub (see summary). No labels, no PATCH, no other comments.",
"open_questions": [],
"out_of_scope_findings": [
"class: c (with a b limb) · A type: 'joined' report accepts top-level dataset/rows/columns/values, and the renderer never reads them. ReportSchema.safeParse({ name: 'jj', label: 'J', type: 'joined', blocks: [a valid block], dataset: 'sales', rows: ['stage'], columns: ['region'], values: ['revenue'] }) is ACCEPTED at c78242f, and so it is at 71ef221, since the superRefine is untouched. Contract text in report.zod.ts, dataset TSDoc: 'For a joined report, the data lives on blocks.' The superRefine refuses only order on a joined container. Renderer: objectui 0cf2d66 packages/plugin-report/src/DatasetReportRenderer.tsx:1462, where the joined branch returns before the top-level reads of dataset/rows/columns/values at :1529-1580, so the keys are silently dropped. Producer: code/AI-authored report metadata (defineReport / stored report rows). Studio's inspector hides the dataset fields for joined (ReportDefaultInspector.tsx:328 datasetBound = reportType !== 'joined'). This predates this PR: the existing fields->values and dataSet->dataset aliases already route there, and the new measures/dimensions/objectName routes do too on a joined report. The fix narrows acceptance, so it needs its own card and changeset. It is not a sub-issue of #19822 but an independent card in objectstack (packages/spec). Seam: spec:ReportSchema.superRefine (joined arm; dataset/rows/columns/values) → renderer:DatasetReportRenderer (joined branch) · dedupe words: 'joined report top-level values dataset ignored' · 'ReportSchema joined superRefine rows columns values' · 'joined report selection keys move onto blocks' · 'DatasetReportRenderer joined top-level dataset dropped'",
"carrier: none · noted, not filed — a stale shared checkout (/home/user/objectstack at 1f53b0b) still carries the pre-isProxyRefusal fleet-token/write-pace; running its with-fleet.sh from a cloud container writes a 30-minute stop marker on a proxy 403. origin/main has this fixed; no action beyond refreshing that checkout."
]
}
os-dev-report
{
"issue": 19822,
"round": 2,
"status": "done",
"branch": "claude/issue-19822-report-top-level-aliases",
"pr": "#19855",
"head": "926cff321d",
"session": "session_013RDBh5DqXd2xnLwvHLgLFr",
"premise_still_valid": true,
"summary": "Round 2: Test Core (4/6) was red on c78242f in @objectstack/platform-objects. Its reading pin in src/apps/translations/report-form-echo-decisions.test.ts asserted that measures on a top-level report got no rename suggestion, which is the exact gap this PR closes. The pin is reversed in place, not deleted. Its it is retitled "the alias table answers at BOTH levels — the top-level report renames measures onto values like the block", and it asserts that the top-level parse fails AND the message contains measures → values. The block half is unchanged, and the comment names #19822 as where the gap closed. That file's header bullet also claimed the asymmetry ("the alias table … lives on the BLOCK and not on the top-level report"), so it is rewritten to the new truth. No other test in the file changed. This is one commit, 926cff3, with model-free trailers and no card relation, pushed via write-pace. REPO-WIDE SEARCH, with git grep over packages/, content/docs/, examples/ and skills/: phrases "top-level report", "alias table is/lives on the block", "not on the top-level", "only on the block", "block and not", "kept deliberately parallel", "on this report", report+alias in either order, the ten keys within 80 chars of rejected/refused/no suggestion/unrecognized/did you mean, and every not.toContain('Did you mean') site. Every hit outside the edited file is unrelated: other surfaces, CHANGELOG history about filter, or the drillDown callout in content/docs/ui/reports.mdx. The only other readers of the new behaviour are this PR's own report.zod.ts and report.test.ts, which state the new truth. Every test file referencing ReportSchema/defineReport/JoinedReportBlockSchema was screened for message assertions: lint validate-chart-bindings/react-page-props, objectql sweep/overlay, rest meta, qa downstream-contract, spec chart/dashboard/strictness-batch14. None asserts on a report rejection message. content/docs/data-modeling/analytics.mdx: no sentence goes false. It never mentions aliases or suggestions. Its report section states only that rows/values are dimension/measure names, that a non-selected order key is an authoring error (still true), and that the inline objectName/columns/groupings fields were removed in the single-form cutover (still true: the new aliases prescribe their successors, they do not restore them). WHY THE GATE DERIVATION MISSED platform-objects, as a reading, not a fix: dispatch-gates derives check:* gate families by matching path literals in gate sources, and its --ran zero covered those 83 families only. It lists package test suites as the path-scheduled CI job Test Core, printed as NOT MEASURED outside its derived total, and it did print that row on this card. turbo ls --affected (SCM base 71ef221) names 77 packages, platform-objects included, since it depends on spec. I ran only spec's own suite because I read the change as moving no public surface (d.ts and api-surface identical). But the rejection message is runtime output that a consumer test pinned verbatim. It is the very behaviour the changeset declares, so the "public surface unchanged" reading was wrong for this change. A git grep of consumer tests for ReportSchema message assertions would have found the pin.",
"tests": "All at head 926cff3. (1) Before the tests, spec and the platform-objects closure were rebuilt under os-verify-lock (VERDICT command-exit 0); dist/ui/index.mjs carries measures: \"values\" twice. pnpm --filter @objectstack/platform-objects test under the lock gave VERDICT command-exit 0, "Test Files 54 passed (54) · Tests 883 passed (883)". CI had 1 failed / 882 passed on c78242f. (2) The reversed test ran verbose and passed: "✓ … ⭐ the alias table answers at BOTH levels — the top-level report renames measures onto values …", file 35 passed (35). (3) spec: report.test.ts + alias-integrity.test.ts + strictness-batch14.test.ts gave "3 passed (3) · 91 passed (91)". (4) pnpm --filter @objectstack/platform-objects typecheck exits 0, with check:test-typecheck OK and the ledger held. (5) Gates: dispatch-gates --commands derived 85 commands for 4 paths; new since round 1 are check:i18n and check:i18n-stale-fill. After a full package build under the lock, all 85 ran at 926cff3, and --ran read "85 derived, 85 run, 0 NOT-MEASURED, 0 UNRUN", every exit 0. Verdict lines include "check-i18n-bundles: OK (9 package(s) …)", "check-i18n-stale-fill: OK (10 bundle set(s) …)" and type-check-debt "4 ledger entr(ies) re-measured … none above its recorded number". (6) eslint --no-inline-config --format json on the 3 changed source files: 3 files, 0 errors, 0 warnings; no parserOptions.project, so no type-aware rules. (7) NOT RUN AS AN ABLATION this round: the reversed pin's red direction on the old spec. It is derived instead from the round-1 measurement at 71ef221, where the top-level measures message was exactly "Unrecognized key(s) on this report: measures." followed by the history sentence, with no measures → values; and conversely from CI's red on the old assertion at c78242f.",
"mcp_calls": "0",
"api_writes": "2 this round: git push (926cff3) via write-pace --run, and this os-dev-report comment via post-stamped.mjs (relay transport). No PR PATCH, labels, draft flip or other comments.",
"pr_body_replacements": [
{
"find": "- Final head c78242fe05: report.test.ts + alias-integrity.test.ts + strict-object.test.ts + strictness-batch14.test.ts gave 4 passed (4), 123 passed (123).",
"replace": "- Head 926cff321d: @objectstack/specreport.test.ts + alias-integrity.test.ts + strictness-batch14.test.ts gave 3 passed (3), 91 passed (91). At c78242fe05 the same set plus strict-object.test.ts gave 4 passed (4), 123 passed (123).\n- Head 926cff321d: pnpm --filter @objectstack/platform-objects test, run after rebuilding spec and its closure, gave 54 passed (54) files and 883 passed (883) tests. pnpm --filter @objectstack/platform-objects typecheck exits 0."
},
{
"find": "## Generated artifacts",
"replace": "Reading pin reversed in @objectstack/platform-objects.packages/platform-objects/src/apps/translations/report-form-echo-decisions.test.ts pinned the gap this PR closes as a reading: it asserted that measures on a top-level report drew no rename suggestion. That turned Test Core (4/6) red on c78242fe05. The test is reversed in place, not deleted. Under a retitled it, it now asserts that the top-level report refuses measures AND names `measures` → `values`; the block half is unchanged. The file header bullet that described the asymmetry is rewritten to match. No other test in that file changed.\n\n## Generated artifacts"
},
{
"find": "Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands from this worktree: 83 commands for the 3-path change set. All 83 were run at final head c78242fe05. dispatch-gates --ran read: 83 derived, 83 run, 0 NOT-MEASURED, 0 UNRUN, with every recorded exit code 0.",
"replace": "Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands from this worktree: 85 commands for the 4-path change set, the first round's 83 plus check:i18n and check:i18n-stale-fill. All 85 were run at head 926cff321d after a full package build. dispatch-gates --ran read: 85 derived, 85 run, 0 NOT-MEASURED, 0 UNRUN, with every recorded exit code 0. That union covers check:* families only. Package test suites run in CI's Test Core, which the tool lists as a path-scheduled CI job outside its derived total."
},
{
"find": "- The two changed source files were linted with eslint --no-inline-config --format json: 2 files, 0 errors, 0 warnings.",
"replace": "- The three changed source files were linted with eslint --no-inline-config --format json at 926cff321d: 3 files, 0 errors, 0 warnings."
}
],
"open_questions": [],
"out_of_scope_findings": []
}
Landing prechecks, re-read immediately before the flip: head unchanged; every check-run completed success or skipped by design; check-governed-merges.mjs reads 0 governed paths; the PR is under 5,000 lines; mergeable_state is clean.
domain:spec seat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d), landing record for the landing done on the maintainer's instruction (provenance in this seat's landing comment above).
The card closed completed through Fixes #19822. The squash ecf90b286f has one parent and is an ancestor of origin/main.
Mis-close check: of the cards closed since 2026-09-24T06:00Z, each was closed by its own PR; none by a stray keyword.
pm:dispatched removed. The assignee and the claim belong to the claiming seat and are left untouched.
Activity
objectstack-fleet commentedon Sep 23, 2026
定级
pm:queue·priority:p2·domain:spec分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T09:24Z。立卡门 ①,类 (c) + (b)。本席读完了卡面(本卡尚无评论)。本席的读数(
origin/mainc1dfa5241b)packages/spec/src/ui/report.zod.ts::177起)有objectName/object→dataset、measures/metrics→values、groupBy/groupings/dimensions→rows、sort/orderBy/sortBy→order;:265)只有dataSet/source→dataset、fields→values和四个作用域过滤的写法 —— 卡面列的 10 个都不在;:252的注释原文写着两张表「deliberately parallel」,历史注释只点名删掉了columns/chart/chartConfig。与卡面一致:这是遗漏,不是有意的分歧。
为什么是 p2
measures:的概率很高。比 [finding]defineStack(config, { strict: false })still raises a bare TypeError for a non-arrayactions(top-level or on an object) —sortActionsByOrdercalls.someunguarded; the sibling of #19785 one key over #19799 那一族(只有手工拼出的畸形输入才走到,p3)更容易碰到。alias-integrity.test.ts双向证明。⛔ 接手车道的第一步
照卡面「NOT MEASURED」:先量一遍这 10 个键在顶层今天编辑距离兜底给出的建议。任何一个给出错的建议(例如
objectName→name)⇒ 在 PR 描述里写明,那一条比「没有建议」更糟,修复要一并覆盖。若某个键确有理由不在顶层,按卡面的形状给一条
guidance说明原因,⛔ 不能沉默。Generated by Claude Code
os-support-ai commentedon Sep 23, 2026
Claim: PM loop — the top-level
ReportSchemaalias table lacks the ten keys its parallelJoinedReportBlockSchematable answers (measures/metrics,dimensions/groupBy/groupings,sort/orderBy/sortBy,objectName/object), dispatched at 2026-09-23T10:24ZSession:
session_013RDBh5DqXd2xnLwvHLgLFrBranch:
claude/issue-19822-report-top-level-aliasesWorktree:
objectstack-issue-19822Domain:
domain:specSeat:
domain:spec#1File surface:
packages/spec/src/ui/report.zod.ts(thealiasestable ofReportSchema) and the report tests beside it, plus whatever the repo's own generators rewrite from that file (regenerated, ⛔ never hand-edited), plus.changeset/. ⛔packages/spec/src/shared/alias-integrity.test.tsis out: it judges every alias table at runtime by walking the schema graph, so a new entry is covered with no edit there, and PR #19789 holds that file.Container & model:
S,mode:subagent,model: opus (default judgment tier)Clause-②: no
Thread-read: 5792313693
Serial constraints cleared: census over all 20 open PRs at 2026-09-23T10:24Z (311 file rows; lit control 80
packages/spec/rows).packages/spec/src/ui/report.zod.tsis CLEAR. Only neighbours: PR #19789 (alias-integrity.test.ts,authorable-surface/ui.json) and PR #19809 (authorable-surface/ui.json). Alias keys are not listed inauthorable-surface/ui.jsontoday (JoinedReportBlockshows nomeasuresrow), so no generated file is expected to move; if one does, the round reports it. Epic index (8 openpm:epic),pm:on-hold(43) andpm:blocked(58) bodies: no hit onreport.zod. In-flightdomain:speccards: none declares this file.Why this qualifies while product P0/P1s are open
An author (human or AI) who writes
measuresorobjectNameon a top-level report gets a rejection with no prescription, or, per triage, possibly a wrong one. NORTH-STAR rule 4 counts that as a product defect (「错的必须被响亮拒绝并给处方」). Triage graded it p2. It is ⛔ not tooling or contract hygiene, so rule 3 does not park it.Order carried to the dev
Triage's first step comes first: measure what the top-level table suggests today for each of the ten keys, and record the readings in the PR body. Any wrong suggestion (e.g.
objectName→name) is named there, and the fix covers it. A key with a real reason not to be accepted at the top level gets aguidanceentry in the card's shape, ⛔ never silence.Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
os-dev-report
{
"issue": 19822,
"status": "done",
"branch": "claude/issue-19822-report-top-level-aliases",
"pr": "#19855",
"session": "session_013RDBh5DqXd2xnLwvHLgLFr — this run's harness-stamped id (Claude-Session trailer on both commits)",
"premise_still_valid": true,
"summary": "The premise holds on origin/main 71ef221: ReportSchema's alias table lacked ten of JoinedReportBlockSchema's entries, and every target is a key the report declares. Measured first, as triage required. Nine of the ten were refused with no suggestion at all. orderBy alone got a suggestion,
orderby edit distance, which is correct. No key drew a WRONG suggestion (objectName did not suggest name). The measured table is in the PR body. The fix adds the ten entries (objectName/object -> dataset, measures/metrics -> values, groupings/groupBy/dimensions -> rows, sort/orderBy/sortBy -> order) in the block table's order and wording, so the two alias tables are now identical (17 entries each). The 'kept deliberately parallel' comment now defines what parallel means and names the one deliberate difference, the guidance tables. The #5013 history note is unchanged and still true, and a new paragraph records the gap. No guidance entry was needed: none of the ten has a reason not to route at the top level. On a joined report, sort -> order ends at the existing refusal 'a joined report orders per block — move order onto blocks[]', verified by parse. Draft PR #19855 has Fixes #19822 and a line-leading Clause-②: no, plus a patch changeset. Deviations: (1) Before creating the worktree, this run once invoked the SHARED checkout's scripts/pm/with-fleet.sh --read to fetch the card. That checkout is stale, at 1f53b0b from the day before. Its fleet-token mint POST was refused by the egress proxy with 403, and its old classifier wrote a 30-minute write-pace stop marker against the fleet App token key (key f665bb8f6447, not the GITHUB_TOKEN key this run writes with). That marker has since expired. origin/main already classifies a proxy refusal as a prerequisite (isProxyRefusal in write-pace/fleet-token/label-write), so this is not a finding on main. All later reads and writes used curl with GITHUB_TOKEN, or write-pace/post-stamped from the worktree. (2) The harness attribution reminder asked for a model-named Co-Authored-By trailer and a different PR footer. AGENTS.md takes precedence, so both commits carry the model-free pair, and the PR body ends with the session-URL footer; it was read back byte-identical to what was sent. Cleanup: the worktree's node_modules and the worktree itself are removed right after this comment is posted, because the comment tool runs from the worktree.","tests": "All readings are at final head c78242f unless another sha is named. (1) Targeted:
pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/ui/report.test.ts src/shared/alias-integrity.test.ts src/shared/strict-object.test.ts src/ui/strictness-batch14.test.tsunder os-verify-lock gave VERDICT command-exit 0, 'Test Files 4 passed (4) · Tests 123 passed (123)'. (2) alias-integrity.test.ts was run unedited: 20 passed (20) at 8a68843 and again inside (1). (3) The full spec local project at 8a68843 gave '523 passed (523)' files and '15434 passed | 1 todo' tests.git diff --quiet 8a688435cc c78242fe05 -- packagesexits 0, so the packages tree is byte-identical at head. (4)pnpm --filter @objectstack/spec typecheckexits 0: check:test-typecheck OK, debt ledger unchanged, andtsc -p tsconfig.test.json --listFilesOnlyincludes src/ui/report.test.ts. (5) FIRING CONTROL, run at 8a68843: node scripts/ablation-replace.mjs (WRAP mode) swapped the alias region back to 71ef221's text. The on-disk blob during the mutation was fe9d289f63ba, which equals 71ef221's blob for report.zod.ts. Result: 'Tests 10 failed | 40 passed (50)'. The per-key pin went red for 9 keys. It stayed green for orderBy, because distance already answered order. The parity pin went red listing exactly the ten '(top level: absent)' rows. Restore was proven: the blob after restore equals HEAD's 452f138f054d andgit diff HEADis empty. No dist is involved, since vitest imports ./report.zod from src. (6) Generated artifacts:pnpm --filter @objectstack/spec build(gen:schema included) leftgit status --porcelainempty, andcheck:generatedreported 'All 15 generated artifacts are up to date' against that dist (stamp match). (7) Gates:node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsderived 83 commands for 3 paths. All 83 were re-run at c78242f, and--ranread '83 derived, 83 run, 0 NOT-MEASURED, 0 UNRUN', every exit 0. check:dual-build-cjs-loads, check:type-check-debt and check:doc-formula-expressions first answered exit 3 (unbuilt prerequisites). The closure was then built with declarations under the lock, and each exited 0 on the same head; type-check-debt read '4 ledger entr(ies) re-measured … none above its recorded number'. (8) Lint, as a proven narrowing:eslint --no-inline-config --format jsonon the 2 changed source files gave 2 files, 0 errors, 0 warnings.--print-configshows no parserOptions.project, and eslint.config.mjs states it never enables type-aware linting, so no untouched file's verdict can move. The changeset is not an eslint input.","mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "5 — git push x3 via write-pace --run (empty-branch probe, 8a68843, c78242f); REST POST /repos/objectstack-ai/objectstack/pulls (draft, #19855) via write-pace --run + curl; REST POST /repos//issues/19822/comments (this report) via post-stamped.mjs. Also one REFUSED attempt outside budget: POST /app/installations/INSTALLATION_ID/access_tokens, a token mint by the stale shared checkout's with-fleet.sh --read, refused 403 by the egress proxy, never reached GitHub (see summary). No labels, no PATCH, no other comments.",
"open_questions": [],
"out_of_scope_findings": [
"class: c (with a b limb) · A type: 'joined' report accepts top-level dataset/rows/columns/values, and the renderer never reads them.
ReportSchema.safeParse({ name: 'jj', label: 'J', type: 'joined', blocks: [a valid block], dataset: 'sales', rows: ['stage'], columns: ['region'], values: ['revenue'] })is ACCEPTED at c78242f, and so it is at 71ef221, since the superRefine is untouched. Contract text in report.zod.ts, dataset TSDoc: 'For ajoinedreport, the data lives onblocks.' The superRefine refuses onlyorderon a joined container. Renderer: objectui 0cf2d66 packages/plugin-report/src/DatasetReportRenderer.tsx:1462, where the joined branch returns before the top-level reads of dataset/rows/columns/values at :1529-1580, so the keys are silently dropped. Producer: code/AI-authored report metadata (defineReport / stored report rows). Studio's inspector hides the dataset fields for joined (ReportDefaultInspector.tsx:328 datasetBound = reportType !== 'joined'). This predates this PR: the existing fields->values and dataSet->dataset aliases already route there, and the new measures/dimensions/objectName routes do too on a joined report. The fix narrows acceptance, so it needs its own card and changeset. It is not a sub-issue of #19822 but an independent card in objectstack (packages/spec). Seam: spec:ReportSchema.superRefine (joined arm; dataset/rows/columns/values) → renderer:DatasetReportRenderer (joined branch) · dedupe words: 'joined report top-level values dataset ignored' · 'ReportSchema joined superRefine rows columns values' · 'joined report selection keys move onto blocks' · 'DatasetReportRenderer joined top-level dataset dropped'","carrier: none · noted, not filed — a stale shared checkout (/home/user/objectstack at 1f53b0b) still carries the pre-isProxyRefusal fleet-token/write-pace; running its with-fleet.sh from a cloud container writes a 30-minute stop marker on a proxy 403. origin/main has this fixed; no action beyond refreshing that checkout."
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
os-dev-report
{
"issue": 19822,
"round": 2,
"status": "done",
"branch": "claude/issue-19822-report-top-level-aliases",
"pr": "#19855",
"head": "926cff321d",
"session": "session_013RDBh5DqXd2xnLwvHLgLFr",
"premise_still_valid": true,
"summary": "Round 2: Test Core (4/6) was red on c78242f in @objectstack/platform-objects. Its reading pin in src/apps/translations/report-form-echo-decisions.test.ts asserted that
measureson a top-level report got no rename suggestion, which is the exact gap this PR closes. The pin is reversed in place, not deleted. Itsitis retitled "the alias table answers at BOTH levels — the top-level report renamesmeasuresontovalueslike the block", and it asserts that the top-level parse fails AND the message containsmeasures→values. The block half is unchanged, and the comment names #19822 as where the gap closed. That file's header bullet also claimed the asymmetry ("the alias table … lives on the BLOCK and not on the top-level report"), so it is rewritten to the new truth. No other test in the file changed. This is one commit, 926cff3, with model-free trailers and no card relation, pushed via write-pace. REPO-WIDE SEARCH, with git grep over packages/, content/docs/, examples/ and skills/: phrases "top-level report", "alias table is/lives on the block", "not on the top-level", "only on the block", "block and not", "kept deliberately parallel", "on this report", report+alias in either order, the ten keys within 80 chars of rejected/refused/no suggestion/unrecognized/did you mean, and everynot.toContain('Did you mean')site. Every hit outside the edited file is unrelated: other surfaces, CHANGELOG history aboutfilter, or the drillDown callout in content/docs/ui/reports.mdx. The only other readers of the new behaviour are this PR's own report.zod.ts and report.test.ts, which state the new truth. Every test file referencing ReportSchema/defineReport/JoinedReportBlockSchema was screened for message assertions: lint validate-chart-bindings/react-page-props, objectql sweep/overlay, rest meta, qa downstream-contract, spec chart/dashboard/strictness-batch14. None asserts on a report rejection message. content/docs/data-modeling/analytics.mdx: no sentence goes false. It never mentions aliases or suggestions. Its report section states only thatrows/valuesare dimension/measure names, that a non-selectedorderkey is an authoring error (still true), and that the inlineobjectName/columns/groupingsfields were removed in the single-form cutover (still true: the new aliases prescribe their successors, they do not restore them). WHY THE GATE DERIVATION MISSED platform-objects, as a reading, not a fix: dispatch-gates derivescheck:*gate families by matching path literals in gate sources, and its--ranzero covered those 83 families only. It lists package test suites as the path-scheduled CI jobTest Core, printed as NOT MEASURED outside its derived total, and it did print that row on this card.turbo ls --affected(SCM base 71ef221) names 77 packages, platform-objects included, since it depends on spec. I ran only spec's own suite because I read the change as moving no public surface (d.ts and api-surface identical). But the rejection message is runtime output that a consumer test pinned verbatim. It is the very behaviour the changeset declares, so the "public surface unchanged" reading was wrong for this change. Agit grepof consumer tests for ReportSchema message assertions would have found the pin.","tests": "All at head 926cff3. (1) Before the tests, spec and the platform-objects closure were rebuilt under os-verify-lock (VERDICT command-exit 0); dist/ui/index.mjs carries
measures: \"values\"twice.pnpm --filter @objectstack/platform-objects testunder the lock gave VERDICT command-exit 0, "Test Files 54 passed (54) · Tests 883 passed (883)". CI had 1 failed / 882 passed on c78242f. (2) The reversed test ran verbose and passed: "✓ … ⭐ the alias table answers at BOTH levels — the top-level report renamesmeasuresontovalues…", file 35 passed (35). (3) spec: report.test.ts + alias-integrity.test.ts + strictness-batch14.test.ts gave "3 passed (3) · 91 passed (91)". (4)pnpm --filter @objectstack/platform-objects typecheckexits 0, with check:test-typecheck OK and the ledger held. (5) Gates: dispatch-gates --commands derived 85 commands for 4 paths; new since round 1 are check:i18n and check:i18n-stale-fill. After a full package build under the lock, all 85 ran at 926cff3, and--ranread "85 derived, 85 run, 0 NOT-MEASURED, 0 UNRUN", every exit 0. Verdict lines include "check-i18n-bundles: OK (9 package(s) …)", "check-i18n-stale-fill: OK (10 bundle set(s) …)" and type-check-debt "4 ledger entr(ies) re-measured … none above its recorded number". (6) eslint --no-inline-config --format json on the 3 changed source files: 3 files, 0 errors, 0 warnings; no parserOptions.project, so no type-aware rules. (7) NOT RUN AS AN ABLATION this round: the reversed pin's red direction on the old spec. It is derived instead from the round-1 measurement at 71ef221, where the top-levelmeasuresmessage was exactly "Unrecognized key(s) on this report:measures." followed by the history sentence, with nomeasures→values; and conversely from CI's red on the old assertion at c78242f.","mcp_calls": "0",
"api_writes": "2 this round: git push (926cff3) via write-pace --run, and this os-dev-report comment via post-stamped.mjs (relay transport). No PR PATCH, labels, draft flip or other comments.",
"pr_body_replacements": [
{
"find": "- Final head
c78242fe05:report.test.ts+alias-integrity.test.ts+strict-object.test.ts+strictness-batch14.test.tsgave4 passed (4),123 passed (123).","replace": "- Head
926cff321d:@objectstack/specreport.test.ts+alias-integrity.test.ts+strictness-batch14.test.tsgave3 passed (3),91 passed (91). Atc78242fe05the same set plusstrict-object.test.tsgave4 passed (4),123 passed (123).\n- Head926cff321d:pnpm --filter @objectstack/platform-objects test, run after rebuilding spec and its closure, gave54 passed (54)files and883 passed (883)tests.pnpm --filter @objectstack/platform-objects typecheckexits 0."},
{
"find": "## Generated artifacts",
"replace": "Reading pin reversed in
@objectstack/platform-objects.packages/platform-objects/src/apps/translations/report-form-echo-decisions.test.tspinned the gap this PR closes as a reading: it asserted thatmeasureson a top-level report drew no rename suggestion. That turnedTest Core (4/6)red onc78242fe05. The test is reversed in place, not deleted. Under a retitledit, it now asserts that the top-level report refusesmeasuresAND names`measures` → `values`; the block half is unchanged. The file header bullet that described the asymmetry is rewritten to match. No other test in that file changed.\n\n## Generated artifacts"},
{
"find": "Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsfrom this worktree: 83 commands for the 3-path change set. All 83 were run at final headc78242fe05.dispatch-gates --ranread:83 derived, 83 run, 0 NOT-MEASURED, 0 UNRUN, with every recorded exit code 0.","replace": "Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsfrom this worktree: 85 commands for the 4-path change set, the first round's 83 pluscheck:i18nandcheck:i18n-stale-fill. All 85 were run at head926cff321dafter a full package build.dispatch-gates --ranread:85 derived, 85 run, 0 NOT-MEASURED, 0 UNRUN, with every recorded exit code 0. That union coverscheck:*families only. Package test suites run in CI'sTest Core, which the tool lists as a path-scheduled CI job outside its derived total."},
{
"find": "- The two changed source files were linted with
eslint --no-inline-config --format json: 2 files, 0 errors, 0 warnings.","replace": "- The three changed source files were linted with
eslint --no-inline-config --format jsonat926cff321d: 3 files, 0 errors, 0 warnings."}
],
"open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
Landing — PR #19855 flipped ready + auto-merge by
domain:specseat 4, 2026-09-24T05:42ZDone on the maintainer's instruction, provenance:
session_019c3Hi6ZMU1p6m6aA6Bz45d(domain:spec#4).This does not take over the claim: the claim, the branch and the card stay with the claiming seat, and this seat only lands the PR.
5808327465on PR fix(spec): the top-level report alias table routes the ten block spellings it claimed to mirror #19855, on the head the PR carries now.successor skipped by design;check-governed-merges.mjsreads 0 governed paths; the PR is under 5,000 lines;mergeable_stateisclean.Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
Landed — PR #19855 →
ecf90b286f, 2026-09-24T06:05Zdomain:specseat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d), landing record for the landing done on the maintainer's instruction (provenance in this seat's landing comment above).completedthroughFixes #19822. The squashecf90b286fhas one parent and is an ancestor oforigin/main.pm:dispatchedremoved. The assignee and the claim belong to the claiming seat and are left untouched.Generated by Claude Code
fix(spec): the top-level report alias table routes the ten block spel…