Skip to content

docs(cli): name the reader of each _views tail per side, and reconcile objectui's inert-key pin - #17721

Merged
os-sales merged 3 commits into
mainfrom
claude/issue-17546-i18n-extract-view-convention-prose
Sep 11, 2026
Merged

os-sales merged 3 commits into
mainfrom
claude/issue-17546-i18n-extract-view-convention-prose

Conversation

@claude

@claude claude Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #17546

Clause-②: no — declared on the card. No exported symbol, no accepted-input set, no published behaviour moves.

Recovery dispatch. The first dev pushed 72b23c09 and died with the container without opening a PR, so no CI had ever run on it and no reading was on record. Every claim below was re-derived here; nothing was inherited as measured.

⚠️ The card's title is partly wrong — one symbol was retired, not three

The card says viewLabel / viewDescription / viewEmptyState are "symbols objectui#7219 retired". Measured: only viewDescription was. The other two are current, and naming them is not residue.

objectui, on its origin/main (fetched; the repo is reachable from this container, so this half is measured, not unmeasured):

symbol site state
useObjectLabel().viewLabel packages/i18n/src/useObjectLabel.ts:481 live
useObjectLabel().viewDescription packages/i18n/src/useObjectLabel.ts:485 removed — the source says so in as many words
useObjectLabel().viewEmptyState packages/i18n/src/useObjectLabel.ts:512 live

The shared helper survived too — viewSuffixes (useObjectLabel.ts:289) is still called by viewLabel (:482) and viewEmptyState (:519, :522), and objectui's own comment at :501 states it: "viewSuffixes is NOT retired with it: viewLabel above and viewEmptyState below share that helper and keep resolving. Only the 'description' tail passed to it is gone."

⇒ the deliverable is not "swap a retired name for the server resolver". It is "name three different readers correctly", because the three tails have three different reader topologies.

The reader topology, per tail

Spec side, packages/spec/src/system/i18n-resolver.ts (read only — see the red line below):

  • resolveViewLabel (:403) reads objects.OBJECT._views.KEY.label
  • resolveViewDescription (:424) reads objects.OBJECT._views.KEY.description
  • both are called by translateView (:907, :908), registered as view: in METADATA_DOCUMENT_TRANSLATORS (:991), from which TRANSLATABLE_METADATA_TYPES is derived (:1008)
  • @objectstack/rest reads that derived set at the metadata boundary: isTranslatableMetaType (packages/rest/src/rest-server.ts:363) gates translateMetaItem (:3686) / translateMetaItems (:3952), both of which call translateMetadataDocument (:3733, :3977)

No empty-state reader exists on the spec side. Case-insensitive empty.?state in i18n-resolver.ts on origin/main: exit 1, zero hits — with two same-file, same-query-shape positive controls firing, description (89 lines) and the camelCase pluralLabel (8 lines). resolveViewEmptyState has zero occurrences tree-wide under one pattern that simultaneously found resolveViewLabel and resolveViewDescription, so the control is built into the query.

