{"id":"69a2c1ba02f069bcaa587514","title":"2026 02 28","path":"how-to/committee/release-notes/2026-02-28","contentMarkdown":"# 28-Feb-2026 — page-editor: restore enrichment query for cross-hierarchy content paths [#170](https://github.com/nbarrett/ngx-ramblers/issues/170)\n\n## [build 505](https://github.com/nbarrett/ngx-ramblers/actions/runs/22518639185) — [commit 6001af4](https://github.com/nbarrett/ngx-ramblers/commit/6001af42a5db773c6cb18ca7c79edce69bc03515)\n\n_____\n\nReverts the single raw-regex query approach which broke image resolution\nfor index pages whose child content paths reference pages outside the\nparent path hierarchy (e.g. test-gallery/ → gallery/...).\n- Restore depth-limited regex for the top-level query (direct children)\n- Restore enrichment query in `enrichIndexColumnsWithImages` using child\nindexes' own content paths (handles cross-hierarchy references)\n- Remove `allPrefetchedPages` parameter — enrichment fetches its own pages\n- Keep `findFirstImageInPage` fallback for TEXT-row-based image sources\n\n### Performance\n- Replace O(N) recursive `resolveIndexContent` calls with single batch DB query\nusing raw regex, with client-side `filterByMaxPathSegments` filtering\n- Remove redundant broad prefetch that fetched all sub-pages unnecessarily\n- Eliminate separate enrichment and grandchild queries in\n`enrichIndexColumnsWithImages` by passing pre-fetched pages from the\ntop-level query — reduces page-content API calls from 3 to 1\n### Image Resolution\n- Fix broken images on deeply nested index pages (e.g. by-year → year →\nvolume → walk) by using unfiltered pre-fetched pages for image search\nacross all depth levels\n- Add `findFirstImageInPage` fallback in `enrichIndexColumnsWithImages`\nfor pages that use TEXT rows with column-level `imageSource` instead of\nCAROUSEL/ALBUM rows (affects Berkshire Weekend Walkers scrapbook)\n- Skip `album-index` rows in `findFirstImageInPage` to avoid picking up\nstale/default images from index row column data\n### Code Cleanup\n- Remove dead code: `resolveIndexContent`, `nextVisitedPaths`, broad\nprefetch, `visitedPaths`/`prefetchedPages`/`depth` parameters from\npublic API\n- Simplify `albumIndexToPageContent` signature to just\n`(pageContentRow, rowIndex)`\n- Add `depthLimitedRegex` helper for STARTS_WITH with maxPathSegments\n- Add batched walk lookup in `extractAlbumColumns` for album locations\n### Testing\n- Add 54 unit tests for IndexService helper methods covering\n`depthLimitedRegex`, `findFirstImageInPage`, `findFirstTextInPage`,\n`optimiseIndexImageSource`, `summarizeTitles`, `deduplicateByHref`,\n`calculateDataCompletenessScore`, `sortColumns`,\n`filterOutExcludedPaths`, `filterByMaxPathSegments`, `pageContentFrom`\n### Location Extraction\n- Handle `album-index` rows in `extractTitleAndDescription` via\n`indexMarkdown`\n- Skip `album-index` rows in `findFirstImageInPage`\n\n- Use match-type-aware regex in index prefetch query so \"Contains\" paths no longer force a starts-with pattern\n- Update filterByMaxPathSegments to respect the configured match type instead of hardcoding startsWith\n- Read carousel image titles and dates from gridViewOptions to match the editor's data model\n- Add move-to-exclude and move-to-include buttons on content path match rows","contentHtml":"<h1>28-Feb-2026 — page-editor: restore enrichment query for cross-hierarchy content paths <a href=\"https://github.com/nbarrett/ngx-ramblers/issues/170\">#170</a></h1>\n<h2><a href=\"https://github.com/nbarrett/ngx-ramblers/actions/runs/22518639185\">build 505</a> — <a href=\"https://github.com/nbarrett/ngx-ramblers/commit/6001af42a5db773c6cb18ca7c79edce69bc03515\">commit 6001af4</a></h2>\n<hr>\n<p>Reverts the single raw-regex query approach which broke image resolution\nfor index pages whose child content paths reference pages outside the\nparent path hierarchy (e.g. test-gallery/ → gallery/...).</p>\n<ul>\n<li>Restore depth-limited regex for the top-level query (direct children)</li>\n<li>Restore enrichment query in <code>enrichIndexColumnsWithImages</code> using child\nindexes&#39; own content paths (handles cross-hierarchy references)</li>\n<li>Remove <code>allPrefetchedPages</code> parameter — enrichment fetches its own pages</li>\n<li>Keep <code>findFirstImageInPage</code> fallback for TEXT-row-based image sources</li>\n</ul>\n<h3>Performance</h3>\n<ul>\n<li>Replace O(N) recursive <code>resolveIndexContent</code> calls with single batch DB query\nusing raw regex, with client-side <code>filterByMaxPathSegments</code> filtering</li>\n<li>Remove redundant broad prefetch that fetched all sub-pages unnecessarily</li>\n<li>Eliminate separate enrichment and grandchild queries in\n<code>enrichIndexColumnsWithImages</code> by passing pre-fetched pages from the\ntop-level query — reduces page-content API calls from 3 to 1</li>\n</ul>\n<h3>Image Resolution</h3>\n<ul>\n<li>Fix broken images on deeply nested index pages (e.g. by-year → year →\nvolume → walk) by using unfiltered pre-fetched pages for image search\nacross all depth levels</li>\n<li>Add <code>findFirstImageInPage</code> fallback in <code>enrichIndexColumnsWithImages</code>\nfor pages that use TEXT rows with column-level <code>imageSource</code> instead of\nCAROUSEL/ALBUM rows (affects Berkshire Weekend Walkers scrapbook)</li>\n<li>Skip <code>album-index</code> rows in <code>findFirstImageInPage</code> to avoid picking up\nstale/default images from index row column data</li>\n</ul>\n<h3>Code Cleanup</h3>\n<ul>\n<li>Remove dead code: <code>resolveIndexContent</code>, <code>nextVisitedPaths</code>, broad\nprefetch, <code>visitedPaths</code>/<code>prefetchedPages</code>/<code>depth</code> parameters from\npublic API</li>\n<li>Simplify <code>albumIndexToPageContent</code> signature to just\n<code>(pageContentRow, rowIndex)</code></li>\n<li>Add <code>depthLimitedRegex</code> helper for STARTS_WITH with maxPathSegments</li>\n<li>Add batched walk lookup in <code>extractAlbumColumns</code> for album locations</li>\n</ul>\n<h3>Testing</h3>\n<ul>\n<li>Add 54 unit tests for IndexService helper methods covering\n<code>depthLimitedRegex</code>, <code>findFirstImageInPage</code>, <code>findFirstTextInPage</code>,\n<code>optimiseIndexImageSource</code>, <code>summarizeTitles</code>, <code>deduplicateByHref</code>,\n<code>calculateDataCompletenessScore</code>, <code>sortColumns</code>,\n<code>filterOutExcludedPaths</code>, <code>filterByMaxPathSegments</code>, <code>pageContentFrom</code></li>\n</ul>\n<h3>Location Extraction</h3>\n<ul>\n<li><p>Handle <code>album-index</code> rows in <code>extractTitleAndDescription</code> via\n<code>indexMarkdown</code></p>\n</li>\n<li><p>Skip <code>album-index</code> rows in <code>findFirstImageInPage</code></p>\n</li>\n<li><p>Use match-type-aware regex in index prefetch query so &quot;Contains&quot; paths no longer force a starts-with pattern</p>\n</li>\n<li><p>Update filterByMaxPathSegments to respect the configured match type instead of hardcoding startsWith</p>\n</li>\n<li><p>Read carousel image titles and dates from gridViewOptions to match the editor&#39;s data model</p>\n</li>\n<li><p>Add move-to-exclude and move-to-include buttons on content path match rows</p>\n</li>\n</ul>\n"}