Found while implementing #13072 (site 1), which collapsed the form-view predicate
root vocabulary to one list. Filed unassigned; recording only, and out of scope
for that card's PR (#13348), whose file surface was fenced to the detector module
plus the pins its change forces.
What the operator now reads
MetadataPlugin._warnUnboundFormPredicateRoots
(packages/metadata/src/plugin.ts) prints the bound vocabulary per surface,
and only for the surfaces the findings implicate:
const surfaces = new Set(findings.map((f) => f.surface));
const vocabulary = [
surfaces.has('field')
? `on a form FIELD: ${quote(BOUND_FORM_FIELD_PREDICATE_ROOTS)}`
: null,
surfaces.has('section')
? `on a form SECTION: ${quote(BOUND_FORM_VIEW_PREDICATE_ROOTS)}`
: null,
].filter(Boolean).join('; ');
Since #13072, those two constants are the same list — a section binds
current_user and its ADR-0068 aliases too (objectui#6110 + #6111), so
BOUND_FORM_FIELD_PREDICATE_ROOTS is BOUND_FORM_VIEW_PREDICATE_ROOTS by
identity. An artifact that carries findings on both slots therefore gets the
identical eight roots printed twice in one line:
(bound roots on a form FIELD: 'record', 'previous', 'parent', 'data', 'current_user', 'user', 'ctx', 'os'; on a form SECTION: 'record', 'previous', 'parent', 'data', 'current_user', 'user', 'ctx', 'os')
Nothing there is false. What it costs is that the per-surface framing implies a
distinction the platform does not currently make, in a notice whose whole design
value is that an operator trusts it. The single-surface cases are unaffected and
read correctly.
Why it was not fixed in #13348
Collapsing the two arms to one flat clause changes operator-facing output and
moves the two not.toContain('form FIELD') / not.toContain('form SECTION')
assertions in packages/metadata/src/plugin-unbound-form-predicate-roots.test.ts
that pin which arms print. That is a deliberate output decision rather than the
mechanical consequence of the contract re-measurement, and #13072's dispatch
narrowed the file surface to the detector module. #13348 corrected the stale
comment beside this code (it claimed the vocabularies differ) and left the
logic alone.
Suggested shape, if triage wants it
Print one clause when the two lists are equal ("bound roots on any form-view
predicate: ..."), keep the per-surface arms when they differ. That keeps the
structure honest in both worlds and needs the two pin assertions updated in
place. Alternatively: leave it, on the grounds that the per-surface arms cost
one duplicated clause and survive a future divergence for free. Both are
defensible; this is not a correctness question.
Measured on origin/main at merge base a286411df plus the diff of #13348.
Generated by Claude Code
Generated by Claude Code
Found while implementing #13072 (site 1), which collapsed the form-view predicate
root vocabulary to one list. Filed unassigned; recording only, and out of scope
for that card's PR (#13348), whose file surface was fenced to the detector module
plus the pins its change forces.
What the operator now reads
MetadataPlugin._warnUnboundFormPredicateRoots(
packages/metadata/src/plugin.ts) prints the bound vocabulary per surface,and only for the surfaces the findings implicate:
Since #13072, those two constants are the same list — a section binds
current_userand its ADR-0068 aliases too (objectui#6110 + #6111), soBOUND_FORM_FIELD_PREDICATE_ROOTSisBOUND_FORM_VIEW_PREDICATE_ROOTSbyidentity. An artifact that carries findings on both slots therefore gets the
identical eight roots printed twice in one line:
Nothing there is false. What it costs is that the per-surface framing implies a
distinction the platform does not currently make, in a notice whose whole design
value is that an operator trusts it. The single-surface cases are unaffected and
read correctly.
Why it was not fixed in #13348
Collapsing the two arms to one flat clause changes operator-facing output and
moves the two
not.toContain('form FIELD')/not.toContain('form SECTION')assertions in
packages/metadata/src/plugin-unbound-form-predicate-roots.test.tsthat pin which arms print. That is a deliberate output decision rather than the
mechanical consequence of the contract re-measurement, and #13072's dispatch
narrowed the file surface to the detector module. #13348 corrected the stale
comment beside this code (it claimed the vocabularies differ) and left the
logic alone.
Suggested shape, if triage wants it
Print one clause when the two lists are equal ("bound roots on any form-view
predicate: ..."), keep the per-surface arms when they differ. That keeps the
structure honest in both worlds and needs the two pin assertions updated in
place. Alternatively: leave it, on the grounds that the per-surface arms cost
one duplicated clause and survive a future divergence for free. Both are
defensible; this is not a correctness question.
Measured on
origin/mainat merge basea286411dfplus the diff of #13348.Generated by Claude Code
Generated by Claude Code