Repository navigation
feat(spec): a field group's requiresFeature hides the group where a deployment feature is off; Edit organization hides Parent Organization and Sort Order on one organization - #30810
Conversation
…en; sys_organization hides group structure on one organization Claude-Session: https://claude.ai/code/session_016WV4cyCnzVPr9GuD38DdGt Co-authored-by: Claude <noreply@anthropic.com>
…; book it in the feature registry Claude-Session: https://claude.ai/code/session_016WV4cyCnzVPr9GuD38DdGt Co-authored-by: Claude <noreply@anthropic.com>
…dle; regenerate spec references; changeset Claude-Session: https://claude.ai/code/session_016WV4cyCnzVPr9GuD38DdGt Co-authored-by: Claude <noreply@anthropic.com>
…it on the object form, regenerate api-surface and export-origins Claude-Session: https://claude.ai/code/session_016WV4cyCnzVPr9GuD38DdGt Co-authored-by: Claude <noreply@anthropic.com>
…unt the new requiresFeature row Claude-Session: https://claude.ai/code/session_016WV4cyCnzVPr9GuD38DdGt Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 3 package(s): 30 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 16 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 170 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 2766081a635df0940d339bfa43378180379935fd && git checkout 2766081a635df0940d339bfa43378180379935fd
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 100303c0430eb644506970270a0134db304b7cbb 24375ec421c30b753b543f58a6e1727eca34dd2b && git checkout -B drift-repro 100303c0430eb644506970270a0134db304b7cbb && git merge --no-ff 24375ec421c30b753b543f58a6e1727eca34dd2b
node scripts/docs-audit/affected-docs.mjs --json 100303c0430eb644506970270a0134db304b7cbb
|
|
domain:server#5 · os-elon-musk · session_016WV4cyvF7SP65frVFAYLv7 Contract reviewServed-tier: Inputs: card #30692 (body, triage 6671686007, claims 6675467698 / 6675514573 / 6675727155, dev report 6677017944), ruling 6670372892 on #30210 (row 4 A), PR #30810 body and file list (28 files, +533/-33), the net diff against merge-base 2d04cd2, and the check-runs on the head. Nothing was built, run or re-run locally. ① Derived judgments
② Semver level
③ Boundary flagsThe dev report lists no open questions. Deviations, each judged:
④ Design judgmentpackages/spec/src/data/object.zod.ts — HOLDS against the ruling (row 4 A: a field-group-level packages/spec/src/data/object.form.ts — HOLDS. One row on the packages/spec/src/kernel/public-auth-features.ts — HOLDS. The slot argument defaults to Findings:
No must-fix. The Check-runs on the head at the time of this read: no gate-carrying run red; Implemented-by: VERDICT: PASS |
Requested by Elon · project thread
Fixes #30692
Clause-②: yes
Metadata-protocol: added
Skills-docs: follow-up owed — skills/objectstack-data/references/examples-objects.md (its Field Groups section teaches
fieldGroupsand should namevisibleWhenandrequiresFeaturebesidecollapse); kept out of this diff so it does not become a governedskills/**change维护者速读
requiresFeature(与动作上的同名键同一套特性名),解析时降成该分组的visibleWhen并从输出中去掉;组织对象声明了四个字段分组,「上级组织」「排序」所在的「集团结构」组要求multiOrgEnabled。packages/spec/src/data/object.zod.ts(新键与降级 transform);packages/lint/src/validate-expressions.ts的withoutLoweredFeatureGate(lint 只放行降级出来的那一个门);packages/platform-objects/src/identity/sys-organization.object.ts(四个分组)。pnpm --filter @objectstack/platform-objects exec vitest run src/identity/sys-organization-group-structure-gate.test.ts,预期 4 条全绿:multiOrgEnabled关时两字段不出现,开时出现。What changes
@objectstack/spec:fieldGroups[].requiresFeature. The field-group twin of the action-levelrequiresFeature, from the samePUBLIC_AUTH_FEATURESvocabulary, so an unknown flag is refused at parse (invalid_valueatrequiresFeature). It is lowered at parse into the group'svisibleWhenby the same helper the action key uses,lowerRequiresFeature, which now takes an optional third argument naming the slot ('visible'by default,'visibleWhen'here); its refusals name that slot. The key is stripped from the output.visibleWhen: "record.kind == 'child'"+requiresFeature: 'multiOrgEnabled'parses to(record.kind == 'child') && features.multiOrgEnabled != false. A non-CELvisibleWhenrefuses the pair, as for actions.PUBLIC_AUTH_FEATURES.multiOrgEnabled.gatedInputsbookssys_organization.fieldGroups.group_structure; thegatedInputspath grammar admitsOBJECT.fieldGroups.KEY, and the platform-objects completeness guard walks field groups in both directions.object.form.tsoffers the key on thefieldGroupsrepeater (label and help in en / zh-CN / ja-JP / es-ES). Liveness:object/fieldGroups.requiresFeatureislive.@objectstack/lint: the lowered gate is accepted. The field-groupvisibleWhenroot verdict now judges the predicate with the trailing gate arequiresFeaturelowers to taken off (withoutLoweredFeatureGate): the gate alone, or(AUTHORED) && GATEwhere the authored part parses on its own. Any otherfeaturesread in a group predicate keeps its root verdict, and its message now points atrequiresFeature. The finding still quotes the whole predicate.@objectstack/platform-objects:sys_organizationdeclaresfieldGroups. Identity, Branding, Configuration, Group Structure, in the fields' own order, so no field moves;id/created_at/updated_atkeepgroup: 'System', which is not declared, so they render last in the ungrouped bucket as before. Group Structure (parent_organization_id,sort_order) carriesrequiresFeature: 'multiOrgEnabled'. Section labels are translated in zh-CN / ja-JP / es-ES.The ui is unchanged, as the ruling says: the form's section gate and the record page's
record:details(ui/packages/plugin-detail/src/renderers/record-details.tsxsectionPredicateVisible) both evaluate a group'svisibleWhenwithusePredicateScope(), which carries the host'sfeatures.Tests
main(1371b9d8, the object before this PR, tests from this PR):sys-organization-group-structure-gate.test.ts3 failed / 1 passed; withmultiOrgEnabled: falsethe flat layout still rendersparent_organization_id.packages/spec/src/data/field-group-requires-feature.test.ts(lowered and stripped; an opt-in flag gets its own gate; unknown flag refused atrequiresFeature; both-present AND-composition from a string and from an envelope; unchanged without the key; insideObjectSchema.create),packages/platform-objects/src/identity/sys-organization-group-structure-gate.test.ts(off hides, on shows, only that group gated, declaration order kept), and a#30692describe in the lint harnessruntime-gate.object-field-group-visibility-writes.test.ts(three lowered shapes publish clean at the door and the build; the unlowered key is clean; five hand-writtenfeaturesshapes keep the verdict; the prescription namesrequiresFeature).ab3d3a94:@objectstack/spec818/818 files, 25833 tests;@objectstack/lint195/195, 8226;@objectstack/platform-objects117/117, 1585; the three typechecks exit 0;check:generatedexit 0.Ablations (one per changed behaviour)
dist/:scripts/ablation-replace.mjsreplaced the transform with one that keeps the group and plantsABLATION_30692(anchor 1 → 0, blob47ddc173→c0bfefc3); spec rebuilt;ablation-dist-preflight.mjsfound the marker in 10 built files. Red: spec pin 4 failed / 2 passed; platform-objects 4 failed (the three group-structure cells and the guard's forward rowsys_organization.fieldGroups.group_structure is gated on multiOrgEnabled). Restored to the HEAD blob withgit diff HEADempty; spec rebuilt; preflight--absentclean over 592 files and the tree; the same two files green, 118/118.rawinstead ofwithoutLoweredFeatureGate(raw)(anchor 1 → 0, blob7b9a6ec1→85289f1e). Red: the three lowered-shape CONTROL cells; restored to the HEAD blob,git diff HEADempty.Acceptance notes
featuresroot is not opened on group predicates generally (ruling row 4 B was not chosen): only the exact trailing gate the lowering emits is accepted. A hand-written predicate byte-identical to that lowered form is accepted too, because it is the same gate.features(any section predicate that faults hides its group). The console publishes it on both surfaces; a host without it would hide Group Structure on a multi-organization deployment as well.multiOrgEnabledis on.id,created_atandupdated_atkeep their undeclaredgroup: 'System'(thefield-group-undeclaredadvisory fires for those three, where before it fired for all twelve fields); declaring a System group would surfacecreated_at/updated_aton the record page, a change the card did not ask for.Verification
Head
24375ec4(branch merged withorigin/main2d04cd2bafter #30753 landed; clean merge, no conflict), after a whole-treeturbo run build(exit 0):node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 105 families on24375ec4; all 105 exit 0.--ran: 105 derived, 105 run, 0 NOT-MEASURED, 0 UNRUN.pnpm lint,pnpm check:cli-command-ids,pnpm check:adr-symbol-anchors: exit 0. Local-onlycheck:dev-prereqs,check:skill-frame-freshness: exit 0.node scripts/check-i18n-bundles.mjs: in sync.@objectstack/spec818/818 files, 25834 tests;@objectstack/lint195/195, 8235;@objectstack/platform-objects117/117, 1589.!in the title, no narrowing arm).packages/platform-objects/src/apps/translations/{en,es-ES,ja-JP,zh-CN}.ts; this PR touches the*.objects.generated.tsand*.metadata-forms.generated.tsbundles beside them, not those files.🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4cyCnzVPr9GuD38DdGt