Skip to content

[pull] main from TryGhost:main - #1407

Merged
pull[bot] merged 16 commits into
code:mainfrom
TryGhost:main
Aug 12, 2026
Merged

pull[bot] merged 16 commits into
code:mainfrom
TryGhost:main

Conversation

@pull

@pull pull Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

kevinansfield and others added 16 commits August 12, 2026 10:18
no ref

- the flag existed to show L/M badges on the posts list for spotting
  lexical vs mobiledoc posts during the editor migration; nothing reads
  it any more now that migration testing is long finished
- also removed the orphaned gh-lexical-indicator CSS rules
no ref

- nothing reads emailCustomization (or the older emailCustomizationAlpha) at runtime any more — there are no labs/feature conditionals left, and kg-default-nodes' exportDOM never consults options.feature when selecting renderers
- removed the flag registration from labs.js, the admin labs toggle, and the ember feature service, and dropped both flags from ExportDOMFeatureOptions
- de-flagged the kg-default-nodes tests that passed the flags as inert options, and removed the flag-specific tests whose coverage was already provided by unflagged tests
…#29488)

no ref

- uploading to an S3/GCS-backed site answered with "Maximum call stack size
  exceeded", which told the caller nothing about the real failure
- an AWS SDK exception is a circular object graph, and the API error handler
  deep-clones the error it renders with no cycle detection, so letting one
  escape the store blew the stack
- both S3 stores now convert a non-NotFound failure into a plain Ghost error
  that holds nothing off the SDK exception by reference, so it is safe to
  serialise
- the origin frames are carried across on the stack, so the underlying storage
  failure is still diagnosable from the logs and Sentry
no reef

This test-only change converts tests for these helpers:

- `total_members`
- `total_paid_members`
- `color_to_rgba`
- `json`
- `title`
- `encode`
- `contrast_text_color`
- `facebook_url`
- JSON-LD escaping helper
no ref

- @tryghost/bookshelf-plugins 2.3.8 pulls in bookshelf-pagination 2.4.1, where the optimized count(*) query is the default for single-table queries, so the behaviour no longer needs to be gated
- removed the smarterCounts labs flag, its gating in the model crud plugin, and the labs UI toggle
ref https://linear.app/ghost/issue/BER-3846/

- how a field type looks in a picker (its icon, and the row pairing that icon
  with its name) is presentation shared by every surface that offers types, and
  there is about to be a second one in the members import
- Settings and the import had rendered the same markup independently, so the
  option row moves alongside the icon rather than being copied next to it
- no behaviour change: the option resolves its own label from the catalog, which
  is where the local {label, value} shape was reading it from anyway
ref https://linear.app/ghost/issue/BER-3859/

A field type's parts were described in two places that nothing held together. The shared catalog derives them from the type's own value schema, while admin hand-writes the label for each one, and the only thing checking that the two still agreed was a hand-applied constraint on the address type alone. A part added upstream reached a publisher as its raw key, and a composite nobody had labelled at all read as a scalar, which is worse: a caller would never think to ask which part it was holding. Presentation is now compile-forced against the value schema for every type, so a part added, removed or renamed upstream fails the build here instead, and the fallback to a raw key is gone. The value a member write may carry was hand-listed the same way, naming address as though it were the only composite there could be; it is derived from the schemas now, so a type added to them is writable without anyone editing that line. The CSV column labels come from the same source, paired to each column by the part it holds rather than by two lists being built in the same order.
ref https://linear.app/ghost/issue/BER-3859/

The member detail editor kept its own list of the address composite's parts, so the parts existed in three places: the value schema that declares them, the catalog that labels them, and this tuple. The tuple also typed the editable value through a Pick, which catches a part being removed or renamed upstream but not one being added, so a new part would have been quietly missing from the editor and from the trimming both the draft and the save run over it. The editor now takes the parts, in the order the schema declares them and under the labels every other surface uses, from the same accessor the import mapping reads. Part keys carry their own type out of the shared catalog now, so a consumer indexes a value by one without restating which parts exist. The formatted address line still names its parts one by one, because where each sits in the sentence is a fact about how an address reads rather than one the schema can supply.
ref https://linear.app/ghost/issue/BER-3859/

Three small things the previous commits left slightly untrue. The presentation catalog's own comment said it owned a type's icon, which it never has, so a reader consolidating presentation would have moved things toward a file that does not hold them. The widened sub-field map on the exported user type had no reader left once labels were resolved from the catalog directly, and leaving it there invited the next consumer to take the untyped path around the accessor that was just added. The editor's control switch fell through to rendering nothing for an input it did not recognise, which reads as tolerance but guards nothing, because the input comes from the catalog rather than the server; typed as never, a control added to the catalog now fails the build instead. The shared package also records where the line between it and admin actually falls, which is whether more than one renderer has to agree on a string rather than presentation against validity, since it already ships the sentences a broken rule shows.
ref https://linear.app/ghost/issue/BER-3859/

A field's type arrives as a string off the wire and is asserted rather than checked, so an admin build older than the server it talks to is handed a type it has never heard of. Two places read that type by indexing a catalog and using the result immediately, which threw on the way to building the import mapping targets. The editor and its validation had already decided what to do about a type this build does not know, twice, in comments that say the server stays authoritative, so the reading now agrees with them: an unheard-of type has no parts and no part labels, and degrades to a single whole-field column instead of failing the surface. This crash predates the rest of this branch and is pinned by a test that reproduces it.
Documentation-only changes to `.github/CONTRIBUTING.md` currently
trigger the MySQL and SQLite acceptance and legacy test matrices because
`.github/**` is shared by the Core filter. Those files cannot affect
Ghost runtime behaviour, so excluding them will reduce unnecessary CI time
on documentation changes.
Established `/docs` as the canonical home for documentation about working on
the Ghost codebase. Added current guides for development setup, contribution
workflow, testing, shipping, and monorepo structure.

Kept `.github/CONTRIBUTING.md` focused on contributor-specific requirements,
with direct links into the codebase documentation. Updated the root README and
docs index so contributors, developers, and self-hosters are routed to the
appropriate documentation.

Removed duplicated setup, command, and monorepo guidance from `AGENTS.md`.
Shared facts now live in human-readable codebase docs, while `AGENTS.md`
retains agent-specific workflow and implementation constraints.
no ref
- nx-set-shas makes a high number of calls to the Github API - transient issues or rate limiting errors are masked as a failure to lookup a successful workflow run
- adding a custom script that only needs one call to the Github API simplifies the setup and leverages the local git checkout more
Removes the obsolete `customFonts` Labs registration, which is entirely unused. 
Custom fonts remain generally available - no runtime behavior is changed.
@pull pull Bot locked and limited conversation to collaborators Aug 12, 2026
@pull pull Bot added the ⤵️ pull label Aug 12, 2026
@pull
pull Bot merged commit ada2639 into code:main Aug 12, 2026
2 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants