Skip to content

Removed the route-settings activation bridge - #29744

Merged
vershwal merged 4 commits into
mainfrom
princi-hkg-1898-remove-activation-bridge
Aug 4, 2026
Merged

Removed the route-settings activation bridge#29744
vershwal merged 4 commits into
mainfrom
princi-hkg-1898-remove-activation-bridge

Conversation

@vershwal

@vershwal vershwal commented Aug 4, 2026

Copy link
Copy Markdown
Member

ref https://linear.app/ghost/issue/HKG-1898

Closes out the DDD Architecture Cleanup milestone: the RouteSettings domain model now flows store → service → RouterManager → routers with no intermediate transformation.

Why now

The activation bridge was a temporary adapter introduced in Phase 1 of the refactor. Its four original conversions have all been relocated by earlier PRs in this milestone:

Conversion Now lives in
array → map keyed by path RouterManager (#29617)
{slug}:slug permalink-adapter.ts (#29662)
resource → controller name api-adapter.ts (#29742)
data{query, router} api-adapter.ts + resolveResourceRead (#29742)

That left the bridge doing only two things, both removed here:

  1. Flattening taxonomies from the domain {tag, author} map into {key, permalink}[]RouterManager.start() now iterates the map directly, which is what step 3.7 of the design doc specifies.
  2. Rebuilding every route/collection field-by-field, whose only real effect was defaulting templates to [] — redundant, since collection-router.js:36 and static-routes-router.js:17 each already default it.

Two behaviours deliberately not carried over

  • The bridge's falsy-permalink guard (if (value)) was unreachable: parseRouteSettings throws on an empty taxonomy permalink (route-settings-parser.ts:370, pinned by validate-route-settings.test.ts:190), and both stores — FileStore and S3RouteSettingsStore — produce their model through that parser. Dropping it is a no-op.
  • The templates: [] default, per above.

loadRouteSettings() now returns yamlSource

The bridge used to strip it. Both callers (dynamic-routing-service.js:52, bridge.js:118) hand the object straight to routerManager.start(), which reads only .routes / .collections / .taxonomies, so the extra property is inert.

integrity.test.js

currentRoutesHash changes because it now hashes the parsed model rather than bridge output. yamlSource is excluded so the canary keeps tracking route structure — including it would trip the test on comment and whitespace edits to default-routes.yaml that change no route. The constant is test-local: the routes_hash setting was removed in #29643, so nothing at runtime or in the DB consumes it.

Testing

Built test-first: the loadRouteSettings contract tests and the legacy suite's fixture helper were changed to expect the domain model, then the production code was changed to satisfy them.

Suite Result
test/unit/** (route-settings, frontend routing, schema) 331 passed
test/integration/services/route-settings 5 passed
--project legacy (full) 451 passed
test/e2e-frontend/ (full) 259 passed

The taxonomy-loop rewrite is the only production behaviour change. It has no unit-level test because no router-manager.test.js exists (mocking start() means standing up eight router types); it is covered by api-vs-frontend.test.js — which stubs loadRouteSettings directly and so only runs under --project legacy — with real taxonomy maps at :372, :809 and :1137, plus the e2e-frontend routing suites.

Out of scope

toDomainNotation() in permalink-adapter.ts is dead production code (only its own unit test calls it). It is unrelated to the bridge and left for a follow-up rather than bundled here.

ref https://linear.app/ghost/issue/HKG-1898

- the bridge was the last transformation between the RouteSettings domain
  model and the routing layer; PRs for HKG-1895/1896/1897 relocated all four
  of its original conversions, leaving only a taxonomy map-to-array flatten
- RouterManager now iterates the domain `{tag, author}` map directly and
  DynamicRoutingService returns the store's model untouched, so the domain
  model flows store -> service -> routers with no intermediate shape
- the bridge also defaulted `templates` to `[]`, which is redundant: both
  collection-router and static-routes-router already default it themselves
- dropped the bridge's falsy-permalink guard rather than porting it — the
  parser rejects empty taxonomy permalinks outright, so it was unreachable
- integrity.test.js now hashes the parsed model instead of bridge output;
  `yamlSource` is excluded so the canary keeps tracking route structure
  rather than tripping on comment or whitespace edits to default-routes.yaml
ref https://linear.app/ghost/issue/HKG-1898

- the parser carried a comment justifying its rss handling in terms of the
  activation bridge and validate.js, both of which are now deleted; the
  reason stands on its own as parse/serialize round-trip fidelity
- dropped a redundant taxonomies assertion that could never fail
  independently of the deepEqual above it
- described the RouterConfig typedef as the domain model rather than "JSON
  config", matching the typedef now pointing at the domain package
@nx-cloud

nx-cloud Bot commented Aug 4, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix

Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci


View your CI Pipeline Execution ↗ for commit a45401b

Command Status Duration Result
nx run ghost:test:ci:integration ✅ Succeeded 2m 25s View ↗
nx run ghost:test:integration ✅ Succeeded 3m 18s View ↗
nx run ghost:test:legacy ✅ Succeeded 2m 54s View ↗
nx run ghost:test:e2e ✅ Succeeded 2m 43s View ↗
nx run ghost-monorepo:lint:boundaries ✅ Succeeded 21s View ↗
nx run-many -t test:unit -p ghost ✅ Succeeded 27s View ↗
nx run-many -t lint -p ghost,ghost-monorepo ✅ Succeeded 20s View ↗
nx run-many --target=build --projects=tag:publi... ✅ Succeeded 1s View ↗
nx run @tryghost/admin:build ✅ Succeeded 3s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-08-04 11:36:18 UTC

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8c9c9b62-66d4-4055-b6d0-20bf340b08e0

📥 Commits

Reviewing files that changed from the base of the PR and between cf1ff26 and f276d5b.

📒 Files selected for processing (1)
  • ghost/core/core/server/services/route-settings/route-settings-parser.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • ghost/core/core/server/services/route-settings/route-settings-parser.ts

Walkthrough

The route settings pipeline now passes parsed domain RouteSettings directly from storage to frontend routing. The activation-bridge conversion layer was removed. Taxonomy routing consumes object mappings. Route hashing excludes yamlSource. Tests cover domain-model preservation, deterministic parsing, taxonomy mounting, and updated legacy fixtures.

Possibly related PRs

Suggested labels: migration

Suggested reviewers: allouis

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: removing the route-settings activation bridge.
Description check ✅ Passed The description directly explains the bridge removal, affected data flow, behavior changes, scope, and test results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch princi-hkg-1898-remove-activation-bridge

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

ref https://linear.app/ghost/issue/HKG-1898

- iterating the domain taxonomies map is the only production behaviour change
  in this branch, and it had no unit-level test: RouterManager has never had
  one, so it was covered only indirectly by the legacy and e2e suites
- asserts against the registry rather than the routers themselves, which keeps
  the setup to a urlService stub and avoids standing up the other seven router
  types the start() path mounts
- all three cases fail against the previous array iteration, so they pin the
  new contract rather than passing vacuously

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the route-settings DDD cleanup by removing the route-settings “activation bridge” layer so the routing system now consumes the RouteSettings domain model directly (store → service → RouterManager → routers), without intermediate reshaping.

Changes:

  • Removed the route-settings activation bridge and updated DynamicRoutingService.loadRouteSettings() to return the store’s parsed domain model directly.
  • Updated RouterManager.start() to iterate the domain taxonomies map directly instead of consuming {key, permalink} entries.
  • Repointed/updated tests and the schema integrity routes canary hash to match the new (bridge-free) hashing input, excluding yamlSource.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
ghost/core/test/unit/server/services/route-settings/route-settings-parser.test.ts Adds determinism assertions for the parsed domain model serialization stability.
ghost/core/test/unit/server/services/route-settings/dynamic-routing-service.test.ts Updates unit expectations so loadRouteSettings() returns the untransformed domain model.
ghost/core/test/unit/server/services/route-settings/activation-bridge.test.ts Deletes bridge characterization/determinism tests along with the bridge.
ghost/core/test/unit/server/data/schema/integrity.test.js Rehashes default routes canary to hash parsed model (omitting yamlSource) instead of bridge output.
ghost/core/test/legacy/mock-express-style/api-vs-frontend.test.js Updates legacy fixture reshaping helper to stub the domain RouteSettings shape.
ghost/core/test/integration/services/route-settings/dynamic-routing-service.test.ts Updates integration expectations for domain-model return shape (incl. taxonomies map + yamlSource).
ghost/core/core/server/services/route-settings/route-settings-parser.ts Minor comment update; continues producing the domain model with stable property ordering.
ghost/core/core/server/services/route-settings/dynamic-routing-service.js Stops calling the activation bridge; returns store.get() result directly.
ghost/core/core/server/services/route-settings/activation-bridge.ts Removes the route-settings activation bridge implementation.
ghost/core/core/frontend/services/routing/static-routes-router.js Updates internal comment to reference parseRouteSettings as the source of type.
ghost/core/core/frontend/services/routing/router-manager.js Switches start() to accept domain RouteSettings and iterates taxonomy map entries directly.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ghost/core/core/server/services/route-settings/route-settings-parser.ts Outdated
ref https://linear.app/ghost/issue/HKG-1898

- the previous wording claimed parse -> serialize round-trips the author's
  file unchanged, which overclaims: serializeRouteSettings emits canonical
  key ordering, so a file whose keys are ordered differently comes back
  reordered
- what the explicit-rss handling actually buys is narrower and worth stating
  precisely: serializing never writes back an `rss` key the author never wrote

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.23077% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.52%. Comparing base (770b027) to head (f276d5b).

Files with missing lines Patch % Lines
...r/services/route-settings/route-settings-parser.ts 0.00% 2 Missing ⚠️
...e/core/frontend/services/routing/router-manager.js 88.88% 1 Missing ⚠️
.../frontend/services/routing/static-routes-router.js 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #29744      +/-   ##
==========================================
+ Coverage   75.47%   75.52%   +0.04%     
==========================================
  Files        1613     1612       -1     
  Lines      142161   142034     -127     
  Branches    17583    17575       -8     
==========================================
- Hits       107296   107265      -31     
+ Misses      33820    33724      -96     
  Partials     1045     1045              
Flag Coverage Δ
e2e-tests 77.65% <69.23%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vershwal
vershwal merged commit fbdcb24 into main Aug 4, 2026
50 checks passed
@vershwal
vershwal deleted the princi-hkg-1898-remove-activation-bridge branch August 4, 2026 11:51
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.

2 participants