Context
Issue #10056 originally asked the Portal News section to surface Pull Requests and Discussions in the app and in generated SEO outputs. Current dev reality has moved on: Epic #12204 superseded #10056 in planning and is now closed complete with 19/19 sub-issues complete, and #12210 closed the PR/Discussion index-generator prerequisite.
The stale broad ticket should not be re-used as an implementation lane, because most of its body is already delivered. The remaining observed gap is narrower and machine-facing: buildScripts/docs/seo/generate.mjs still does not enumerate PR or Discussion content routes for sitemap / llms.txt generation.
The Problem
V-B-A on current source shows the Portal app has the PR/Discussion view/data surfaces, but the SEO generator still only treats issues and release notes as GitHub News content:
apps/portal/view/news/TabContainer.mjs includes /news/pulls and /news/discussions tabs.
apps/portal/view/news/pulls/ and apps/portal/view/news/discussions/ exist with route controllers and lazy tree consumers.
buildScripts/docs/index/pulls.mjs and buildScripts/docs/index/discussions.mjs exist and emit chunked JSON data under apps/portal/resources/data/{pulls,discussions}/.
buildScripts/docs/seo/generate.mjs currently has collectReleaseRoutes() and collectIssueRoutes(), but no PR or Discussion route collectors.
collectAllRoutes() currently includes top-level, learn-tree content, examples, releases, and issues only.
getLlmsTxt() currently groups release-notes, tickets, examples, top-level pages, and learn-tree content; it does not include GitHub Pull Requests or GitHub Discussions sections.
Reproducer evidence:
node buildScripts/docs/seo/generate.mjs --format urls --base-url https://neomjs.com | rg "/news/(pulls|discussions)"
<h1 class="neo-h1" data-record-id="4">no output</h1>
node buildScripts/docs/seo/generate.mjs --format llms --base-url https://neomjs.com | rg "Pull Requests|Discussions|GitHub Tickets|news/pulls|news/discussions"
<h1 class="neo-h1" data-record-id="5">only the GitHub Tickets section is present</h1>
The Architectural Reality
The owning substrate is buildScripts/docs/seo/generate.mjs, not generated files such as apps/portal/llms.txt or apps/portal/sitemap.xml. This matches the generated-output rule already used by #12225 / #12253 / #12259.
The source content already exists in synced markdown:
- Active PR files:
resources/content/pulls/**/pr-*.md
- Archived PR files:
resources/content/archive/pulls/**/pr-*.md
- Active Discussion files:
resources/content/discussions/**/discussion-*.md
- Archived Discussion files:
resources/content/archive/discussions/**/discussion-*.md
The route shape should mirror the shipped Portal routes:
- PR route id:
/news/pulls/<number>
- Discussion route id:
/news/discussions/<number>
The Fix
Add PR and Discussion route support to the SEO generator:
- Add
collectPullRoutes() scanning active and archived pr-*.md files and producing {category: 'pull-requests', filePath, id: '/news/pulls/<number>', pullNum} records sorted newest/highest number first.
- Add
collectDiscussionRoutes() scanning active and archived discussion-*.md files and producing {category: 'discussions', filePath, id: '/news/discussions/<number>', discussionNum} records sorted newest/highest number first.
- Wire both collectors into
collectAllRoutes() so getSitemapXml(), URL output, object output, and llms.txt consume the same route set.
- Extend
getPriority() for /news/pulls/ and /news/discussions/ per #10056's original SEO intent, with current priority values verified in the PR body.
- Extend
getLlmsTxt() with explicit GitHub Pull Requests and GitHub Discussions sections that map to raw markdown URLs, mirroring the GitHub Tickets section.
- Regenerate generated SEO outputs only if the established release/build workflow for this repo expects generated files to be committed for this surface; otherwise document why the generator-only change is sufficient.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
buildScripts/docs/seo/generate.mjs route collection |
#10056 residual + current Portal route controllers |
Include PR and Discussion markdown as /news/pulls/<number> and /news/discussions/<number> routes |
Current generator omits them from sitemap / URL output |
JSDoc on the new collectors |
--format urls emits PR/Discussion routes |
getLlmsTxt() machine-reader output |
#10056 SEO/LLM value + existing GitHub Tickets section |
Include Pull Requests and Discussions sections with raw markdown URLs |
Current output lists tickets only |
Generator source, not hand-edited output |
--format llms contains the new sections |
| Sitemap priority |
#10056 priority intent + current getPriority() route classifier |
Assign specific priorities for /news/pulls/* and /news/discussions/* |
Fall back to DEFAULT_PRIORITY |
getPriority() comments / PR body |
--format xml spot-check or unit/assertion evidence |
Decision Record Impact
None. This is aligned with the existing generated-SEO-source discipline from #12225 / #12253 / #12259 and with #12204's Portal News route architecture.
Acceptance Criteria
Out of Scope
- Rebuilding the Portal PR/Discussion UI. That work was delivered under #12204 and follow-up tickets.
- Changing the synced markdown grammar for PRs or Discussions.
- Reworking the chunked Portal data index generators.
- Editing generated SEO files by hand.
- General SEO identity-copy changes unrelated to PR/Discussion route discovery.
Avoided Traps
- Reusing #10056 as-is. It now bundles mostly delivered work and would mislead future agents into rebuilding closed #12204 scope.
- Hand-editing
apps/portal/llms.txt or sitemap output. The generator owns the durable behavior.
- Adding a new Portal app tab or data generator. Those exist already.
Duplicate Sweep
- Live latest-open sweep: checked latest 20 open GitHub issues on 2026-06-06 via
gh issue list --state open --limit 20 --json number,title,author,labels,url; no equivalent PR/Discussion SEO route ticket found.
- Knowledge Base semantic sweep attempted with
ask_knowledge_base("Portal News Pull Requests Discussions issue 10056 current implementation"), but the KB collection is currently unavailable (collection not found). KB silence was not treated as evidence.
- Local exact sweep across
resources/content/issues, resources/content/archive/issues, resources/content/pulls, and resources/content/discussions found the successor chain #12204, #12210, #12219, #12300 and adjacent SEO work #12225 / #12253 / #12255 / #12259, but no open equivalent for adding PR/Discussion route collectors to generate.mjs.
- GitHub Search API endpoint returned 404 through this shell path; live issue-list + local synced corpus were used as the reliable duplicate sweep.
Related
- Supersedes the residual SEO portion of #10056.
- #12204 closed complete — Portal news PR/Discussion views + chunked lazy-load tree.
- #12210 closed — PR/Discussion index generators.
- #12225 / #12253 / #12255 / #12259 — adjacent generated SEO source discipline.
Origin Session ID: 019e98ad-5af5-7981-be15-dfc740a81d46
Handoff Retrieval Hint: "#10056 portal news PR Discussion generated SEO routes collectPullRoutes collectDiscussionRoutes llms sitemap"
Context
Issue #10056 originally asked the Portal News section to surface Pull Requests and Discussions in the app and in generated SEO outputs. Current
devreality has moved on: Epic #12204 superseded #10056 in planning and is now closed complete with 19/19 sub-issues complete, and #12210 closed the PR/Discussion index-generator prerequisite.The stale broad ticket should not be re-used as an implementation lane, because most of its body is already delivered. The remaining observed gap is narrower and machine-facing:
buildScripts/docs/seo/generate.mjsstill does not enumerate PR or Discussion content routes for sitemap /llms.txtgeneration.The Problem
V-B-A on current source shows the Portal app has the PR/Discussion view/data surfaces, but the SEO generator still only treats issues and release notes as GitHub News content:
apps/portal/view/news/TabContainer.mjsincludes/news/pullsand/news/discussionstabs.apps/portal/view/news/pulls/andapps/portal/view/news/discussions/exist with route controllers and lazy tree consumers.buildScripts/docs/index/pulls.mjsandbuildScripts/docs/index/discussions.mjsexist and emit chunked JSON data underapps/portal/resources/data/{pulls,discussions}/.buildScripts/docs/seo/generate.mjscurrently hascollectReleaseRoutes()andcollectIssueRoutes(), but no PR or Discussion route collectors.collectAllRoutes()currently includes top-level, learn-tree content, examples, releases, and issues only.getLlmsTxt()currently groupsrelease-notes,tickets, examples, top-level pages, and learn-tree content; it does not include GitHub Pull Requests or GitHub Discussions sections.Reproducer evidence:
node buildScripts/docs/seo/generate.mjs --format urls --base-url https://neomjs.com | rg "/news/(pulls|discussions)" <h1 class="neo-h1" data-record-id="4">no output</h1> node buildScripts/docs/seo/generate.mjs --format llms --base-url https://neomjs.com | rg "Pull Requests|Discussions|GitHub Tickets|news/pulls|news/discussions" <h1 class="neo-h1" data-record-id="5">only the GitHub Tickets section is present</h1>The Architectural Reality
The owning substrate is
buildScripts/docs/seo/generate.mjs, not generated files such asapps/portal/llms.txtorapps/portal/sitemap.xml. This matches the generated-output rule already used by #12225 / #12253 / #12259.The source content already exists in synced markdown:
resources/content/pulls/**/pr-*.mdresources/content/archive/pulls/**/pr-*.mdresources/content/discussions/**/discussion-*.mdresources/content/archive/discussions/**/discussion-*.mdThe route shape should mirror the shipped Portal routes:
/news/pulls/<number>/news/discussions/<number>The Fix
Add PR and Discussion route support to the SEO generator:
collectPullRoutes()scanning active and archivedpr-*.mdfiles and producing{category: 'pull-requests', filePath, id: '/news/pulls/<number>', pullNum}records sorted newest/highest number first.collectDiscussionRoutes()scanning active and archiveddiscussion-*.mdfiles and producing{category: 'discussions', filePath, id: '/news/discussions/<number>', discussionNum}records sorted newest/highest number first.collectAllRoutes()sogetSitemapXml(), URL output, object output, andllms.txtconsume the same route set.getPriority()for/news/pulls/and/news/discussions/per #10056's original SEO intent, with current priority values verified in the PR body.getLlmsTxt()with explicit GitHub Pull Requests and GitHub Discussions sections that map to raw markdown URLs, mirroring the GitHub Tickets section.Contract Ledger Matrix
buildScripts/docs/seo/generate.mjsroute collection/news/pulls/<number>and/news/discussions/<number>routes--format urlsemits PR/Discussion routesgetLlmsTxt()machine-reader outputGitHub Ticketssection--format llmscontains the new sectionsgetPriority()route classifier/news/pulls/*and/news/discussions/*DEFAULT_PRIORITYgetPriority()comments / PR body--format xmlspot-check or unit/assertion evidenceDecision Record Impact
None. This is aligned with the existing generated-SEO-source discipline from #12225 / #12253 / #12259 and with #12204's Portal News route architecture.
Acceptance Criteria
node buildScripts/docs/seo/generate.mjs --format urls --base-url https://neomjs.com | rg "/news/pulls/"returns PR routes.node buildScripts/docs/seo/generate.mjs --format urls --base-url https://neomjs.com | rg "/news/discussions/"returns Discussion routes.node buildScripts/docs/seo/generate.mjs --format llms --base-url https://neomjs.comcontains explicit GitHub Pull Requests and GitHub Discussions sections.getPriority()classifies/news/pulls/*and/news/discussions/*explicitly rather than relying onDEFAULT_PRIORITY.apps/portal/llms.txt/ sitemap output is committed or intentionally left to the release pipeline.Out of Scope
Avoided Traps
apps/portal/llms.txtor sitemap output. The generator owns the durable behavior.Duplicate Sweep
gh issue list --state open --limit 20 --json number,title,author,labels,url; no equivalent PR/Discussion SEO route ticket found.ask_knowledge_base("Portal News Pull Requests Discussions issue 10056 current implementation"), but the KB collection is currently unavailable (collection not found). KB silence was not treated as evidence.resources/content/issues,resources/content/archive/issues,resources/content/pulls, andresources/content/discussionsfound the successor chain #12204, #12210, #12219, #12300 and adjacent SEO work #12225 / #12253 / #12255 / #12259, but no open equivalent for adding PR/Discussion route collectors togenerate.mjs.Related
Origin Session ID: 019e98ad-5af5-7981-be15-dfc740a81d46
Handoff Retrieval Hint: "#10056 portal news PR Discussion generated SEO routes collectPullRoutes collectDiscussionRoutes llms sitemap"