Surfaced by astro-data (019f8104-6622) while source-tracing whether .catch() is represented. Their CODE claim was wrong -- catch is fully represented, executed proof in the reply -- but the DOCS half of their claim was right, and pulling it revealed a bigger gap behind it. A fourth item was added by huttspawn from the render seat.
1. Supported-constructs list is missing wrappers it supports
README.md:146 (HEAD) / :150 (main) reads:
... plus optional, nullable, default, and describe/meta.
catch and readonly are both absent, though both are in FLAG_WRAPPERS (src/introspection/unwrap.ts:12-21) and both are peeled with inner constraints surviving. A reader source-tracing the docs concludes catch is unsupported -- which is exactly what happened.
Already fixed in the uncommitted docs rewrite on feat/monorepo-plugin-host, which lists all five wrappers in one table row. This card exists so the fix is tracked rather than riding silently on a docs branch, and to cover the parts the rewrite does NOT fix, below.
2. refine and pipe/transform appear in no supported-constructs table at all
Zero hits across README.md, docs/**, AGENTS.md. But kelex has dedicated warning codes for both (refine-unrepresented, transform-output-dropped), so it plainly encounters them. A construct kelex warns about but never names in docs is worse than one it does not handle -- the consumer has no way to anticipate the warning.
This is load-bearing for the render/authoring seats specifically: WARN-on-unrepresentable-refine rather than silent-drop was the position astro-consent, rafters and huttspawn all independently endorsed. It should be documented as a contract, not left as runtime surprise.
3. The whole warning taxonomy is undocumented -- the systemic finding
src/introspection/types.ts:57-78 defines 16 WarningCode values:
unsupported-type, refine-unrepresented, catch-fallback-dropped, default-unstable, transform-output-dropped, coerce-unrepresented, key-policy-unrepresented, format-unrecognized, check-dropped, record-key-narrowed, intersection-key-overlap, numeric-enum-as-union, discriminator-unresolved, discriminator-ambiguous, target-warning, target-field-unprocessed.
Every one of the 16 returns zero hits across README.md, docs//*.md, AGENTS.md, docs/plugins/. The taxonomy exists only in source and tests. The one doc sentence that gestures at it is README.md:165 prose -- "Anything the reader cannot represent is reported as a warning, never dropped in silence" -- which promises a mechanism it never enumerates.
So catch was not a specific documentation gap. It was the visible edge of a total absence.
The explanatory content already exists in-repo and simply was never promoted: .changeset/catch-resolution.md:5-9 explains catch semantics in prose, and .changeset/structured-warnings.md:7 lists several codes. Release-note fragments, not user-facing docs.
4. Authored-vs-derived label is recoverable but undocumented (huttspawn, 019f8102-d431)
introspect.ts:398 sets label to metaString(meta, "title") ?? nameToLabel(name). So the flat label field cannot tell a consumer whether a human authored it or kelex derived it from the key.
Render seats need that distinction, in huttspawn's words: "a derived label I override without thinking, an authored one I treat as intent and think twice."
It IS recoverable -- meta rides verbatim since #147, so meta?.title !== undefined is exactly the signal. huttspawn found this by reading source and filed no ask. That is the gap: undocumented-but-recoverable is still a gap, and no render seat should have to re-derive it from source. Document it as a consumer recipe.
Worth noting as rationale: this is the cleanest evidence for the #147 decision to carry the full meta payload verbatim rather than a title/description subset. That call was made on lossless-round-trip grounds and it bought a consumer a capability nobody designed for.
Acceptance criteria
- The supported-constructs table names all five peeled wrappers: optional, nullable, default, catch, readonly.
refine and pipe/transform appear in the docs with their actual treatment stated (constraint recorded as present, not reasoned through; output side of a transform not represented).
- A warning-code reference documents all 16 codes: what triggers each, and what the consumer should do about it.
- The reference lives on the user-facing doc surface, not in
.changeset/.
- README.md:165's promise of a warning mechanism links to that reference.
- The authored-vs-derived label recipe (
meta?.title !== undefined) is documented wherever label is described, with the derived-vs-intent consequence stated.
Surfaced by astro-data (019f8104-6622) while source-tracing whether
.catch()is represented. Their CODE claim was wrong -- catch is fully represented, executed proof in the reply -- but the DOCS half of their claim was right, and pulling it revealed a bigger gap behind it. A fourth item was added by huttspawn from the render seat.1. Supported-constructs list is missing wrappers it supports
README.md:146 (HEAD) / :150 (main) reads:
catchandreadonlyare both absent, though both are in FLAG_WRAPPERS (src/introspection/unwrap.ts:12-21) and both are peeled with inner constraints surviving. A reader source-tracing the docs concludes catch is unsupported -- which is exactly what happened.Already fixed in the uncommitted docs rewrite on feat/monorepo-plugin-host, which lists all five wrappers in one table row. This card exists so the fix is tracked rather than riding silently on a docs branch, and to cover the parts the rewrite does NOT fix, below.
2.
refineandpipe/transformappear in no supported-constructs table at allZero hits across README.md, docs/**, AGENTS.md. But kelex has dedicated warning codes for both (
refine-unrepresented,transform-output-dropped), so it plainly encounters them. A construct kelex warns about but never names in docs is worse than one it does not handle -- the consumer has no way to anticipate the warning.This is load-bearing for the render/authoring seats specifically: WARN-on-unrepresentable-refine rather than silent-drop was the position astro-consent, rafters and huttspawn all independently endorsed. It should be documented as a contract, not left as runtime surprise.
3. The whole warning taxonomy is undocumented -- the systemic finding
src/introspection/types.ts:57-78defines 16 WarningCode values:unsupported-type, refine-unrepresented, catch-fallback-dropped, default-unstable, transform-output-dropped, coerce-unrepresented, key-policy-unrepresented, format-unrecognized, check-dropped, record-key-narrowed, intersection-key-overlap, numeric-enum-as-union, discriminator-unresolved, discriminator-ambiguous, target-warning, target-field-unprocessed.
Every one of the 16 returns zero hits across README.md, docs//*.md, AGENTS.md, docs/plugins/. The taxonomy exists only in source and tests. The one doc sentence that gestures at it is README.md:165 prose -- "Anything the reader cannot represent is reported as a warning, never dropped in silence" -- which promises a mechanism it never enumerates.
So
catchwas not a specific documentation gap. It was the visible edge of a total absence.The explanatory content already exists in-repo and simply was never promoted:
.changeset/catch-resolution.md:5-9explains catch semantics in prose, and.changeset/structured-warnings.md:7lists several codes. Release-note fragments, not user-facing docs.4. Authored-vs-derived label is recoverable but undocumented (huttspawn, 019f8102-d431)
introspect.ts:398setslabeltometaString(meta, "title") ?? nameToLabel(name). So the flatlabelfield cannot tell a consumer whether a human authored it or kelex derived it from the key.Render seats need that distinction, in huttspawn's words: "a derived label I override without thinking, an authored one I treat as intent and think twice."
It IS recoverable --
metarides verbatim since #147, someta?.title !== undefinedis exactly the signal. huttspawn found this by reading source and filed no ask. That is the gap: undocumented-but-recoverable is still a gap, and no render seat should have to re-derive it from source. Document it as a consumer recipe.Worth noting as rationale: this is the cleanest evidence for the #147 decision to carry the full meta payload verbatim rather than a title/description subset. That call was made on lossless-round-trip grounds and it bought a consumer a capability nobody designed for.
Acceptance criteria
refineandpipe/transformappear in the docs with their actual treatment stated (constraint recorded as present, not reasoned through; output side of a transform not represented)..changeset/.meta?.title !== undefined) is documented whereverlabelis described, with the derived-vs-intent consequence stated.