tail server client verdict
label resolveViewLabel useObjectLabel().viewLabel read on both sides
description resolveViewDescription — (removed by objectui#7219) server-side only
emptyState — (no reader) useObjectLabel().viewEmptyState client-side only

⭐ The fact the draft missed, and the reason this commit exists

The draft ended the description bullet with "⛔ The absence of a browser-side helper is not evidence the key is inert" — true, but it stops one step short of the thing that will bite the next reader.

objectui does not merely lack a helper. It pins this key as inert: packages/i18n/src/__tests__/useObjectLabel-view.test.tsx:144 is a whole describe('_views.VIEW.description is an inert catalog entry (objectui#7219)'), and the ruling comment says a bundle entry written under it "reached no screen". And in this repo, no bundle authors the leaf at all — parsed across all nine shipped en.objects.generated.ts, _views blocks carry label (104 leaves) and emptyState (9 leaves) and zero description leaves. The zero carries its control: the same parser found the other two leaf kinds in the same blocks.

A reader who greps objectui, hits "inert catalog entry", and deletes this emission would be repeating this card's own defect class with the polarity flipped. So the docblock now names both facts, scopes them to the browser path objectui#7219 removed, and says neither reaches the server reader.

The "reaches the screen" claim is now cited rather than asserted — the server overlay lands on the served view document's description, which objectui relays and renders:

  • packages/app-shell/src/views/ObjectView.tsx:2401description: viewDef.description ?? listSchema.description
  • packages/plugin-list/src/ListView.tsx:3404pickLocalized(schema.description, displayLocale)

The second original clause is TRUE — re-checked, not carried over

The card's site made two claims. The first was false; ⛔ repairing one and leaving the other standing is this card's defect class, so the second was re-measured: the shipped platform bundle does carry sys_user._views.all_users.labelpackages/platform-objects/src/apps/translations/en.objects.generated.ts:124 _views:128 all_userslabel: "All Users". @objectstack/platform-objects is published (not private, 17.4.0, files: [dist, README.md, CHANGELOG.md]). The clause survives unchanged.

Changeset: skip-changeset — the draft's patch is REVERSED

The draft argued patch on the grounds that @objectstack/cli builds with plain tsc, so the JSDoc is emitted into dist/utils/i18n-extract.js inside files[]. That premise is correct and was re-measured — the build script is tsc -p tsconfig.build.json and the docblock text is present in the built .js. But it shows bytes moving, not a release, and three things decide it the other way:

  1. AGENTS.md's criterion is "a diff that publishes nothing from any released package." Nothing consumer-observable moves: the emitted key set, the walk and every exported signature are byte-identical, and pushViewEntries is not exported (i18n-extract.ts:392, a plain function).
  2. Measured with a positive control. The docblock text reaches no .d.ts — the consumer-visible type surface — while an exported symbol's JSDoc in the same file does. pushViewEntries in packages/cli/dist/utils/i18n-extract.d.ts: zero hits, exit 1; control collectExpectedEntries in the same file: 3 hits, exit 0. So no consumer can call it, type against it, or observe it.
  3. House precedent is directly on point and went the draft's other way. PR docs(objectql): the last two carriers of the falsified "schema-uniform" premise state what the tree does #17717 — comment-only edits to packages/objectql/src/engine.ts and packages/objectql/src/validation/rule-validator.ts, a released package that also ships dist — carries skip-changeset and no changeset file.

On the draft's reading, no comment edit in any src/ file could ever take the label, which would empty the category .github/workflows/lint.yml:3104 names as "the textbook skip-changeset case — such a PR releases nothing". The changeset file is deleted in this PR.

packages/spec was read, never written

packages/spec/src/system/i18n-resolver.ts is the thing the new prose describes. 「凡触 packages/spec 一律转 domain:spec 座位,不论谁需要它」 — reading it is required, and not one byte was written into it. git diff --name-only origin/main...HEAD is exactly one file, packages/cli/src/utils/i18n-extract.ts.

Judgement owed on packages/lint/src/validate-translation-references.ts:381 — ⛔ not edited

Verdict: leave it. Its load-bearing clause is true and its names are live, so there is no stale-prose defect here — only an imprecision that is not worth another seat's landing.

The comment argues why the default form view gets addSections but no _views name: "the composer does give the default form a runtime identity (OBJECT.form), but _views.* is a LIST-view convention — viewLabel / viewDescription resolve view tabs, and the i18n walker emits no _views entry for any form view". Its conclusion is sound and unaffected by objectui#7219, and unlike the CLI site it never says "in @object-ui/i18n", so it is not pointing a reader at a removed member of a named package. viewLabel is live on both sides. Two imprecisions remain: viewDescription names no client-side resolver any more (server-side the symbol is resolveViewDescription), and "resolve view tabs" conflates _views with _tabs, which is resolveTabLabel / translateInterfaceTabs territory. Both are cosmetic — no behaviour, no gate and no reader's conclusion turns on either. ⇒ this is a noted, not filed observation, not a defect; packages/lint's spec-facing surface routes to domain:spec, so if the seat disagrees it is that seat's edit, not mine.

⚠️ One reason to be conservative here beyond routing: this comment quotes i18n-extract.ts verbatim — "form views have no counterpart in the viewLabel / _views.* resolver convention". That sentence is a third viewLabel site inside my own authorised file (i18n-extract.ts:1242), and it is accurate, so editing it would have dangled the lint file's citation for no gain. It is deliberately untouched.

Verification

Measured at 5fce933b, the final commit. Every exit code captured before any pipe (cmd > log 2>&1; EXIT=$?).

  • Gate union — 48 families derived, 48 accounted, 0 UNRUN. Derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (the script derives its own change set; no hand-written file list), then reconciled with --ran carrying a recorded exit code per command: ✓ 48 derived famil(ies) accounted for — 46 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3). Re-derived after a fresh git fetch origin main: byte-identical to the union that was run.
  • 46 of 48 green (exit 0).
  • 2 NOT MEASURED, ⛔ not red — both exit 3, and their printed verdict lines say why rather than the number:
    • pnpm check:dual-build-cjs-loads :: exit 3 — "PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/ … ⛔ This is NOT a pass: nothing was measured." (12 packages outside this card's closure are unbuilt; its own --self-test passed, 93 cases.)
    • pnpm check:i18n-coverage :: exit 3 — "Nothing was compared: 12 config(s) did lint, but a partial round cannot judge the ratchet … this result says NOTHING about whether any declared label went untranslated." (examples/app-showcase cannot load its config without a repo-wide build.) Both need a whole-repo pnpm build, which is CI's Build Core job. The two i18n gates that do not need it — pnpm check:i18n and pnpm check:i18n-walk-parity — are green, and they are the ones that would move if the emitted key set had changed.
  • pnpm lint — exit 0, full repo-wide run, not narrowed. This lane's known blind spot: dispatch-gates.mjs does not name it, so the lane always adds it. It completed in the foreground, so no narrowing had to be argued.
  • pnpm --filter '@objectstack/cli^...' build --concurrency=2 — exit 0, then pnpm --filter @objectstack/cli build — exit 0 (gates reading dist/ needed the rebuilt package; it is also what makes the .d.ts measurement above authoritative rather than stale).
  • pnpm --filter @objectstack/cli typecheck — exit 0, including check:test-typecheck ("@objectstack/cli's test layer compiles under packages/cli/tsconfig.test.json").
  • pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 — exit 0: Test Files 196 passed (196), Tests 2813 passed (2813).
  • Tier scope. Only the unit tier is owed locally: the diff touches no integration-layer file, no bin/ entry and no spawn helper. The integration tier is declared to CI, which runs both.
  • No new tests. The diff is one JSDoc block; there is no behaviour to assert and ⛔ no ablation is possible on a comment — a mutation to prose changes no gate's verdict, so a red/green pair would be fabricated. Stated rather than skipped silently.
  • Heavy verification went through scripts/pm/os-verify-lock.sh with a stable OS_VERIFY_LOCK_SLOT, sharing the box with the dev on [finding] packageBodyAsStack's ruled half has no in-package pin — its firing direction is held only by an examples/ fixture, and the dev's own ten-line fix was left unauthorised #17169. Wall-clock figures under that lock are shared-box readings and are not quoted as timings.

Acceptance notes

  • noted, not filedpackages/lint/src/validate-translation-references.ts:381 still spells viewDescription and says viewLabel / viewDescription "resolve view tabs". Cosmetic only; the clause it supports is true (judged in full above). Successor: domain:spec, which owns that file's spec-facing surface. ⛔ Not filed as a card: it is an imprecision in a comment whose conclusion holds, not a defect in any of the three filing classes.
  • noted, not filedi18n-extract.ts:1242 and i18n-extract.ts:451 were re-measured and are accurate, so no repair was owed at either. Recorded because "the card named one site" is not the same as "the file has one site", and the next reader of this file should not have to re-derive that.
  • Nothing else was touched. ⛔ No content/docs/releases/, no packages/spec, no packages/lint, no label flip on any other actor's PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c


Generated by Claude Code

…r tail

The `pushViewEntries` docblock attributed all three tails it emits to one
browser-side reader: "the convention the runtime resolver reads (`viewLabel` /
`viewDescription` / `viewEmptyState` in @object-ui/i18n)". Measured against
`origin/main` and the objectui checkout, the three tails have three different
readers and the sentence was wrong about two of them:

