Skip to content

An authored display type can WIDEN inline-edit on a computed field — type: 'number' on a rollup unlocks the chip #3355

Description

@xuyushun441-sys

Split out of objectstack-ai/objectstack#5077 as an out-of-scope finding — filed unassigned. Found by measurement while fixing the dropped readonly key; not fixed in that PR because it changes the meaning of an authored type across two components.

What was measured

Probe against origin/main (532cf8b), rendering RecordHighlightsRenderer inside an InlineEditProvider canEdit, reading the DOM for the inline-edit affordance (cursor-pointer target + hover pencil):

object field authored entry chip inline-editable?
supply_share: { type: 'number' } 'supply_share' yes correct
supply_share: { type: 'number' } { name, type: 'formula' } no correct
score: { type: 'formula' } { name: 'score' } no correct
score: { type: 'formula' } { name: 'score', type: 'number' } yes wrong

The last row is the problem: the object declares the column computed, the author writes a display type to fix formatting, and the chip becomes writable.

Why it happens

HeaderHighlight.tsx:

const resolvedType = field.type || objectDefField?.type;
const isComputed = TEXTUAL_REF_FALLBACK_TYPES.has(resolvedType as string);

TEXTUAL_REF_FALLBACK_TYPES is formula | summary | rollup | auto_number. Because the authored type replaces the object's type rather than adding to it, an authored non-computed type erases the object's computed declaration from the gate's view.

DetailSection.tsx has the identical shape — inlineEditType = enrichedField.type || field.type, and enrichDetailField only fills type from the object when the view field left it undefined. So the details body has the same hole. Any fix must land in both or the two surfaces drift, which is the drift fieldEnrichment.ts was created to stop.

Why it is not academic

This is the real configuration in the app that reported objectstack-ai/objectstack#5077. They ship

properties: { fields: [ /* … */ { name: 'supply_share', type: 'number' }, /* … */ ] }

as a workaround for objectstack-ai/objectstack#5066 (display formatting), and supply_share is a hook-maintained rollup. The measured corruption there — a rollup overwritten by hand, staying wrong until an unrelated child-row touch re-fired it — goes through this path, not through the missing readonly alone. Fixing readonly gives them a way out; it does not close the trap for the next app that writes a display override.

The decision

What does an authored type on a highlight / detail-view field mean?

Option A — narrow-only. Treat the gate's type set as a union: non-editable if the authored type or the object type is computed. An authored type can then only ever lock a field, never unlock one. Display-renderer selection keeps using the authored type exactly as today, so nothing visual changes.

  • Long-term soundness: the object schema is the source of truth for whether a column is machine-computed; a presentation override has no business granting write access. Monotonic-in-the-safe-direction is the property you want in a gate that guards data integrity. Nobody can be legitimately relying on inline-editing a formula column — the write either bounces server-side or, worse, lands and corrupts.
  • AI-authoring safety: this is the structural fix. An authoring model writing type: 'number' to fix formatting cannot accidentally hand users write access to a rollup, because the two concerns stop sharing one key's authority. No new vocabulary, no way to get it wrong.
  • Cost: behaviour change for any page that today relies on a type override to make a computed field editable. I could not construct a case where that is desirable rather than a latent bug.

Option B — separate the concerns properly: keep type as display-only and add an explicit editable/readonly declaration for the gate.

Option C — leave as-is, documenting that an authored type fully overrides including editability.

  • Cheapest, and honest about current behaviour. Long-term cost: a documented footgun in a data-integrity gate, on the exact key authors are told to reach for when a chip renders wrong. Documentation does not stop an AI author who never reads it.

Recommendation: A, with B's readonly key as the explicit-intent escape hatch on top (that half is already in flight). A is the option where the mistake becomes unrepresentable rather than merely avoidable, and it is the one that keeps the object schema authoritative about what is machine-owned. Land it in HeaderHighlight and DetailSection together.

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions