Repository navigation
docs(skills): objectstack-automation teaches the read-only record_link screen field, with an eval prompt - #26446
Conversation
…nk` screen field, with an eval prompt The `screen` node row of SKILL.md teaches `type: 'record_link'`: the field shows the `reference` record whose id `defaultValue` evaluates to, as a link to its record page, and takes no input — both keys required, the five input keys refused, a resume value under its name refused — with the one result-screen example over a `create_record` `outputVariable`, and the two workarounds an author otherwise reaches for (a completed `end` `message`, a markdown link in a screen `description`). One eval prompt (id 9) covers the result screen. The Filter operands bullet's restatement of item 1's refusal detail is cut; the two touched token-ratchet rows move by the measured remainder under the maintainer's ruling A. Claude-Session: https://claude.ai/code/session_01JQwxbYLKc8xxih9Em65LNW Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewReviewed at 2026-10-27T04:13Z by the independent contract-review subagent, on the PR's one commit, read adversarially against the card, the spec and the engine on Served-tier: Method: every reading is ① Derived judgments(a) Every new sentence is true of the spec and the engine on
(b) The one cut is a genuine duplicate with a surviving home. Filter operands bullet, L209–210: "every other (c) Ratchet rows pinned at the measurement; ruling A applied and quoted. Hand audit on the blobs: SKILL.md head 24674 bytes, stamp line L16 (d) Eval 9. The file parses; ids 1–9 unique and sequential; entry 9 has the same key set as entry 8 ( (e) Card Wanted met, nothing beyond. Teach: shape ✓, two required keys ✓, five refused keys ✓, resume refusal ✓, (f) PR body. Line 1 the harness attribution HTML comment, line 2 the harness (g) Report shape and claim. os-dev-report 6433471282 (2026-10-27T04:05Z) carries every key of the os-dev.md template on the head plus ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读改了什么:objectstack-automation 技能的 席位核对ACCEPT ·
Generated by Claude Code |
…ide #26446) PR #26448 went dirty after #26446 (d1a31d0) raised the objectstack-automation rows of scripts/check-skills-token-ratchet.mjs beside the objectstack-platform rows this branch re-pins. Resolved by keeping both sides: main's sibling rows and this card's rows; nothing else conflicted. check:skills-token-ratchet exit 0, --self-test exit 0 (79 cases). Claude-Session: https://claude.ai/code/session_01JQwxbX1XjSzpntF9n85TgB Co-authored-by: Claude <noreply@anthropic.com>
Requested by Warren · project thread
Fixes #26347
Clause-②: no
Metadata-protocol: none
维护者速读
skills/objectstack-automation/SKILL.md的screen节点行(L91)教只读的屏幕字段type: 'record_link':它显示reference对象里 id 等于defaultValue求值结果的那条记录(按显示名,链接到记录页),不收输入;reference与defaultValue必填,required/options/placeholder/min/max拒收,恢复时在它名下带值拒收(400 INVALID_SCREEN_INPUT);附一个结果屏示例(defaultValue: { dialect: 'cel', source: 'account.id' }读create_record的outputVariable),并点明两种会被拒或原样显示的替代写法。eval 文件加第 9 题(卡上原题)。棘轮脚本两行上限按实测调整,裁决原文写在行旁;「Filter operands」小节删去一句重复 item 1 的话。record_link落进@objectstack/spec,技能没教。AI 作者写「创建完成后显示新记录链接」的结果屏时,会去写 completedend的message(被 spec 拒收)或在屏幕description里写 markdown 链接(runner 原样显示成文字)。skills/objectstack-automation/SKILL.mdL91screen行的新增子句;②scripts/check-skills-token-ratchet.mjs两行上限及注释;③evals/flows-triggers-approvals.json第 9 题。node scripts/check-skills-token-ratchet.mjs→ 看到skills/objectstack-automation/SKILL.md is 6164 tokens (ceiling 6164; headroom 0)与flows-triggers-approvals.json is 2141 tokens (ceiling 2141; headroom 0),末行authored bundle file(s) within their ceilings。skills/**),请 approve 或直接 Merge when ready。What changes
Card #26347's 「What is owed」 section, and nothing wider:
SKILL.mdL91, thescreennode row (the one home — the row already enumeratesconfig.fields[]and teaches thefilemember, so an author writing a screen flow's result screen reads it):'record_link'(never'record', an object field type) takes no input — it shows thereferencerecord whose iddefaultValueevaluates to, by display name, as a link to its record page; the one example{ name: 'account_link', type: 'record_link', reference: 'crm_account', defaultValue: { dialect: 'cel', source: 'account.id' } }over acreate_recordoutputVariable: 'account'; both keys required;required/options/placeholder/min/maxrefused; a resume value under its name refused (400 INVALID_SCREEN_INPUT); a completedendmessageis refused and a markdown link in a screendescriptionrenders literally. Every clause was read from the merged code, not the card:packages/spec/src/automation/builtin-node-config.zod.ts(SCREEN_FIELD_RECORD_LINK_TYPE,…_REFERENCE_REQUIRED,…_DEFAULT_VALUE_REQUIRED,SCREEN_FIELD_RECORD_LINK_REFUSED_KEYS, thesuperRefineat the field, andEndConfigSchema's refusal ofmessageon a completed end),screen-field-record-link.test.ts,packages/services/service-automation/src/builtin/screen-record-link-resume.test.ts(theaccount.idspelling overoutputVariable: 'account',INVALID_SCREEN_INPUT),screen-input-contract.ts, the error-code ledger (400), andui/packages/app-shell/src/views/FlowRunner.tsx(thedescriptionis a plain text child of the dialog description).evals/flows-triggers-approvals.json: entry 9, the card's prompt verbatim; the ideal answer names thescreenflow, twocreate_recordnodes withoutputVariable, the lastscreenof twotype: 'record_link'fields withreferenceanddefaultValue: { dialect: 'cel', source: 'account.id' }/'contact.id', norequired/placeholder/options, no completed-endmessage, no markdown link in thedescription; assertions as the card gives them. The expected output is written so that it never spells eithermust_not_containstring (it says "never the object field type" instead of the negated spelling).SKILL.mdL209–210, Filter operands — the one genuine duplicate cut: the bullet restated Valid-but-silently-wrong item 1's refusal detail (expression-invalid, "with its envelope"); the surviving home is item 1 at L233–235, which names the gate, the error id and the CEL spelling the refusal carries. −41 bytes.scripts/check-skills-token-ratchet.mjs, the two objectstack-automation rows only, under the maintainer's ruling on the seat's decision card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, tap A (2026-10-27 01:21Z), verbatim and untranslated: 「A:先削重复,余额按实测提高」. Step one, duplicates cut first: the one above inSKILL.md; the eval file's eight fixtures share no sentence (0 bytes to cut). Step two, each row follows its measurement (ceil(utf8 bytes / 4),SKILL.mdminus its 20-byte stamp line):SKILL.mdpriced bytes 24014 → 24654 (+681 added, −41 cut, +640 net), 6004 → 6164 (headroom was 2 bytes, 0 tokens; +160);evals/flows-triggers-approvals.json7289 → 8561 bytes (+1272), 1823 → 2141 (headroom was 3 bytes, 0 tokens; +318). Both pinned AT the measurement, each comment quoting the tap. Rows measured againstorigin/main75afeffd(skills(objectstack-platform): teachdemoStaffand when to pick it overdevLogins#26420 landed), the branch's base; no other package's row is touched.references/_index.mdis generator-owned (gen:skill-refs) and unchanged (no schema moved).references/examples-flows.mdis untouched (the row held the teaching).SKILL.mdline 1 is untouched (#25640 owns the stamp). #26362 (the approval-lock read) is the next card on this package and is not taught here.Two readings (lines, and tokens as the ratchet counts them):
SKILL.mdevals/flows-triggers-approvals.json(not .md, reported for the raise)SKILL.md+references/**/*.md, 4 files; the package has norules/)Removed: the Filter operands restatement only.
skip-changeset: the published skills packages carry nopackage.json; nothing is released from any package.Why
The key landed in
@objectstack/specwith PR #26355 (4548ba34e6) and the skill did not teach it, so an AI author asked for a result screen reached for a completedendmessage(refused at parse) or a markdown link in the screendescription(shown as literal text).Metadata-protocol: none: the protocol already carries the key; the gap was the teaching.Tests
node scripts/check-skills-token-ratchet.mjs— exit 0: both touched rows at headroom 0,81 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.node scripts/check-skills-token-ratchet.mjs --self-test— exit 0,79 cases pass.pnpm --filter @objectstack/spec run check:skill-docs,check:skill-refs,check:skill-examples— see Verification. The new teaching is a table cell (inline code), so noos:checkblock was added; the example count stays as onmain.must_containstring occurs in its expected output and neithermust_not_containstring occurs in the prompt or expected output.Acceptance notes
evals/README.md, if it enumerates the eval topics, was not updated; not read, not filed: observation only.Fixes #26347follows immediately.Verification
Gate list derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon the final tree (base75afeffd, headc9e57c28), each run locally with the exit code captured before any pipe;--ranreconciliation below. No commit followed the gate runs, so every reading is ofc9e57c28.Reconciliation (
node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack): exit 0 —53 derived famil(ies) accounted for — 52 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3), 0 UNRUN.The one NOT MEASURED is
pnpm check:dual-build-cjs-loads(exit 3: its prerequisite is a whole-repo build; this diff touches no package source, and CI'sLint & Repo Gatesruns it — a declared narrowing). The closures forcheck:skill-examplesandcheck:doc-formula-expressions(@objectstack/client...,@objectstack/client-react...,@objectstack/lint...,@objectstack/formula...) were built underscripts/pm/os-verify-lock.sh(slotissue-26347,VERDICT command-exit 0, 276 s held, 0 s waited);check:dts-closureandcheck:lean-entry-closureran after that build (38 built package(s) swept - 160/160 declared declaration file(s) present).node scripts/check-comment-mask-corpus.mjsran in the serial cheap runner, never besidecheck:skill-examples.check:pm-dispatch-gatesran detached on the final head: fast tier,1901 cases pass, exit 0. Two runs are outside the derivation and recorded anyway:check:skill-refsandcheck:skill-examples, the card's acceptance gates (the eval file and the row are the only skill edits; the example count stays at 264).Every command with its exit code on c9e57c2 (55 lines: the 53 derived, plus `check:skill-refs` and `check:skill-examples`)
node scripts/check-ci-filter-parity.mjs— exit 0node scripts/check-closing-keyword-parity.mjs— exit 0node scripts/check-closing-keyword-parity.mjs --self-test— exit 0node scripts/check-comment-mask-corpus.mjs— exit 0node scripts/check-declaration-mirrors.mjs— exit 0node scripts/check-declaration-mirrors.mjs --self-test— exit 0node scripts/check-doc-route-spelling.mjs --advisory— exit 0node scripts/check-doc-route-spelling.mjs --self-test— exit 0node scripts/check-dts-emitted.mjs --self-test— exit 0node scripts/check-scripts-symbol-anchors.mjs— exit 0node scripts/check-scripts-symbol-anchors.mjs --self-test— exit 0node scripts/check-self-test-wired.mjs— exit 0node scripts/check-self-test-wired.mjs --self-test— exit 0node scripts/check-self-test-workflow-commands.mjs— exit 0node scripts/check-self-test-workflow-commands.mjs --self-test— exit 0node scripts/check-skills-token-ratchet.mjs— exit 0node scripts/check-skills-token-ratchet.mjs --self-test— exit 0node scripts/check-whole-set-label-write.mjs— exit 0node scripts/check-whole-set-label-write.mjs --self-test— exit 0node scripts/ci/assert-turbo-remote-cache.mjs --self-test— exit 0node scripts/ci/plan-test-core-shards.mjs --self-test— exit 0node scripts/ci/prune-turbo-cache.mjs --self-test— exit 0node scripts/pm/bare-root-worklist.mjs --self-test— exit 0pnpm check:agent-test-spelling— exit 0pnpm check:bash32-floor— exit 0pnpm check:cli-command-ids— exit 0pnpm check:corpus-claim-drift— exit 0pnpm check:cross-package-test-inputs— exit 0pnpm check:doc-authoring— exit 0pnpm check:driver-memory-census— exit 0pnpm check:entry-guard— exit 0pnpm check:gitlink-declared— exit 0pnpm check:merge-driver— exit 0pnpm check:nul-bytes— exit 0pnpm check:parse-guard— exit 0pnpm check:pm-governed-merges— exit 0pnpm check:pm-skill-id-lint— exit 0pnpm check:pnpm-filter-targets— exit 0pnpm check:pnpm-flag-spellings— exit 0pnpm check:ratchet-remedy-authority— exit 0pnpm check:refd-timer-probe— exit 0pnpm check:role-word— exit 0pnpm check:skill-compatibility— exit 0pnpm check:skill-frame-sync— exit 0pnpm check:skill-identifier-liveness— exit 0pnpm check:sourcemap-no-sources-content— exit 0pnpm check:watch-hint-literal— exit 0pnpm --filter @objectstack/spec run check:skill-docs— exit 0pnpm --filter @objectstack/spec run check:skill-refs— exit 0pnpm --filter @objectstack/spec run check:skill-examples— exit 0pnpm --filter @objectstack/lint run check:doc-formula-expressions— exit 0pnpm check:dts-closure— exit 0pnpm check:lean-entry-closure— exit 0pnpm check:dual-build-cjs-loads— NOT MEASURED (exit 3, PREREQUISITE NOT MET: whole-repo build; CI's Lint & Repo Gates runs it)pnpm check:pm-dispatch-gates— exit 0Token ratchet on c9e57c2
skills/objectstack-automation/SKILL.md is 6164 tokens (ceiling 6164; headroom 0)skills/objectstack-automation/evals/flows-triggers-approvals.json is 2141 tokens (ceiling 2141; headroom 0)81 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.--self-test:79 cases pass.check:skill-examples on c9e57c2
264 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them(unchanged frommain: the new teaching is a table cell, not anos:checkblock).Human Minimum
Each item is one rule from CONTRIBUTING.md › Human Minimum.
packages/specholds no runtime logic. (No schema change.)pnpm lintis CI's run (repo-wide scan).main, one pull request.skip-changeset); both declaration lines are filled in above.packages/specnot touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code