Skip to content

fix(catalog): publish and document only what the manifests actually carry - #73

Merged
rmyndharis merged 1 commit into
mainfrom
fix/publish-only-fields-the-contract-has
Aug 8, 2026
Merged

fix(catalog): publish and document only what the manifests actually carry#73
rmyndharis merged 1 commit into
mainfrom
fix/publish-only-fields-the-contract-has

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

Three claims in the catalog layer turned out to have nothing behind them. All three came from the same reflex — writing down what a field ought to say instead of checking what produces it.

ingress[].methods could only ever be null

The generator mapped methods: r.methods ?? null from the manifest's ingress route. Core's PluginIngressRoute declares route, mode, signature, challenge, verify, maxBodyBytes, conversationId and response. There is no methods. Both published entries were null, and always would be.

That matters more here than a spare key normally would: this block exists so an operator can see what a plugin binds before installing it, and a provisioned ingress route is a @Public() endpoint. A null in a security-facing column reads as "any method" or "unknown" — neither of which was ever measured.

The column is removed, and the ingress test now pins the entry's key set, so a published field has to have a manifest field behind it. Verified by putting the line back: the suite drops to 1 failure and returns to green when it is removed again.

sessionScoped defaulted to the opposite of the host

sessionScoped: manifest.sessionScoped ?? false

The host decides the other way round — plugin-loader.service.ts treats a plugin as global only where manifest.sessionScoped === false, so an absent value means session-scoped.

Nothing was ever published wrongly: validateManifest throws on an undefined value before this line runs, and all ten manifests declare true. So this is a readability fix, not a correctness one — but the line stated the inverse of the rule it implemented, in a file whose whole job is to describe plugins accurately. Dropped rather than inverted, because with that validation above it any default is dead code.

The repo-gates paragraph listed two of five

It named the sessionScoped and testedOpenWAVersion gates and stopped, omitting the three a contributor actually trips: a missing CHANGELOG.md, a changelog with no released ## [x.y.z] — YYYY-MM-DD heading, and a manifest version that disagrees with that heading.

It also said a missing i18n block or locale is "a warning, not a failure". That is true of catalog.mjs and false of CI: one test fails a stable plugin missing any supported locale, and another — added last week after es shipped half-translated — fails any plugin with a locale that translates the name and description but not every configSchema field. A contributor reading the old sentence would take a red build as a bug in the gate.

The paragraph now lists all five hard failures and says where i18n is actually enforced.

Verification

550 tests, catalog:check, typecheck and build all pass. The regenerated plugins.json differs from the committed one by exactly the two deleted "methods": null lines.

One thing left alone, noted rather than fixed: the supported-locale list exists twice, in catalog.mjs and in the test, so adding a locale in one place silently fails to enforce it in the other. Deduplicating means making catalog.mjs importable — it does its work at module top level — which is a larger change than this one.

…arry

Three claims in the catalog layer had nothing behind them.

`ingress[].methods` read `r.methods ?? null` against a manifest key that does not
exist: core's `PluginIngressRoute` declares route, mode, signature, challenge,
verify, maxBodyBytes, conversationId and response — no `methods`. Both published
entries were `null`, and a reader of a security-facing column cannot tell a route
that accepts every method from a field that can never be filled. The column is gone,
and the test now pins the entry's key set so a published field always has a manifest
field behind it.

`sessionScoped: manifest.sessionScoped ?? false` defaulted to the opposite of the
host, which treats a plugin as global only when the manifest says `false` explicitly.
The default was unreachable — validateManifest refuses an undefined value first, and
all ten manifests declare it — so nothing was ever published wrongly, but the line
told a reader the inverse of the rule it was implementing. Dropped rather than
inverted: with the validation above it, any default is dead code.

The repo-gates paragraph listed two of the five conditions that fail the build,
omitting the three a contributor actually trips: a missing CHANGELOG.md, a changelog
with no released heading, and a version that disagrees with the manifest. It also
said a missing i18n locale is "a warning, not a failure" — true of catalog.mjs and
false of CI, where one test fails a stable plugin missing any locale and another
fails any plugin whose locale translates the name but not the config fields.

550 tests, catalog:check, typecheck and build all pass; the regenerated catalog
differs by exactly the two deleted lines.
@rmyndharis
rmyndharis merged commit 3ddf793 into main Aug 8, 2026
1 check passed
@rmyndharis
rmyndharis deleted the fix/publish-only-fields-the-contract-has branch August 8, 2026 08:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant