Skip to content

Fixed lazy URL service wrongly disowning posts in collection routes - #29008

Merged
allouis merged 1 commit into
mainfrom
lazy-url-collection-post-ownership
Jul 2, 2026
Merged

Fixed lazy URL service wrongly disowning posts in collection routes#29008
allouis merged 1 commit into
mainfrom
lazy-url-collection-post-ownership

Conversation

@allouis

@allouis allouis commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

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

Summary

In compare mode the lazy URL service reported ownsResource as false for posts that the eager service owned, surfacing as LAZY_URL_PARITY_MISMATCH divergences.

The collection controller hands each rendered post to ownsResource to drop posts that a higher-priority collection actually owns (so the same post never renders on two collection URLs). The lazy service decides ownership by evaluating the base filter status:published+type:post against the resource — but the Content API serializer strips both status and type from public posts, so the filter never matched and every candidate post was disowned and removed from the collection.

The eager service is unaffected: it owns by cache id membership (hasId), with the base filter applied once at fetch time against full models, so it never re-evaluates the filter per call.

Fix

The controller already restored type; this restores status: 'published' as well, which is always correct because collections only ever load published posts (postsPublic). Restoring the stripped column keeps the base filter fully enforced rather than relaxing it, preserving parity with eager.

Testing

TDD: added a controller unit test that simulates a Content-API-stripped post (no type/status) and asserts the resource handed to ownsResource carries both restored. Confirmed it fails before the fix and passes after. Full collection.test.js suite green; lint clean.

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

- in compare mode the lazy URL service reported ownsResource false for
  posts the eager service owned, surfacing as LAZY_URL_PARITY_MISMATCH
- the collection controller hands each rendered post to ownsResource to
  drop posts a higher-priority collection owns; the lazy service decides
  ownership by evaluating the base filter status:published+type:post
  against the resource, but the Content API serializer strips both
  status and type from public posts, so the filter never matched and
  every candidate post was disowned and removed from the collection
- the eager service is unaffected: it owns by cache id membership
  (hasId), with the base filter applied once at fetch against full
  models, so it never re-evaluates the filter per call
- the controller already restored type; restore status: 'published' as
  well, which is always correct because collections only ever load
  published posts. Restoring the stripped column keeps the base filter
  fully enforced rather than relaxing it, preserving parity with eager
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4b2ff2f5-a638-4a78-87d5-e6c01848a868

📥 Commits

Reviewing files that changed from the base of the PR and between 6530493 and 6ce674e.

📒 Files selected for processing (2)
  • ghost/core/core/frontend/services/routing/controllers/collection.js
  • ghost/core/test/unit/frontend/services/routing/controllers/collection.test.js

Walkthrough

Changes

In the collection controller, the ownership-check resource object now includes both type and status: 'published', rather than type alone, when filtering posts for ownership via routerManager.ownsResource. This ensures posts stripped of status by the Content API are still correctly evaluated as owned. A new unit test was added verifying that the resource object passed to the ownership check includes the restored type and status fields when the Content API response omits them.

Related issues: None specified

Related PRs: None specified

Suggested labels: None specified

Sequence Diagram(s)

sequenceDiagram
  participant collectionController
  participant routerManager

  collectionController->>collectionController: build resource {...post, type, status: 'published'}
  collectionController->>routerManager: ownsResource(resource)
  routerManager-->>collectionController: ownership result
Loading

Suggested reviewers: vershwal

✨ 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 lazy-url-collection-post-ownership

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

@nx-cloud

nx-cloud Bot commented Jul 1, 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 6ce674e

Command Status Duration Result
nx run ghost:test:ci:integration ✅ Succeeded 2m 36s View ↗
nx run ghost:test:integration ✅ Succeeded 2m 50s View ↗
nx run ghost:test:legacy ✅ Succeeded 3m 2s View ↗
nx run ghost:test:e2e ✅ Succeeded 2m 28s View ↗
nx run-many --target=build --projects=tag:publi... ✅ Succeeded <1s View ↗
nx run-many -t lint -p ghost ✅ Succeeded 35s View ↗
nx run-many -t test:unit -p ghost ✅ Succeeded 29s View ↗
nx run @tryghost/admin:build ✅ Succeeded 8s View ↗
Additional runs (2) ✅ Succeeded ... View ↗

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


☁️ Nx Cloud last updated this comment at 2026-07-01 08:04:10 UTC

@allouis
allouis marked this pull request as ready for review July 2, 2026 07:45
@allouis
allouis merged commit 9e2f320 into main Jul 2, 2026
43 of 44 checks passed
@allouis
allouis deleted the lazy-url-collection-post-ownership branch July 2, 2026 07:45
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