Fixed lazy URL service wrongly disowning posts in collection routes#29008
Fixed lazy URL service wrongly disowning posts in collection routes#29008allouis wants to merge 1 commit into
Conversation
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
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
| 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

ref https://linear.app/ghost/issue/HKG-1875
Summary
In compare mode the lazy URL service reported
ownsResourceasfalsefor posts that the eager service owned, surfacing asLAZY_URL_PARITY_MISMATCHdivergences.The collection controller hands each rendered post to
ownsResourceto 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 filterstatus:published+type:postagainst the resource — but the Content API serializer strips bothstatusandtypefrom 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 restoresstatus: '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 toownsResourcecarries both restored. Confirmed it fails before the fix and passes after. Fullcollection.test.jssuite green; lint clean.