Sync the project docs mount instead of hand-vendoring it #135
Labels
No labels
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
burndown-2026-06
burndown-2026-08
icebox
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilysiren/website#135
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Angie's lane on
coilysiren/inbox#438, split out because that bullet is a lane assignment inside a design brief rather than a trackable unit of work, and because the shape is now concrete: umbra's mount landed onmainand the only thing keeping itnoindexis that the copy is hand-made.The gap
src/projects/umbra-docs/holds 21 files copied by hand fromcoilyco-flight-deck/umbraat commit2285380. Verified byte-identical at the time of copying, so the problem is not that it is wrong. The problem is that nothing keeps it right.Indexing a drifting copy manufactures exactly the failure
#133names: if a page and a repository disagree about what a project is, the repository wins and the page is the bug. That would be 21 bugs on the canonical domain, so the mount stays out of the index until a sync exists.Interim guard already in place:
umbraDocsSourceinsrc/data/umbra-docs.jsrecords the source commit, and every docs page prints it and names the repository as the source of truth. That converts silent drift into visible drift. It is not a substitute for the sync.What is already built, so this is smaller than it sounds
None of the hard parts are copy logic, and all of them are done and tested:
src/data/umbra-docs.js- the manifest. Section tree, reading order, sidebar, front door and prev/next all derive from it.documentation-layoutpermits no subdirectories underdocs/, so this is the only place section structure can live.src/projects/umbra-docs/umbra-docs.11tydata.js- permalink, title, shelf and reading position computed from the filename, so vendored files need no front matter and stay verbatim.mountedDocLinksineleventy.config.js- rewrites repo-relative.mdlinks. 47 of them in umbra alone. A mounted target becomes its route, an unmounted one points back at the file in its own repo.docs/project-docs-mount.md- the whole contract, including why the mount is excluded fromdead-cross-links.What is missing is the step that replaces
cpwith a fetch, plus writing one commit string.Recommended shape
Committed vendor, refreshed by a scheduled Forgejo Action. A workflow clones the source repo, copies
docs/through the exclusion list, updatesumbraDocsSource, and commits.#438's "verbatim needs an exclusion list" requirement needs anyway.agentic-os-kaiassync-repo-registry.ymlandsync-repo-digests.yml.Rejected: fetching at build time, because local dev then diverges from CI unless a cached fallback exists, and the fallback is the vendored copy again. Rejected: submodules, because the exclusion list needs per-file control.
Carry these across
#438names the planning artifacts that must not mount:repository-plan.md,claude-native-ui-plan.mdand threeeval-ref-*pages in agent-compose,worklog.mdandissues.mdin sirens-echo.dead-cross-linksexclude also flips that hook to a full-tree walk, which surfaced a pre-existingsrc/pages/resume.mdlink and pulledsrc/pages/**into the same list. The other three repos will hit this again.architecture.mdpoints atfeatures-detail.md, which does not exist.CONTRIBUTING.mdpoints atCODE_OF_CONDUCT.mdandSECURITY.md, which live at the repo root rather than underdocs/. Worth fixing upstream rather than papering over here.Done means
src/projects/umbra-docs/is produced by a workflow rather than by handumbraDocsSourceis written by the same step that copies the filesfollow, indexand intoCANONICAL_ROUTESandllms.txtThat last box is not this issue's to tick.
#133's done-means list also requires a Search Console baseline recorded before publication, which is Kai's.Related:
coilysiren/inbox#438,coilysiren/website#133.Landed on
main. Full pipeline green on20bd2fd: test, test-e2e, mirror, staging image, TruffleHog.Done means
src/projects/umbra-docs/is produced by a workflow.scripts/sync-project-docs.pyclones each source shallow, copies what the exclusion list permits, and writes the stamp. Running it against the hand copy changed nothing: 21 files, byte-identical, at the commit the stamp already named, which is the strongest evidence available that it reproduces what was there.src/data/docs-mounts.jsoncarries source, target, and exclusions per project, plus the lists for the repos not mounted yet, so #438's must-not-mount set survives until agent-compose and sirens-echo land.umbraDocsSourceis written by the same step that copies the files. It is generated intosrc/data/docs-mount-source.jsonand joined in atsrc/_data/umbraDocs.js, so the manifest went back to pure hand-written structure and a generated file no longer shares a path with a reviewed one.src/docs-mount.test.tsfails the ordinary gate at 14 days. Both forced and observed: backdating givesumbra was last synced 57 days ago, and an unlisted file in the mount fails the manifest-agreement check.CANONICAL_ROUTES. Left as filed. Drift is no longer what holds it, so what remains is #133's Search Console baseline, which is Kai's.Proven rather than assumed
Dispatched the workflow on the real runner (run 629, success):
Checkout token, egress to the source repo, and the exit-without-pushing path all work.
Two things found on the way
test-e2ewas already red before this, on the parent commit7ffe7c2and every one of the 21 docs pages:landmark-main-is-top-level,landmark-no-duplicate-main,landmark-unique.base.njkopens the page's<main>and the docs frame opened a second inside it. So the mount shipped with an accessibility failure that its own coverage was reporting to nobody. Fixed in4a7b2cb: the inner element is adivkeeping the id the skip link targets, withtabindex="-1"so the skip moves focus. Cypress went from 22 passing and 21 failing to 89 passing.The sync runs on the runner, not through
scripts/ci/run-in-container.sh. That adapter streams the checkout in withtar | docker run, so files written inside the container never come back. Worth knowing before anyone adds a second write-back job. Git and python3 are all this needs, which is whatmirror-to-github.shalready assumes.Also:
code-commentsreads tracked files, so a new file passes--all-fileswhile untracked and fails on the commit after the one that lands it. That cost20bd2fd.