Uh oh!
There was an error while loading. Please reload this page.
feat(spec): declare placeholder on FieldSchema — Option C ruling on objectui#4676 (#9019) - #9113
Merged
Merged
Conversation
…bjectui#4676 (#9019) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01225pUjnCKWqxcc1PeqKFUq
…ldschema-placeholder
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 106 hand-written doc(s) reference the affected code — list omitted above 15 rows. Re-derive: ⛔ 7 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.
|
This was referenced Aug 16, 2026
…ldschema-placeholder
…e placeholder form entries (#9019) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01225pUjnCKWqxcc1PeqKFUq
os-zhuang
marked this pull request as ready for review
August 16, 2026 11:38
Uh oh!
There was an error while loading. Please reload this page.
os-zhuang pushed a commit
that referenced
this pull request
Aug 16, 2026
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01225pUjnCKWqxcc1PeqKFUq
os-project-manager pushed a commit
that referenced
this pull request
Aug 17, 2026
…upling walkMetadataForms (packages/cli/src/utils/i18n-extract.ts) emits the metadataForms i18n surface from two producers: METADATA_FORM_REGISTRY (the 17 *.form.ts modules, already covered by the form-module convention entry in dispatch-gates.mjs) and DEFAULT_METADATA_TYPE_REGISTRY plus the METADATA_FORM_REGISTRY module itself (packages/spec/src/kernel/ metadata-plugin.zod.ts, packages/spec/src/system/metadata-form-registry.ts). Editing either of the latter two moves the same platform-objects bundles PR #9113 had to regenerate, and derived nothing from dispatch-gates. Both are exactly two known files, not a runtime-enumerated population, so this closes the gap the same way SURFACE_MODULE and check-type-check-coverage.mjs's ROOT_PROGRAM_COUPLED_SCRIPT already do: two bare module-body path-literal constants declared directly in check-i18n-bundles.mjs (the script check:i18n resolves to), read by the ordinary path-literal derivation with no new CHANGE_KIND_GATES entry. Pinned live in dispatch-gates.mjs's own self-test (existsSync + a matched classifyEntry verdict for each), so a renamed or moved registry module reddens that self-test instead of the derivation silently going blind on this edge again. Fixes#9144
This was referenced Aug 17, 2026
akarma-synetal pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Aug 17, 2026
…ts + keepHead/keepTail, enforced on the FieldMasker channel (objectstack-ai#8993) (objectstack-ai#9128) * feat(spec,plugin-security): partial field masking — maskingRule presets + keepHead/keepTail, enforced in FieldMasker (objectstack-ai#8993) Re-introduces the 2026-06-pruned maskingRule key WITH its runtime consumer in the same PR (ADR-0049 declare = enforce; maintainer ruling 2026-08-16 Option A): - spec: FieldMaskingRuleSchema — closed preset enum (phone/id_card/ bank_account/email/name) + keepHead/keepTail escape hatch; guidance tombstone flipped (the objectstack-ai#9019 placeholder precedent); liveness row live with evidence; authoring forms; regenerated artifacts. - plugin-security: maskFieldValue (deterministic, length-preserving, idempotent); maskResults REPLACES masked-for-caller fields instead of deleting (requiredPermissions is the unmask gate — same ADR-0066 D3 evaluation; explicit permission-set denies still delete); predicate + aggregate guards refuse masked-field probes (the equality oracle); detectMaskedEchoWrites refuses masked round-trip writes with 400 VALIDATION_ERROR; getReadableFields keeps masked columns in the projection so export headers match served rows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01225pUjnCKWqxcc1PeqKFUq * test(rest): pin export screen-vs-CSV parity for partial masking; add changeset (objectstack-ai#8993) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01225pUjnCKWqxcc1PeqKFUq * regenerate artifacts on the merged tree (post-objectstack-ai#9113 merge) (objectstack-ai#8993) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01225pUjnCKWqxcc1PeqKFUq * gates: ADR-0122 alias form + Iso850 pin; translate the new maskingRule form strings (objectstack-ai#8993) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01225pUjnCKWqxcc1PeqKFUq --------- Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Aug 17, 2026
…bjectstack-ai#9143) * fix(pm): derive check:i18n from a metadata form module edit (objectstack-ai#9116) A `.form.ts` change in packages/spec moves platform-objects' committed metadata-form bundles, but no derived gate list could name check:i18n for it: the gate walks packages/ for extract configs, packages/spec owns none, and the gate's own path literals are its CLI/stale-dist prerequisites. The family scored neither matched nor undetermined — printed nowhere. PR objectstack-ai#9113 paid one CI round trip plus a patch commit for that edge. Two changes, one contract: - scripts/i18n-bundle-surface.mjs — the config walk and the docstring-flag parse move here and BOTH readers import them. dispatch-gates used to carry a hand-written mirror of the gate's walk, described in its own comment as mirroring it "exactly": a second contract that agrees until one side moves, with nothing to report the day it stops. - a second convention entry in CHANGE_KIND_GATES for a metadata form module, with the population walked at runtime and the applicability read from the configs' own documented flags — the day every config passes --no-metadata-forms, no form module can move a committed bundle and the entry stops firing by itself. Both consumers declare the shared module as a bare module-body constant, the shape check-type-check-coverage.mjs already uses: an import specifier is not a discoverable watch hint, so without it a card editing the shared enumeration would move two gates while deriving neither — the same blind spot one layer down. Pinned live in the tool's self-test, both directions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm * test(pm): fail the metadata-form cases by name, not on a TypeError (objectstack-ai#9116) Reverse-verifying the new entry by making every extract config opt out emptied the rendered lines, and the bare `formHit[0]` crashed the whole self-test — one stack in place of 183 named verdicts, hiding every other finding behind it. Same fallback discipline check-i18n-bundles.mjs states for its own classifiers. Ablated again after the fix: 5 named failures, all of them the new claims, nothing else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm * docs(pm): cite the filed follow-up for the uncovered type-registry edge (objectstack-ai#9116) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm --------- Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Aug 17, 2026
…upling (objectstack-ai#9219) walkMetadataForms (packages/cli/src/utils/i18n-extract.ts) emits the metadataForms i18n surface from two producers: METADATA_FORM_REGISTRY (the 17 *.form.ts modules, already covered by the form-module convention entry in dispatch-gates.mjs) and DEFAULT_METADATA_TYPE_REGISTRY plus the METADATA_FORM_REGISTRY module itself (packages/spec/src/kernel/ metadata-plugin.zod.ts, packages/spec/src/system/metadata-form-registry.ts). Editing either of the latter two moves the same platform-objects bundles PR objectstack-ai#9113 had to regenerate, and derived nothing from dispatch-gates. Both are exactly two known files, not a runtime-enumerated population, so this closes the gap the same way SURFACE_MODULE and check-type-check-coverage.mjs's ROOT_PROGRAM_COUPLED_SCRIPT already do: two bare module-body path-literal constants declared directly in check-i18n-bundles.mjs (the script check:i18n resolves to), read by the ordinary path-literal derivation with no new CHANGE_KIND_GATES entry. Pinned live in dispatch-gates.mjs's own self-test (existsSync + a matched classifyEntry verdict for each), so a renamed or moved registry module reddens that self-test instead of the derivation silently going blind on this edge again. Fixesobjectstack-ai#9144 Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#9019
Implements the maintainer ruling of 2026-08-16 (Option C on objectui#4676, 「主线1 3 4:同意」):
placeholderbecomes a declared optional string key onFieldSchema, with the semantics the four shipped objectui render surfaces already implement (measured in objectui#4676 report comment 5301288148: plugin-form, plugin-detail, app-shellresolveActionParams, apps/console FormPage — feeding the@object-ui/fieldswidgets).What changed
packages/spec/src/data/field.zod.ts—placeholderdeclared next toinlineHelpText,.describe()prose carries the three-way distinction (in-input placeholder that disappears on typing, vsinlineHelpTextalways-visible help beside/under the input, vsdescriptiontooltip/developer docs), with a doc comment recording the ruling and the measured consumers.packages/spec/src/data/authoring-key-lint.ts— theFIELD_KEY_GUIDANCEretirement entry ("never a FieldSchema key. Author hint text throughinlineHelpTextordescription.") is REMOVED, replaced by a NOTE comment recording the flip. Note: the prescription prose lived here (folded intoFieldSchema'sstrictObjectguidance options viafieldKeyGuidanceAsStrictOptions()), not literally infield.zod.tsas the card assumed — same table region the dispatch warned about, one file over. Theauthoring-key-lint.test.tsno-rot pin ("no guidance entry names a key the schema now declares") makes leaving the entry a red build, so the flip is gate-enforced, not convention.packages/spec/src/data/object.form.ts+field.form.ts— the "placeholderremoved: never a FieldSchema key" tombstone comment in object.form.ts is replaced with the actual form field entry, and the full per-field editor (field.form.ts) offers the key too. Bounded same-class completion, named here per the in-place exemption: the object.form.ts comment was mandated prose-flip surface; the field.form.ts row makes the declared key authorable in the editor the reconciliation test names as "where the long tail of FieldSchema is authored". Both entries are validated bymetadata-form-zod-reconciliation.test.ts(form-only direction).packages/spec/liveness/field.json—liverow withevidenceScope: "cross-repo"citing the measured objectui read points @9ce096fb0 (the ledger gate demands a row for every newly authorable property; evidence format follows the existingprecisioncross-repo row).state-counts.mdregenerated.authorable-surface/data.jsongainsdata/Field:placeholder(base anchor lag is the allowed informational state);content/docs/references/data/field.mdxregenerated wholesale viagen:docs— the new row renders the distinction.field.test.tsgains an accept-side describe block — parse + round-trip, coexistence of all three hint keys, optional-stays-absent, non-string rejection, no type-restriction (flat like scale/min), unknown-key strictness undisturbed,.describe()prose pin via JSON Schema, and the object-document shape that used to 422 onPUT /api/v1/meta/object/:name.@objectstack/spec(accept-set expansion on a published surface), with the ADR-0087 not-required annotation (purely additive).Reverse verification (direction: rejection flips to acceptance)
Pre-change probe on unmodified
origin/main@9bf110fb6, built dist:{name,label,type:'text'}control SUCCESS;+placeholderFAILunrecognized_keyswith the exact "never a FieldSchema key" prescription;+inlineHelpText/+descriptionSUCCESS. Post-change probe on the rebuilt dist:+placeholderSUCCESS and round-trips; non-stringplaceholderstill rejects. This is the expected direction for an accept-set expansion — the old reject-with-prose pin is gone (guidance entry removed, enforced by the no-rot gate) and the accept side is pinned infield.test.ts.#9088 same-file churn
#9088 (currency guidance in the same
field.zod.tsguidance region) landed mid-task as predicted;origin/mainre-merged after it (merge commit7cb089f37), clean merge, both semantics verified present: thecurrencyguidance entry survives in theguidance:block and theplaceholderdeclaration stands. Full spec suite re-run green after the merge.Verification (all at final HEAD
7cb089f37, after the merge commit)@objectstack/specfull suite: 406 files, 10771 tests, all passed. Typecheck green.@objectstack/spec, named explicitly): rest 2001 ✓, objectql 3730 ✓, lint 2065 ✓, metadata 603 ✓, metadata-core 162 ✓, metadata-fs 51 ✓, metadata-protocol 1565 ✓ — zero fixture flips needed (no consumer fixture pinned the field-levelplaceholderrejection; searched).node scripts/pm/dispatch-gates.mjsagainst the actual diff and run in full: changeset-gate-self-tests, cross-package-test-inputs (both forms), docs-audit-scope, docs-redirects, merge-driver, objectui-changeset, quick-reference-counts, role-word, spec-parsed-alias, type-source-resolution, nul-bytes, adr-0087-registration, changeset-no-major, empty-changeset, dev-prereqs, doc-formula-expressions, query-options-erasure, engine-double-contract, where-matcher, type-check-coverage, type-check-debt (workspace closure built via turbo first, 70/70), spec check:api-surface / check:authorable-surface / check:docs / check:generated / check:liveness / check:export-origins — all EXIT=0. Beyond the prompt's list, the derivation added the changeset/docs families (changeset-gate-self-tests, objectui-changeset, adr-0087, no-major, empty-changeset, docs-audit-scope, docs-redirects, quick-reference-counts, role-word) — all run, all green.validate: app-crm, app-showcase, app-todo — all EXIT=0 (pre-existing draft-flow warnings only).objectui side per the ruling: zero code change expected there; objectui#4676 unblocks on the release + pin bump.
Generated by Claude Code
Generated by Claude Code