Repository navigation
docs(skills): the objectstack-ui report example declares its download in exportOptions under the base object's allowExport - #27318
Conversation
… in exportOptions under the base object's allowExport The Report Configuration example in rules/dashboards.md taught dateRange and not exportOptions. The example now declares exportOptions with formats csv / xlsx and names the optional includeHeaders / fileNamePrefix in a trailing comment; the note block says who may download is the base object's permission-set allowExport and that a joined report takes neither dateRange nor exportOptions. Paid under the token ratchet by folding the dateGranularity bullet (taught under Server-side date bucketing) and the drilldown sentence (taught under Drilldown): 6221 -> 6214 tokens, ceiling untouched. Claude-Session: https://claude.ai/code/session_01QSeKYmhU5KEj1nukYhp1Tg Co-authored-by: Claude <noreply@anthropic.com>
…port-export-options
|
domain:skills#2 · os-justin · session_01QSeKYmhU5KEj1nukYhp1Tg Contract-review-claim: session_01QSeKYmhU5KEj1nukYhp1Tg · head 94cb20a · 2026-10-28T16:38Z |
|
domain:skills#2 · os-justin · session_01QSeKYmhU5KEj1nukYhp1Tg Contract reviewServed-tier: Claim line 6474877580 on this head (2026-10-28T16:41Z); no earlier record or claim on it. Read at 2026-10-28T16:41Z by the ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: PASS |
|
domain:skills#2 · os-justin · session_01QSeKYmhU5KEj1nukYhp1Tg 维护者速读 — 席位终稿 · PR #27318 · head
|
Fixes #26777
Clause-②: no
Metadata-protocol: none
维护者速读
skills/objectstack-ui/rules/dashboards.md〈Report Configuration〉的defineReport示例在dateRange下加一行exportOptions: { formats: ['csv', 'xlsx'] },行尾注释点名可选的includeHeaders/fileNamePrefix;注释块加一句:exportOptions只声明下载,谁能下载是基对象权限集上的allowExport,joined报表既不接受dateRange也不接受exportOptions。token 棘轮用同文件折叠支付:删掉〈Server-side date bucketing〉已教过的dateGranularity一条和〈Drilldown〉已教过的drilldown一句;文件 6221 → 6214 tokens,上限 6221 不动。dateRangeandexportOptions#26774 为卡 skills(objectstack-ui): no eval teaches a report's dateRange / exportOptions, because both ui eval files sit at their token ceiling (follow-up owed by #26548) #26633 落地的 eval 要求报表声明exportOptions并以allowExport命名下载权限,而技能规则只教dateRange;照技能写报表的 agent 没有下载声明的样例,可能自造permissions.export这类键或漏掉导出。改后 eval 若失败只会是 agent 的错,不再是教学的缺口。skills/objectstack-ui/rules/dashboards.mdL419–421(注释块新句,措辞即契约)、L401(示例新行)、原 L406–409 与 L414–415 的删除(折叠是否真有第二处);.changeset/26777-report-export-options-rule.md。node scripts/check-skills-token-ratchet.mjs,预期打印skills/objectstack-ui/rules/dashboards.md is 6214 tokens (ceiling 6221; headroom 7)并以 0 退出。skills/**受管面,Tier H;PR 保持 draft,由席位落地)。What changes
One governed rule file and one changeset.
skills/objectstack-ui/rules/dashboards.md〈Report Configuration〉 — the report section the skill routes to (SKILL.mdL148 points at this file for report config):defineReportexample gains one line underdateRange(the diff below):exportOptionswithformats: ['csv', 'xlsx'], and a trailing comment naming the optionalincludeHeaders/fileNamePrefix. Every key is read offpackages/spec/src/ui/report.zod.tsonorigin/main: the report'sexportOptionsisReportExportOptionsSchema.optional()whose describe reads "Report export control:{ formats?, includeHeaders?, fileNamePrefix? }, csv / xlsx, on by default; who may export is the base object's export permission (refused on a joined report)";formatsadmits exactly'csv' | 'xlsx'(the reverse leg under Tests shows'pdf'refused by the type).exportOptionsdeclares the download, never who may download — that is the base object's permission-setallowExport; ajoinedreport takes neitherdateRangenorexportOptions. It is the schema's own docblock shortened — "Who may export is NOT declared here — there is no report permission key. The control is offered to a viewer whose effective API operations on the dataset's base object includeexport: theObjectPermission.allowExportaxis" — plus the two joined-container refusalsJOINED_CONTAINER_DATE_RANGE_REFUSEDandJOINED_CONTAINER_EXPORT_OPTIONS_REFUSED. The example writes noallowExport: trueanywhere:allowExportis named in words as a permission-set key, which is what the eval'smust_not_containguards.dateGranularitybullet (old L406–409): its meaning lives in 〈Server-side date bucketing —dateGranularity(ADR-0021)〉 — the lead paragraph (the dataset dimension carries it; selecting it groups server-side; without it every timestamp becomes its own category) and the five-value bucket table — in the Level A table under 〈Dataset-Bound Widgets〉 (date-bucketday/week/month/quarter/yearfits a dataset; a computed bucket escalates), and in the example's own comment two lines above the call (close_datewithdateGranularity: 'quarter');drilldownsentence (old L414–415): its meaning lives in 〈Drilldown〉 — "Reports drill the same way. Asummary/matrixreport (drilldowndefaultstrue) opens the identical in-place drawer on row/cell click".rows/columnsaxis sentence and theordernuances (bymust be a selected name; list thecolumnskey first) have no second home in the file beyond the example's inline comments, so they stay. One further candidate was left for a later shrink: the example'sordercomment ("by measure; dates default to chronological") restates the note's ASCENDING sentence..changeset/26777-report-export-options-rule.md:@objectstack/skillspatch — the published bundle is built fromskills/**(packages/skillsshipsdist, itsbuildissync-catalog.mjs) — both declaration lines at line start, one sentence.Not touched, by the ruling:
scripts/check-skills-token-ratchet.mjs(thedashboards.mdrow stays 6221 — the standing ruling 「A:先削重复,余额按实测提高」 has no locatable comment id, so no raise; the file now sits 7 tokens under its ceiling, so none is needed either) andskills/objectstack-ui/evals/**(the eval already expects this teaching).The edited region, before → after
Skills readings (
skills/**touched; before =origin/maina0aa8a1, the branch base; after = head; tokens in the ratchet'sceil(utf8 bytes / 4)convention):rules/dashboards.mdlines / bytes / tokensskills/objectstack-ui/**linesSKILL.mdlinesskills/**tree linesWhy
The eval landed by PR #26774 for card #26633 (
skills/objectstack-ui/evals/report-period-export.json) scores a report-authoring answer onexportOptionswith'csv'/'xlsx'and onallowExportnamed in words, and refusespermissions.export,canExport,allowExport: trueand'pdf'. Onorigin/mainthe rules teachdateRangeand nothing about the download (git grep -n "exportOptions\|allowExport" skills→ hits only underevals/), so an agent authoring from the skill had no example of the declaration and the eval could fail for a gap in the teaching rather than in the agent. The premise held on the branch base a0aa8a1: the same grep, the same zero hits underrules/**.Tests
node scripts/check-skills-token-ratchet.mjs— before:skills/objectstack-ui/rules/dashboards.md is 6221 tokens (ceiling 6221; headroom 0); after:… is 6214 tokens (ceiling 6221; headroom 7),82 authored bundle file(s) within their ceilings, exit 0 both runs. Its--self-testexit 0.pnpm --filter @objectstack/spec check:skill-examples(the gate that type-checks everyos:checkblock; it ispackages/spec's script, run by CI after the workspace build, and not in thedispatch-gates --commandslist for this diff) — after building@objectstack/specand the@objectstack/client-react...closure underscripts/pm/os-verify-lock.sh(VERDICT command-exit 0, held 73 s and 264 s):✅ 270 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them, exit 0. Soformats: ['csv', 'xlsx']as string literals is accepted bydefineReport's input type (hypothesis 4 holds).node scripts/ablation-replace.mjs --file skills/objectstack-ui/rules/dashboards.md --anchor "formats: ['csv', 'xlsx'] }" --replacement "formats: ['csv', 'pdf'] }" -- pnpm --filter @objectstack/spec check:skill-examples: mutation landed on disk (anchor 1 → 0, blob b5223630 → afe444cb), the gate went red witherror TS2322: Type '"pdf"' is not assignable to type '"csv" | "xlsx"', command exited 1; restored by the tool, then proven: the on-disk blob hash equals the HEAD blob (b5223630913e881657aac13fe9d2ad21757779e1),git diff HEADempty,git statusclean. Expected direction red; observed red. No permanent test file left.test/typecheckis owed; no test file edited. The eval JSON is executed by no gate (the repo has no eval runner).Acceptance notes
exportOptionswithformats'csv' | 'xlsx',includeHeaders?,fileNamePrefix?, and the joined refusals atreport.zod.tsL187–207 — confirmed, quoted above; (2)content/docs/references/ui/report.mdxL71 and L116–122 teach the same keys — confirmed (a generated reference page; the rule text here is shorter); (3) the folds — confirmed fordateGranularityanddrilldown; therows/columns/orderwording was not a restatement and stays; (4) theos:checkcompile — confirmed, with the reverse leg; (5) the derived gate list carried 43 families and did not namecheck:pm-governed-prose(the diff touches neitherAGENTS.mdnor the governed register), so it was not run.origin/mainmoved from a0aa8a1 (the branch base) to d4427ae (oneui/packages/componentstest commit) while the branch was open; merged in as 94cb20a with no overlap on any touched surface, and the gate union below ran on that head.Verification
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat head94cb20ad(the final commit, derived from the merge base with no paths passed) printed 43 commands, identical to the derivation before theorigin/mainmerge. All 43 ran sequentially in the worktree after that commit, each exit captured before any pipe (bash -c "$cmd" >> log 2>&1; EXIT=$?): 42 exit 0 — among themnode scripts/check-skills-token-ratchet.mjsand its--self-test,node scripts/check-empty-changeset.mjs --base origin/main,node scripts/check-adr-0087-registration.mjs --base origin/main,node scripts/check-changeset-no-major.mjs --base origin/main,node scripts/check-closing-keyword-parity.mjs,pnpm check:changeset-gate-self-tests,pnpm check:pm-governed-merges,pnpm check:published-files,pnpm check:skill-compatibility,pnpm check:skill-frame-sync,pnpm check:skill-identifier-liveness,pnpm check:doc-authoring,pnpm check:role-word,pnpm check:corpus-claim-drift,pnpm check:nul-bytes,pnpm check:pm-skill-id-lint,pnpm check:dts-closure,pnpm check:lean-entry-closure; 1 exit 3 —pnpm check:dual-build-cjs-loads, PREREQUISITE NOT MET ("some package has no dist/": 33 packages, it asks for a whole-workspacepnpm build), NOT MEASURED locally; CI'sLint & Repo Gatesruns it after its build.dispatch-gates --ran:✓ dispatch-gates --ran: 43 derived famil(ies) accounted for — 42 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3), exit 0.pnpm check:dev-prereqsread this box as not fully built (68 of 106 packages withoutdist; exit 1) — a state of the worktree, not of the diff, since only@objectstack/specand theclient-reactclosure were built here;check:skill-frame-freshnessis not implicated (no four-axis framework file touched).pnpm lint, the type-check lanes and the path-scheduled jobs are CI's runs on this PR.git rev-parse --short HEAD= 94cb20a.Human Minimum
Each item is one rule from
CONTRIBUTING.md › Human Minimum,
which links the AGENTS.md text that states it.
packages/specholds no runtime logic. (No schema touched.)pnpm lintpasses (the repo-wide run is CI's; no source file edited).main, one pull request.packages/spectouched: n/a, not touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01QSeKYmhU5KEj1nukYhp1Tg
Generated by Claude Code