- `label` is read on BOTH sides — `resolveViewLabel`
  (`packages/spec/src/system/i18n-resolver.ts:403`) via `translateView` (:907),
  registered as `view:` in `METADATA_DOCUMENT_TRANSLATORS` (:991) from which
  `TRANSLATABLE_METADATA_TYPES` is derived (:1008) and read by
  `packages/rest/src/rest-server.ts:363`; and `useObjectLabel().viewLabel`
  client-side.
- `description` is read SERVER-SIDE ONLY, by `resolveViewDescription` (:424,
  called at :908). objectui#7219 removed the
  `useObjectLabel().viewDescription()` member, and the objectui source says so
  in as many words at `packages/i18n/src/useObjectLabel.ts:485`. The old prose
  therefore pointed the reader at a symbol that no longer exists, for a key that
  is still resolved and still reaches the screen — the inversion #15180 read as
  "declared, accepted, read by nothing".
- `emptyState` is read CLIENT-SIDE ONLY. `emptyState` has zero occurrences in
  `i18n-resolver.ts` (positive control in the same file: `description`, 90
  occurrences) and `resolveViewEmptyState` has zero occurrences tree-wide
  (positive control: `resolveViewLabel`, present), while
  `useObjectLabel().viewEmptyState` is live at `useObjectLabel.ts:512`.

