Found while implementing #14782 (the os explain flow sample); out of scope there, filed
unassigned for triage. Suggested domain: domain:cli.
The observation
packages/cli/src/commands/explain.ts holds a SCHEMAS catalog of 12 entries —
object, fields, field, view, flow, agent, app, query, dashboard,
action, workflow, trigger. Each carries a required list, an optional list and an
example string, and every one of them is hand-maintained: nothing derives them from
the schema they describe, and until now nothing checked them against it.
The existing test block in packages/cli/test/commands.test.ts states the hazard in its
own words, and its comment is worth quoting because it was written after this already
happened twice:
The token set is asserted EXACTLY, and that exactness is the point: this catalog is
hand-maintained and does NOT derive from the spec enum, so a spec-side enum change that
stops here is invisible to any review that only reads packages/spec.
That guard covers exactly one field of one entry (object.ownership, from #3244, widened
again at #5678).
Why this is worth a card rather than a note
#14782 measured what an unguarded entry drifts into. The flow entry's example did not
merely carry a wrong token — it did not parse as a Flow at all:
ISSUE [nodes] Invalid input: expected array, received undefined
ISSUE [edges] Invalid input: expected array, received undefined
ISSUE [] Unrecognized key(s) on this flow: `trigger`, `steps`.
Did you mean `trigger` -> `type`, `steps` -> `nodes`?
Its required / optional lists named two keys (steps, trigger) that are strict-object
aliases, i.e. loud parse errors, and omitted two that are required (nodes, edges).
Meanwhile os generate flow, in the same package, was scaffolding the correct shape all
along — so the drift was not for want of the truth being known locally.
PR #14809 pins the flow entry by parsing its example against the real FlowSchema. That
technique generalises, and it is the only kind of guard that cannot drift alongside the
catalog it checks, because it re-derives the truth from the spec on every run. It was
deliberately not generalised in that PR: the other entries are outside that card's
face, and turning the guard on all 12 at once would fail on entries nobody has mandate to
rewrite in a p3 documentation fix.
What is NOT claimed
I did not audit the other 11 entries. This card records that they are unguarded and
that one of the twelve was measured badly wrong — not that any specific other entry is
wrong. The first step for whoever takes this is cheap: extend the parse-the-example
technique entry by entry and see which ones fail.
Suggested shape
- For each catalog entry with a resolvable schema in
@objectstack/spec, parse its
example against that schema in commands.test.ts.
- Where an entry has no single schema to parse against (
fields is a fragment, query may
be one), say so explicitly in the test rather than skipping silently.
- Fix whatever the parse turns up, one entry at a time.
Triage may well decide the audit is worth more than the generalised guard, or split them.
Found while implementing #14782 (the
os explain flowsample); out of scope there, filedunassigned for triage. Suggested domain:
domain:cli.The observation
packages/cli/src/commands/explain.tsholds aSCHEMAScatalog of 12 entries —object,fields,field,view,flow,agent,app,query,dashboard,action,workflow,trigger. Each carries arequiredlist, anoptionallist and anexamplestring, and every one of them is hand-maintained: nothing derives them fromthe schema they describe, and until now nothing checked them against it.
The existing test block in
packages/cli/test/commands.test.tsstates the hazard in itsown words, and its comment is worth quoting because it was written after this already
happened twice:
That guard covers exactly one field of one entry (
object.ownership, from #3244, widenedagain at #5678).
Why this is worth a card rather than a note
#14782 measured what an unguarded entry drifts into. The
flowentry's example did notmerely carry a wrong token — it did not parse as a
Flowat all:Its
required/optionallists named two keys (steps,trigger) that are strict-objectaliases, i.e. loud parse errors, and omitted two that are required (
nodes,edges).Meanwhile
os generate flow, in the same package, was scaffolding the correct shape allalong — so the drift was not for want of the truth being known locally.
PR #14809 pins the
flowentry by parsing its example against the realFlowSchema. Thattechnique generalises, and it is the only kind of guard that cannot drift alongside the
catalog it checks, because it re-derives the truth from the spec on every run. It was
deliberately not generalised in that PR: the other entries are outside that card's
face, and turning the guard on all 12 at once would fail on entries nobody has mandate to
rewrite in a p3 documentation fix.
What is NOT claimed
I did not audit the other 11 entries. This card records that they are unguarded and
that one of the twelve was measured badly wrong — not that any specific other entry is
wrong. The first step for whoever takes this is cheap: extend the parse-the-example
technique entry by entry and see which ones fail.
Suggested shape
@objectstack/spec, parse itsexampleagainst that schema incommands.test.ts.fieldsis a fragment,querymaybe one), say so explicitly in the test rather than skipping silently.
Triage may well decide the audit is worth more than the generalised guard, or split them.