Skip to content

docs(skills): an objectstack-data eval relabels a vendor field with fieldPatches, never by redeclaring it in fields - #30941

Merged
os-zhuang merged 3 commits into
mainfrom
claude/project-thread-7ld3bj
Nov 6, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/project-thread-7ld3bj

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

domain:skills#2 · os-tesla · session_01L9qibyYUF3Rw1uw6uU1yUy

Fixes #28804

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:skills/objectstack-data/evals/objects-fields-relationships.json 新增第 7 例:装了 HotCRM 后,作者想让 crm_account.industry 字段显示为 "Sector"。标准答案是在配对包 hotcrm.custom 里写 defineObjectExtension({ extend: 'crm_account', fieldPatches: { industry: { label: 'Sector' } } });必含 fieldPatches、hotcrm.custom、extend: 'crm_account'、label: 'Sector'、defineObjectExtension,禁含把 industry 在 fields 里重新声明(industry: Field.select()、overrides:、name: 'crm_account'。另加一条 changeset。技能正文零改动。
  • 为什么改:技能的〈Object Extension Model〉教了"改厂商字段的显示用 fieldPatches,不要在 fields 里重声明",但没有任何评测覆盖它;以后为付 token 棘轮而删掉这段,什么都不会红。这一例让这条教学有了守门。
  • 风险与回滚:只加一个评测夹具用例与一条 changeset,不改技能文本、不改运行时;评测夹具不计入 token 棘轮(裁决 6513306068 B)。回滚即 revert。
  • 先看:skills/objectstack-data/evals/objects-fields-relationships.json 第 7 例(expected_output 的每句都对照 main 上 SKILL.md 〈Object Extension Model〉与 packages/objectql/src/registry.ts 的 patchedField 写成);.changeset/28804-data-eval-field-patches.md。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs,预期 skills/objectstack-data/evals/objects-fields-relationships.json is 2150 tokens — eval fixture, measured but not ratcheted,skills/objectstack-data/SKILL.md is 6087 tokens (ceiling 6123) 不变;再 grep -c "label: 'Sector'" skills/objectstack-data/SKILL.md 得 1,证明每个必含 token 都在技能里教过。
  • 需要你做的:本 PR 触 skills/**(Tier H),需要受管审批人在 GitHub 上 Approve 一次;之后席位落地。

What changes

skills/objectstack-data/evals/objects-fields-relationships.json: case 7, appended after case 5's crm_account extension (the fixture whose topic cluster holds object extensions; hooks-security-seeds-datasources.json has no extension case).

  • Prompt: HotCRM installed; its crm_account object's industry field should read "Sector" instead of "Industry", without touching HotCRM's source.
  • Expected output: defineObjectExtension({ extend: 'crm_account', fieldPatches: { industry: { label: 'Sector' } } }) authored in hotcrm.custom and registered in objectExtensions; a patch carries display keys only (label, description, inlineHelpText, placeholder), the field's type, values and rules stay HotCRM's, a tenant-edited key keeps the tenant's text; never redeclare industry in fields (takes the field over, cuts it off from upgrades, and an unsuffixed field in a .custom extension is refused anyway); an option's label rides the same patch keyed by the option's stored value only for a field with its own options, a picklist-bound field's options are never patchable, a patch naming a field or option value the target lacks is refused at install and by os validate.
  • must_contain: hotcrm.custom, defineObjectExtension, extend: 'crm_account', fieldPatches, label: 'Sector'. Each appears as a whole token in skills/objectstack-data/SKILL.md on main (1, 2, 1, 4, 1 hits; checked with the IDENT_CHAR boundary rule of ui/scripts/check-skill-eval-tokens.mjs, whose own population is skills/objectui only, so the check for this bundle is by hand).
  • must_not_contain: industry: Field.select( (the take-over spelling: HotCRM's field is Field.select), overrides: (replacing the object whole), name: 'crm_account' (redeclaring the object). None names a mechanism a right contrasting answer must spell.

.changeset/28804-data-eval-field-patches.md: '@objectstack/skills': patch, both declaration lines.

Every sentence of the expected output states what main does: skills/objectstack-data/SKILL.md 〈Object Extension Model〉 (the whitelist, the take-over rule, the __c refusal, the picklist rule), packages/spec/src/data/object.zod.ts (FieldDisplayPatchSchema, refuseFieldPatchOfReplacedField, fieldPatchesDescription), packages/objectql/src/registry.ts patchedField (the picklist-bound options skip), packages/metadata-core/src/extension-field-patch-targets.ts (the field / option / picklist-option misses the install door and os validate refuse by).

Readings (os-dev rule for skills/**):

Reading Before (origin/main 4d56914a) After
skills/objectstack-data/evals/objects-fields-relationships.json lines 120 140
same file, tokens (check-skills-token-ratchet, eval fixture: measured, not ratcheted) 1749 2150
skills/objectstack-data/SKILL.md lines / tokens 465 / 6087 (ceiling 6123) unchanged
Package, all 11 skills/*/SKILL.md, lines 4525 unchanged

No ceiling row moves; no skill text is added or deleted.

Why

#28804: an out-of-scope finding of PR #28795 (card #28730, which added the fieldPatches paragraph and is closed completed). With no eval, a later trim made to pay the token ratchet could drop the paragraph and nothing would fail. Evals sit outside the ratchet (ruling record 6513306068 B), so the case costs no skill text.

Tests

No runtime code changes. The fixture parses as JSON (7 cases, ids 1–7); the case's own expected_output contains every must_contain token and none of the must_not_contain tokens (self-check script in the thread).

Acceptance notes

Verification

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack against the two-file diff at 73639a7c (branch base origin/main 4d56914a, unchanged at push time, so no merge was needed). Every line run with stdin closed, exit codes landed on disk first: 40 derived families, 40 run, 40 exit 0; dispatch-gates --ran reconciliation: 40 derived, 40 run, 0 NOT-MEASURED, 0 UNRUN. Ran list: skills-seat-2/out/28804-gates-ran-73639a7c.list in the project files.

Gate readings at 73639a7
  • check-skills-token-ratchet: skills/objectstack-data/evals/objects-fields-relationships.json is 2150 tokens — eval fixture, measured but not ratcheted; skills/objectstack-data/SKILL.md is 6087 tokens (ceiling 6123; headroom 36), unchanged; 57 authored bundle file(s) within their ceilings, exit 0.
  • check:skill-identifier-liveness, check:skill-compatibility, check:skill-frame-sync, check-empty-changeset --base origin/main, check-changeset-no-major --base origin/main, check-adr-0087-registration --base origin/main, check:pm-governed-merges, check:doc-authoring, check:nul-bytes, check:role-word, check-closing-keyword-parity, check-comment-mask-corpus, the rest of the 34 no-build families: exit 0.
  • Six dist-reading families after a declarations build of ./packages/** under the verify lock (VERDICT command-exit 0, 7m27s): check:dual-build-cjs-loads (116 published require entry point(s) across 71 package(s) load; 2456 emitted CommonJS file(s) parse), check:lean-entry-closure, check:dts-closure (241/241 declared declaration file(s) present), check:published-files, check:sourcemap-no-sources-content, @objectstack/lint check:doc-formula-expressions: exit 0.
  • ui/scripts/check-skill-eval-tokens.mjs: exit 0 (Every must_contain token is taught by its own skill bundle; population skills/objectui only, see Acceptance notes).
  • Tier: dispatch-gates --tier on the two paths: skills/** clause ①, claude-fable-5-1 mandated, no one-line exit; this thread runs on it. check-governed-merges --test on the two paths: Tier H.

CI families (Lint & Repo Gates, Test Core, the rest) are the PR's check-runs, not re-run locally.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint is CI's run (no source file in the diff).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L9qibyYUF3Rw1uw6uU1yUy

…ield with fieldPatches

Case 7 of objects-fields-relationships.json: an author wants HotCRM's
crm_account.industry to read "Sector". The accept set requires
fieldPatches on a defineObjectExtension in hotcrm.custom; it refuses
industry redeclared in fields, which takes the field over.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibyYUF3Rw1uw6uU1yUy
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 6, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibz5RLVEYDFco93jZ7u

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 73639a7c48d12b5348553051869e3c4d2033c003
Local-runs: none
Scope: skills/objectstack-data/evals/objects-fields-relationships.json + skills/objectstack-data/SKILL.md (§ Object Extension Model, main 33043bd), packages/spec/src/data/object.zod.ts (FieldDisplayPatchSchema, refuseFieldPatchOfReplacedField, fieldPatchesDescription), packages/objectql/src/registry.ts (patchedField, applyFieldPatches), packages/metadata-core/src/extension-field-patch-targets.ts, docs/adr/0146 D10, hotcrm objectstack.config.ts / src/sales/objects/account.object.ts / src/sales/picklists/industry.picklist.ts, .changeset/29969-platform-push-eval.md (semver precedent). Remainder of the diff (.changeset/28804-data-eval-field-patches.md): the lane seat's ACCEPT at TIER_DEFAULT.

① Derived judgments

  • Accept set, case 7 must_contain (hotcrm.custom, defineObjectExtension, extend: 'crm_account', fieldPatches, label: 'Sector'): each is a whole token (IDENT_CHAR rule of ui/scripts/check-skill-eval-tokens.mjs) in skills/objectstack-data/SKILL.md on main 33043bd — 1 / 2 / 1 / 4 / 1 hits, lines 347–372. The dev's by-hand count is reproduced. Right. Note: label: 'Sector' and extend: 'crm_account' are taught at line 364 ONLY, so any rewrite of that example (③ below) must keep both tokens or cases 5 and 7 go untaught.
  • Accept set, must_not_contain industry: Field.select(: HotCRM's field is Field.select({ label: 'Industry', group: 'basic', picklist: 'industry' }) (account.object.ts L311–318), so this is the copy-the-vendor's-declaration take-over spelling the skill forbids (SKILL.md L355–357). Right as far as it reaches — narrow, see ④ should-fix 1. overrides: and name: 'crm_account': the same pair case 5 already refuses; a right answer spells neither (SKILL.md's own name: 'crm_account' at L86 is the namespace rule, not an extension). Right.
  • Prompt facts: hotcrm namespace crm (hotcrm objectstack.config.ts L92), object crm_account (account.object.ts L8), field industry labelled "Industry". Right; the prompt is the card's reach line verbatim.
  • expected_output claims vs the live tree: display-only whitelist label / description / inlineHelpText / placeholder (SKILL.md L357–359, fieldPatchesDescription reads BASE_FIELD_DISPLAY_WHITELIST); tenant's text wins (patchedField tenantPatched, ADR-0029 D9.2a); redeclaring in fields takes the field over and both-at-once is refused (refuseFieldPatchOfReplacedField); unsuffixed field in a .custom extension refused (SKILL.md L369–372, ADR-0146 D10); option label keyed by stored value only for a field with its own options, picklist-bound options never patchable (patchedField skips when picklistBound; fieldPatchTargetMisses reason picklist-option); refused at install and by os validate (header of extension-field-patch-targets.ts). Every sentence holds. Right.
  • Self-consistency: the case's expected_output contains all five must_contain tokens and none of the three must_not_contain tokens (checked by reading the hunk; no in-repo gate covers this bundle — check-skill-eval-tokens walks skills/objectui only). Right.
  • Public surface: no skill text, schema or runtime change; an eval fixture is inert in a consumer install (skills/README.md anatomy) and measured, not ratcheted (check-skills-token-ratchet population 1b, ruling record 6513306068 B). SKILL.md 6087 tokens unchanged. Right.

② Semver level

.changeset/28804-data-eval-field-patches.md: '@objectstack/skills': patch, Clause-②: no, Metadata-protocol: none; the PR body carries the same two lines. An eval-only addition to the published bundle is a patch, as the precedent .changeset/29969-platform-push-eval.md (platform skill eval, case 12) set. Check Changeset: success. Clause-②: no — right: no capability is declared or narrowed; the declaration face owes nothing more.

③ Boundary flags

  • open_questions: [] — none raised; none found owed.
  • Dev out-of-scope finding (class c) — SKILL.md L364 example patches options of crm_account.industry, which is picklist-bound. CONFIRMED on both trees. main 33043bd SKILL.md L364 reads defineObjectExtension({ extend: 'crm_account', fieldPatches: { industry: { label: 'Sector', options: { technology: { label: 'Tech' } } } } }); hotcrm main account.object.ts L311–318 declares industry: Field.select({ ..., picklist: 'industry' }) with no inline options, and src/sales/picklists/industry.picklist.ts holds technology. fieldPatchTargetMisses (extension-field-patch-targets.ts) returns reason picklist-option for any options key on a field whose picklist is a non-empty string, so the install door and os validate refuse a verbatim copy ("Remove options from this patch"), and the registry fold's patchedField skips it (!picklistBound). Reach is WIDER than the dev named: the same example sits in packages/spec/src/data/object.zod.ts fieldPatchesDescription() (L4997–4998) AND the TSDoc at L5013, in content/docs/references/data/object.mdx L581 (generated from the description — fix at source only), and hand-authored content/docs/data-modeling/object-extensions.mdx L104–115, which contradicts its own L149–150 ("a field whose options come from a shared picklist has no option labels of its own to patch"). packages/spec/CHANGELOG.md L3649 shows a prior fix changed tech to technology but left the picklist binding. The dev's "noted, not filed" does not discharge it: a follow-up card is owed (domain:skills + spec prose; the filing must keep label: 'Sector' and extend: 'crm_account' as whole tokens in SKILL.md, ① note). Out of scope here: the dispatch order forbade a SKILL.md edit.
  • Does case 7's accept set inherit the refusal? No. The accept set neither requires nor refuses options:, so an answer that copies L364 verbatim is neither rewarded nor penalised; what is in scope is the reference answer's wording, judged in ④ (should-fix 2). Tightening the accept set to refuse an option patch on industry must wait for the L364 rewrite — until then it would red the skill's own taught example and contradict the card's Wanted ("with any option keyed by a stored value").
  • Acceptance note: no runner; check-skill-eval-tokens population is skills/objectui only. Answered by this review's own whole-token count (① first bullet). Not a gap this card can close.
  • Acceptance note: overlap with docs(skills): the data skill's Field Groups section teaches a group's visibleWhen and requiresFeature #30890 / docs(skills): the objectstack-data field-types formula row says a formula is no dataset or cube dimension (group key) either #30921 / Bare-name phase 2: the published authoring skills teach one rule, every metadata name carries the namespace (ruling C on #30798) #30805. Different files; compare/main...73639a7c is ahead 1, behind 0 at review time — no merge owed.
  • Tier H (skills/**): a governed approver's GitHub approval is owed before merge; whole-PR, outside this record.
  • Check-runs on the head (13:02Z): every completed non-skipped run is success — Lint & Repo Gates, TypeScript Type Check, Build Core, Test UI, Dogfood Regression Gate, Live E2E UI, all Lint · and Type Check · families, Check Changeset, Check PR Size, PR-body guards, Governed Surface Queue Guard, Auto Label. Test Core (1/8) and (2/8) were still in_progress; the diff holds no runtime code, so they cannot be moved by it, and ACCEPT waits on their conclusion as usual.

④ Design judgment

skills/objectstack-data/evals/objects-fields-relationships.json, case 7 — against the card's eval prompt and the spec it teaches on main:

  • Against the card: the prompt is the reach line; fieldPatches on a defineObjectExtension in hotcrm.custom is required; the redeclaration is refused in its taught spelling; option-by-stored-value is stated (prose, correctly unasserted — the prompt asks for no option relabel). Holds.
  • Against the code (① fourth bullet): every claim in expected_output is what registry.ts, object.zod.ts and extension-field-patch-targets.ts do today. Holds.
  • Fixture shape (id, prompt, expected_output, files: [], assertions) matches cases 1–6; ids 1–7 unique; the hunk is valid JSON (the trailing-comma placement is right). Holds.

Trying to break it:

  • Should-fix 1 — must_not_contain industry: Field.select( catches only the Field.select take-over. A redeclaration that also changes the type (industry: Field.text({ label: 'Sector' })) is a worse take-over and passes the accept set. industry: Field. is a strictly broader token at zero cost: its last character is not an IDENT_CHAR so the whole-token rule treats it as a prefix, and the right answer fieldPatches: { industry: { label: 'Sector' } } never spells it. Not a FAIL: the taught failure mode (copying the vendor's declaration into fields) is the Field.select spelling, and the card's Wanted is met for it.
  • Should-fix 2 — the reference answer for a prompt about crm_account.industry spells options: { technology: { label: 'Tech' } }, the exact patch HotCRM's industry is refused for (reason picklist-option), hedged only as "only for a field that declares its own options" without saying that industry is not one. The answering agent gets no HotCRM source (files: []), so a grader reading the reference literally can accept an answer that patches industry's options. Either drop the concrete technology / Tech spelling from this case's expected_output (keep the rule as prose) or state that HotCRM's industry takes its options from the industry picklist. Not a FAIL: the accept set is not moved by it, and the root is SKILL.md L364 (③, follow-up card).
  • Must-fix: none found.

Implemented-by: claude/project-thread-7ld3bj
Reviewed-by: session_01L9qibz5RLVEYDFco93jZ7u

VERDICT: PASS

…pelling on a picklist-bound field

Contract review should-fixes on PR #30941: must_not_contain now refuses
any `industry: Field.` redeclaration, not only the select one; the
expected output states that HotCRM's industry takes its options from a
picklist, so no options entry belongs on the patch.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibyYUF3Rw1uw6uU1yUy
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibz5RLVEYDFco93jZ7u

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 894478ff68198fb2dec7505ce7bf6e0d1b21a09f
Local-runs: none
Scope: skills/objectstack-data/evals/objects-fields-relationships.json + skills/objectstack-data/SKILL.md (§ Object Extension Model, main 33043bd), ui/scripts/check-skill-eval-tokens.mjs (wholeTokenPattern, the must_not_contain shape-only rule), packages/metadata-core/src/extension-field-patch-targets.ts, packages/objectql/src/registry.ts (patchedField), hotcrm src/sales/objects/account.object.ts / src/sales/picklists/industry.picklist.ts. Remainder of the diff (.changeset/28804-data-eval-field-patches.md, unchanged): the lane seat's ACCEPT at TIER_DEFAULT.

Delta record on the earlier record for head 73639a7 (comment 6685496287): judges only what moved. Everything that record found right and did not move stands.

What moved: fix commit 66ef62e (+2 −2, case 7 only) and merge commit 894478f (parents 66ef62e and origin/main 33043bd). Net diff main...894478ff: ahead 3, behind 0, the same two files, +10 / +20.

① Derived judgments

  • Accept set, must_not_contain industry: Field.select( → industry: Field.. Under wholeTokenPattern the first character i is an IDENT_CHAR (left boundary asserted) and the last character . is not (exact substring on the right), so the token is a prefix match: it catches industry: Field.select(, industry: Field.text( and every other Field.* take-over of industry in fields. The right answer fieldPatches: { industry: { label: 'Sector' } } does not spell it; no file under skills/ spells industry: Field at all (grep, main tree), so no guide sentence an answer might quote trips it; the only spelling in reach is HotCRM's own account.object.ts L311, which is the vendor source the prompt forbids touching. check-skill-eval-tokens shape-checks must_not_contain only (header § "must_not_contain is NOT validated against the guides, deliberately") — a non-empty string passes. Right; should-fix 1 closed.
  • Accept set, must_contain: untouched (five tokens, 1 / 2 / 1 / 4 / 1 whole-token hits in SKILL.md on 33043bd). Unchanged, right.
  • expected_output: the options: { technology: { label: 'Tech' } } spelling is gone; the new sentence reads "HotCRM's industry takes its options from the industry picklist, and a picklist-bound field's options are never patchable, so no options entry belongs on this patch." True on hotcrm main: account.object.ts L311–318 industry: Field.select({ label: 'Industry', group: 'basic', picklist: 'industry' }), no inline options; src/sales/picklists/industry.picklist.ts definePicklist({ name: 'industry', ... }). True on objectstack main: fieldPatchTargetMisses returns reason picklist-option for any options key on a field whose picklist is a non-empty string ("Remove options from this patch"), applied at the install door and by os validate; patchedField skips options when picklistBound. The conditional rule for a field with its own options is kept as prose, so the card's Wanted ("with any option keyed by a stored value") is still stated. Right; should-fix 2 closed.
  • Self-consistency at 894478f: the case's expected_output contains all five must_contain tokens and none of the three must_not_contain tokens (industry: Field. is absent — the reference spells industry: {). Fixture parses; ids 1–7. Right.
  • The merge: compare/66ef62e0...894478ff brings exactly .changeset/30512-service-settings-locales-b.md, packages/services/service-settings/src/translations/{de,ko,ru}.ts, translations/index.ts, settings-translation-coverage.test.ts — service-settings translations, as the dev said. None touches this PR's files, skills/** or packages/spec; the net diff against main is unchanged in file list and line counts. Right.

② Semver level

Unchanged: .changeset/28804-data-eval-field-patches.md '@objectstack/skills': patch, Clause-②: no, Metadata-protocol: none. The fix moves two strings inside an eval fixture; nothing new publishes. Check Changeset on 894478f: success. Clause-②: no — still right.

③ Boundary flags

  • Both should-fixes of the earlier record are closed on the tree (① bullets 1 and 3). No new dev flag; no open_questions; no fix-round os-dev-report on the card or PR at review time — the dev's account reached this review by relay only, and the tree was judged, not the account.
  • Should-fix (PR body, prose remainder, not a hits file): the PR body still says must_not_contain is industry: Field.select( (L27 and the maintainer summary) and that the expected output "keeps the options form conditional"; both are now false on the tree. Update the body so its account matches 894478f. Not a FAIL: the body is read, never reviewed, and the tree is right.
  • The follow-up card owed for SKILL.md L364 / fieldPatchesDescription() / object-extensions.mdx (earlier record ③) is unchanged by this head and still owed; the fix did not touch SKILL.md, so label: 'Sector' and extend: 'crm_account' remain taught at L364.
  • Tier H (skills/**): a governed approver's GitHub approval is still owed before merge; mergeable_state: blocked.
  • Check-runs on 894478f (13:17Z): 40 runs — 25 completed/success, 13 completed/skipped, 2 in_progress (Test Core (1/8), Test Core (2/8)). Every completed non-skipped run is success: Lint & Repo Gates, TypeScript Type Check, Build Core, Test UI, Dogfood Regression Gate, Live E2E UI, all Lint · and Type Check · families, Check Changeset, Check PR Size, PR-body guards, Governed Surface Queue Guard, Auto Label, Plan Test Core shards, filter. The two pending shards read runtime code this PR does not change (the merge's translation files are main's, already green there); ACCEPT waits on their conclusion as usual.

④ Design judgment

skills/objectstack-data/evals/objects-fields-relationships.json, case 7 at 894478f — only the two moved strings re-judged against the card's prompt and the spec on main:

  • The widened refusal industry: Field. makes the card's Wanted ("refuses an industry redeclared in fields") hold for every Field.* spelling of the take-over, not only the vendor's Field.select, at no cost to a right answer. Holds.
  • The reference answer now says of the prompt's own field that its options come from the industry picklist and that no options entry belongs on the patch — the exact verdict extension-field-patch-targets.ts renders — so a grader reading it literally can no longer accept an option patch on industry. The answering agent, with files: [], is still fairly graded: the skill teaches the picklist rule (SKILL.md L361–363), and the accept set does not require the agent to know HotCRM's binding. Holds.
  • Trying to break it: a take-over spelled without the builder (industry: { type: 'select', ... }) still passes the accept set; no builder-free spelling is taught anywhere in the bundle, so no token is owed for it. Not a finding.
  • Must-fix: none. Should-fix in the hits file: none.

Implemented-by: claude/project-thread-7ld3bj
Reviewed-by: session_01L9qibz5RLVEYDFco93jZ7u

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-tesla · session_01L9qibz5RLVEYDFco93jZ7u

维护者速读

  • 改了什么:数据技能评测 objects-fields-relationships.json 加第 7 题:作者想把 HotCRM 的 crm_account.industry 显示成 "Sector"。正确答案是在对象扩展里用 fieldPatches 只改 label;在 fields 里重新声明 industry(任何 Field.*)算接管字段,判错。题目说明 HotCRM 的 industry 选项来自 industry 选项列表,不能打补丁。另有 changeset。
  • 为什么改:技能里「对象扩展」一段教 fieldPatches,但没有评测守着;以后为省 token 删掉这段也不会有任何东西报错。
  • 风险与回滚:只加一道评测题和 changeset,不改技能文字、不碰运行时;评测不计入 token 上限。回滚即 revert。
  • 先看:skills/objectstack-data/evals/objects-fields-relationships.json 第 7 题的 must_contain / must_not_contain。
  • 两分钟验证:node ui/scripts/check-skill-eval-tokens.mjs(CI 里的 Skill Eval Token Check)应通过,第 7 题的 must_contain 词都在技能文字里。
  • 需要你做的:改的是 skills/**,属于 Tier H,需要 os-zhuang(或 hotlong)批准后才能合并。契约复审 PASS 6685496287,补改后增量复审 PASS 6685772270。

席位意见:契约复审 PASS,两条建议修改都已补上,增量复审无发现。复审另查出技能里 fieldPatches 的示例本身在 HotCRM 上会被拒(改的是选项列表绑定字段的选项),已另开 #30944,不在本 PR。可以批准。

席位核对

ACCEPT · seat domain:skills#2 · head 894478ff · 2026-11-06T13:28Z

  1. Shape: Fixes #28804, draft, base main, 2 files (skills/objectstack-data/evals/objects-fields-relationships.json case 7, .changeset/28804-data-eval-field-patches.md '@objectstack/skills': patch), fix commit 66ef62e0 plus a merge of main 33043bd8 (which brought only service-settings translations; net diff is still the two files).
  2. Ruling: filing gate ② on skills(objectstack-data) evals: no eval exercises an object extension, so nothing checks that an author patches a vendor field's display with fieldPatches instead of taking it over in fields #28804, an out-of-scope finding of PR docs(skills): objectstack-data teaches an object extension's fieldPatches — relabel a vendor field without redeclaring it in fields #28795; blocker skills(objectstack-data): teach an object extension's fieldPatches in the Object Extension Model section, once #28565 applies them #28730 closed completed; triage 6684785520 (p3); Claim 6685069739.
  3. Contract review: PASS 6685496287 at 73639a7c (no must-fix, two should-fixes). Delta PASS 6685772270 at 894478ff (same reviewer, both closed): must_not_contain widened to industry: Field. (catches every Field.* takeover; the right answer spells industry: {, nothing under skills/ spells industry: Field); expected_output drops the options: { technology: … } spelling and says HotCRM's industry is picklist-bound (hotcrm account.object.ts Field.select({ …, picklist: 'industry' }); fieldPatchTargetMisses reason picklist-option on main). Clause-②: no, Metadata-protocol: none.
  4. Corrected facts (PR body not patched): the body cites head 73639a7c, says must_not_contain is industry: Field.select( and that the expected output keeps the options form conditional; on this head the token is industry: Field. and the expected output carries no options entry.
  5. Gates / check-runs: dev reports 40/40 derived families exit 0 at 73639a7c and again 40/40 at 894478ff (--ran: 0 NOT-MEASURED, 0 UNRUN; list skills-seat-2/out/28804-gates-ran-894478ff.list); report 6685331902. On head 894478ff: 41 check-runs, 28 success, 13 skipped, 0 failed; mergeable_state clean.
  6. Accepted deviations: none. Residue filed as skills+spec: the taught fieldPatches example patches crm_account.industry's options, but HotCRM's industry is picklist-bound, so a copy is refused at install #30944 (the taught fieldPatches example at SKILL.md L364, the spec's fieldPatchesDescription() and two docs pages patch a picklist-bound field's options); its rewrite must keep label: 'Sector' and extend: 'crm_account', which this case's must_contain reads.
  7. Landing: GOVERNED, Tier H (skills/**). The seat readies the PR and the relay's governed-review leg requests the approvers; no auto-merge is armed by the seat.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 6, 2026 14:11
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 6, 2026
Merged via the queue into main with commit 1c34fd7 Nov 6, 2026
42 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-7ld3bj branch November 6, 2026 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

2 participants