The second clause was re-checked rather than carried over and is TRUE: the
platform bundle does carry `sys_user._views.all_users.label`
(`packages/platform-objects/src/apps/translations/en.objects.generated.ts:124`
`_views` → `:128` `all_users` → `label: "All Users"`). Across all nine shipped
`en.objects.generated.ts` bundles, `_views` blocks carry `label` leaves and no
`description` leaf, so naming `.label` there is exact.

`viewLabel` and `viewEmptyState` are NOT retired: objectui kept the
`viewSuffixes` helper all three shared and dropped only the `'description'`
tail. The added warning says that, so the next reader does not over-apply
objectui#7219 and delete two current citations.

`pushViewEmptyState`'s own docblock (:453) names `viewEmptyState` in
@object-ui/i18n and is left untouched — on this measurement it is accurate.

Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c

Co-authored-by: Claude <noreply@anthropic.com>
…tail docblock

Measured rather than assumed: `@objectstack/cli` builds with plain
`tsc -p tsconfig.build.json`, so JSDoc survives into
`dist/utils/i18n-extract.js`, which is inside the package's `files[]`. A
comment-only diff therefore moves published bytes here, and `skip-changeset`
would be wrong — the false sentence is text an upgrading agent can grep in the
published tarball. Positive control on the same probe: the docblock's
`sys_user._views.all_users.label` phrase is likewise present in the built
`dist/utils/i18n-extract.js`, and absent from the emitted `.d.ts`.

Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c

Co-authored-by: Claude <noreply@anthropic.com>
… `_views.<view>.description`

Successor pass on the R73 draft. The draft's reader topology re-derived and
CONFIRMED; one omission corrected and the changeset reversed.

