LearnNewsExamplesServices
Frontmatter
id14496
titleSync learn/** to neomjs/pages in the hourly data-sync pipeline
stateClosed
labels
bugaibuild
assigneesneo-fable-clio
createdAtJul 2, 2026, 6:26 PM
updatedAtJul 2, 2026, 6:44 PM
githubUrlhttps://github.com/neomjs/neo/issues/14496
authorneo-fable-clio
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 2, 2026, 6:44 PM

Sync learn/** to neomjs/pages in the hourly data-sync pipeline

neo-fable-clio
neo-fable-clio commented on Jul 2, 2026, 6:26 PM

Context

Operator-directed production investigation (2026-07-02): Google Cloud statistics report a sustained 404 wave on neomjs.com. One of the two root causes lives in this repo's data-sync pipeline: the hourly job advances the advertised route surface (sitemap.xml, llms.txt, portal data indexes) but never syncs the learn/** markdown those routes point at. Operator ruling on the fix side (verbatim): "you already figured out the solutions, so of course i approve" — workflow-side sync approved; 404s are causing Googlebot ranking downgrades, so this is business-tier, not cosmetic.

Live latest-open sweep: checked latest 20 open issues at 2026-07-02T16:15Z; no equivalent found. A2A in-flight sweep: latest 30 all-status messages at 16:15Z; no competing claim (my own 16:06Z investigation broadcast announced this filing).

The Problem

The Push Data to neomjs/pages step copies, hourly: devindex users.jsonl, apps/portal/resources/data/*.json (flat glob), sitemap.xml, llms.txt, and the six resources/content/* archive buckets. It does not copy learn/**.

neomjs/pages (= neomjs.github.io) is where human traffic is served. Its node_modules/neo.mjs/learn/** tree only refreshes on release-time/manual full deploys. Verified consequences (2026-07-02):

  • pages:node_modules/neo.mjs/learn/blog/ holds 11 files, newest cohort v10-era; dev has 14 — every post since the last full deploy is an advertised dead link (specimen: the April time-capsule post, merged 11:52Z today via #14465, present in the hourly-synced sitemap, absent in pages).
  • learn/tree.json (the SPA's learn navigation index) also lives in the unsynced tree — so even the nav index on production is release-frozen while sitemap.xml advances hourly. Index-advances-without-content is structural, exactly as the operator reported.
  • The flat *.json glob misses apps/portal/resources/data/ subdirectories (e.g. tickets/v*/, pulls/latest/ chunk trees), which drift the same way between full deploys.

Route-class blast note: this is one of two stacked causes. The sibling cause (deployment middleware frozen by dirty-checkout halts) is #14478 + private-repo work; this ticket heals the human-traffic class independently of that chain.

The Architectural Reality

  • Workflow: .github/workflows/data-sync-pipeline.yml, Push Data to neomjs/pages step — the established sync pattern is rm -rf + cp -r per directory ("syncing deletions natively via git", per the Epic #11187 7-bucket fan-out comment in the workflow itself).
  • Pages layout: content roots under temp_pages/node_modules/neo.mjs/ (verified live via the GitHub contents API — the blog listing above).
  • Neo-side commit step (dev push) is untouched: learn/** is authored source in this repo; only the pages-push step needs the additional copy set.
  • The pages commit already uses --no-verify (no archaeology guard on the pages clone) — no new commit-gating concerns.

The Fix

In the Push Data to neomjs/pages step:

  1. Add learn to the deletion-synced copy set, same pattern as the content buckets:
       rm -rf temp_pages/node_modules/neo.mjs/learn
    cp -r learn temp_pages/node_modules/neo.mjs/
  2. Replace the flat portal-data copy with a deletion-synced recursive copy of apps/portal/resources/data/ (covers the chunked subdirectories).
  3. Extend the pages-side change-detection git status -s path list and git add set accordingly (git add -A on the two synced roots).

No new scripts, no new secrets, no .mjs files (structural pre-flight N/A).

Acceptance Criteria

  • learn/** (including learn/tree.json) syncs to temp_pages/node_modules/neo.mjs/learn/ hourly with deletion sync (removed/renamed source files disappear from pages — required for route renames like the #14311 Introduction reshape to propagate instead of leaving stale duplicates).
  • apps/portal/resources/data/** syncs recursively (subdirectory chunk trees included), deletion-synced.
  • Change detection + git add cover the new paths (no silent "No changes detected" when only learn/** changed).
  • Post-merge validation (flagged post-merge-only): after the next hourly run following a learn/** change on dev, the changed file is present in neomjs/pages — specimen check: learn/blog/the-organism-already-existed.md exists in pages.
  • Workflow comment documents the copy-set rationale (advertised-route/content coherence) with a pointer to this ticket.

Out of Scope

  • The middleware freeze + auto-deploy leg (private-repo work, routed to the operator; neo-side sibling is #14478).
  • Release-time full-tree pages deploys (unchanged; this ticket only closes the hourly gap between them).
  • apps/portal/index.html / app-shell assets (release-owned, not content-churned).

Avoided Traps

  • Middleware-side-only fix rejected: human traffic proxies to pages; a middleware fix alone leaves the human class dead.
  • Syncing the whole repo tree rejected: the copy set stays scoped to content that routes advertise (learn + portal data), keeping the hourly commit small and reviewable.
  • Symlink/submodule schemes rejected: the workflow's established rm -rf+cp -r deletion-sync pattern is proven and native to the pages history.

Decision Record impact

none — aligned with the Epic #11187 fan-out pattern already governing this workflow step.

Related

#14478 (sibling root cause — tracked runtime files freeze the middleware pulls) · #14465 (live dead-link specimen) · #14311/PR #14470 (route reshape whose propagation depends on deletion sync) · Epic #11187 (the workflow's content fan-out pattern) · the #14470 cycle-3 deployment-blast-radius lesson (public routes are deployment substrate).

Origin Session ID: 4ebdc396-4bd7-4dee-b16b-23baf188a622

Retrieval Hint: query_raw_memories("neomjs.com 404 wave pages learn sync middleware freeze deployment blast radius")

tobiu referenced in commit 2f51e15 - "fix(build): sync learn content and recursive portal data to pages (#14496) (#14497)" on Jul 2, 2026, 6:44 PM
tobiu closed this issue on Jul 2, 2026, 6:44 PM