Corrected. The draft said "⛔ The absence of a browser-side helper is not
evidence the key is inert" and stopped there. objectui does not merely lack a
helper — it PINS this key as "an inert catalog entry"
(`packages/i18n/src/__tests__/useObjectLabel-view.test.tsx`, a whole `describe`),
and measured across all nine shipped `en.objects.generated.ts` bundles, `_views`
blocks author `label` (104) and `emptyState` (9) leaves and ZERO `description`
leaves. A reader who greps objectui hits "inert catalog entry" and deletes this
emission — the same defect class as the sentence this card is about, aimed the
other way. The block now names both facts, scopes them to the browser path
objectui#7219 removed, and says neither reaches the server reader.

The reach claim is now cited rather than asserted: the overlay lands on the
served view document's `description`, which objectui relays
(`packages/app-shell/src/views/ObjectView.tsx`
`description: viewDef.description ?? listSchema.description`) and renders
(`packages/plugin-list/src/ListView.tsx`, `pickLocalized(schema.description,
displayLocale)`).

Changeset REVERSED to `skip-changeset`. The draft argued `patch` because the
JSDoc is emitted into `dist/utils/i18n-extract.js` inside `files[]`. That premise
is true — re-measured — but it shows bytes moving, not a release. Measured with a
positive control, the docblock reaches NO `.d.ts` (an exported symbol's JSDoc in
the same file does), and `pushViewEntries` is not exported, so nothing a consumer
can call or type against moves. House precedent is directly on point and went the
other way: a comment-only edit to `packages/objectql/src/engine.ts` and
`validation/rule-validator.ts` — a released package that also ships `dist` — took
`skip-changeset` and no changeset file.

Left standing deliberately, both re-measured as ACCURATE: the `pushViewEmptyState`
docblock naming `viewEmptyState` in @object-ui/i18n (live), and the `formViews`
comment naming `viewLabel` (live) — which `packages/lint` quotes verbatim, so
editing it would dangle that citation.

Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c
Co-authored-by: Claude <noreply@anthropic.com>
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/cli/src/utils/i18n-extract.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/cli/src/utils/i18n-extract.ts) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 66440147a5b79b7b41b51ba5490ba33419e787e3packageMentionDocs.

@claude

claude Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Review of record — ACCEPT

Head reviewed: 5fce933bf2fdcc9129768edc68359855d82a404b · reviewed 2026-09-11T20:14Z (stamp from date -u in this posting call).

Reviewed-by: domain:cli execution PM seat (#6024) · session_01TSf4DV7ziu4V5j73e46b7c · account os-sales
Implemented-by: an os-dev subagent of that same session — a recovery dispatch, after a container restart killed the first dev mid-flight (reclamation note 5639320918).

⚠️ Independence, stated rather than implied: the implementer was this seat's own dispatched subagent, so this is ⛔ not a review by an independent second party. Clause-②: no, nothing exported, so no contract review is owed.

Gates and CI on this head

check-clause2-carriers.mjs --pair 17721      EXIT=0
check-governed-merges.mjs  --pr 17721        EXIT=0   ✅ NOT governed
check-governed-merges.mjs  --test AGENTS.md  EXIT=3   ⛔ GOVERNED    <- the control

27 completed/success · 6 completed/skipped · 0 running · NON-green: NONE after a latest-per-name collapse; combined status success; mergeable_state: clean. One file, and the diff is provably comment-only — parsed from the diff rather than described: 35 added lines, 4 removed, 0 non-comment lines in either direction. ⛔ Zero packages/spec/ paths and zero content/docs/releases/ paths.

⭐ The dev falsified this card's title, and this seat verified it at the source

Recorded in full at 5639850744; the short form is that the title called three symbols "retired by objectui#7219" and only one was. Verified by this seat from objectui's own origin/main (ad80b06) — the file's presence on that ref confirmed with git ls-tree, ⛔ not from a working-tree listing, because mixing a working-tree file list with an origin/main content read is how a zero comes back looking like a full scan:

"There is deliberately NO viewDescription member here … viewSuffixes is NOT retired with it: viewLabel above and viewEmptyState below share that helper and keep resolving. Only the 'description' tail passed to it is gone."

⇒ objectui says it in its own words. The card has been retitled so the false premise does not become the citation surface when it closes; ⛔ the body was not rewritten — 存量不追溯改写, and edit history is the archive.

⚠️ And the dispatch order was wrong on the reachability, which is worth recording against this seat rather than the dev: the order told it to treat the objectui half as UNFIRED-BECAUSE-UNMEASURED. /home/user/objectui is a local checkout, so that half was measurable all along and the dev measured it. ⛔ A seat's instruction to record something as unmeasured does not make it unmeasurable.

⭐ The correction the dev made to the dead run's draft is sharper than the original defect

The draft had the reader topology right and it was kept. What was added is the half that makes the docblock safe to read: objectui does not merely lack a helper — it pins the key as "an inert catalog entry", and no bundle in this repo authors a description leaf (nine shipped en.objects.generated.ts: 104 label, 9 emptyState, zero description).

⇒ left unstated, the next reader greps objectui, reads "inert", and deletes the emission — this card's own defect class with the polarity flipped. The docblock now names both facts, scopes them to the browser path objectui#7219 removed, and cites the reach claim (ObjectView.tsx:2401 relays, ListView.tsx:3404 renders via pickLocalized) instead of asserting it.

What this seat measured that the review would otherwise have overclaimed

The docs-drift bot reported "1 changed file yielded no anchor … this is not a clean bill of health", so its blind spot was live. Checked by hand:

viewDescription · viewLabel · viewEmptyState · useObjectLabel · @object-ui/i18n
  -> 0 files in content/docs/**  (each)
POSITIVE control, same query shape: "objectstack" -> 355 files   (channel live)

⇒ no docs page carries the falsehood. Four pages do state the _views convention (i18n-standard.mdx:903, translation.mdx:93/:253/:414, ui/translations.mdx:68-:69) but every one describes it by key address and shape, never by naming a reader symbol.

⚠️ A real limit on what this review certifies, stated rather than glossed: because the docs describe the convention only by address, the dev's reader-topology claim cannot be cross-checked against them. It stands on objectui's source (which this seat read) and on the spec-side resolvers, ⛔ not on any independent documentation.

Accepted as reported

  • The packages/lint:381 judgement — leave it. Its load-bearing clause (that _views.* is a list-view convention, so a default form view gets addSections and no _views name) is true and untouched by objectui#7219; and unlike the CLI site it never says "in @object-ui/i18n", so it points no reader at a removed member of a named package. Two imprecisions remain, both cosmetic, and an imprecision in a comment whose conclusion holds is not a defect. ⛔ Read, judged, not editedpackages/lint's spec-facing surface is another seat's.
  • The draft's patch changeset was reversed to skip-changeset, as required. Labels on this head confirm it.
  • ⚠️ No ablation, and the dev said so rather than skipping it: the diff is one JSDoc block, so a prose mutation moves no gate's verdict and a red/green pair would be fabricated. ⭐ Declining to manufacture evidence is the right call.
  • Four zero-hit controls, each sharing its target's failure mode — including one that demonstrated the wrapped-prose failure directly: a git grep -c -F for the lint file's verbatim quote exits 1 with zero hits while the phrase is present, because it wraps mid-phrase behind a * prefix. ⇒ the failure mode was shown, not assumed.
  • Two further sites in the same file (:1242, :451) re-measured as accurate and deliberately untouched — and :1242 is quoted verbatim by packages/lint, so editing it would have dangled that citation for no gain. ⭐ "The card named one site" is not "the file has one site."

Verdict

ACCEPT. One file, comment bytes only, provably so; the card's own premise falsified with evidence and verified here at the source; the omission that would have inverted the defect closed; the out-of-fence site read, judged and left alone. Landing armed by this seat.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants