Repository navigation
refactor: authored prose moves to src/content/ - #456
Merged
Merged
Conversation
www/writing/, www/md/ and the four root .md documents become src/content/. The writing posts and their posts.json, the hand-authored twins for the three Worker-rendered pages, and index/README/auth/resume are AUTHORED text, not assets that happen to sit in the served tree. Sixth slice of lifting the parked bun branch's renames onto main, and the second of three that finish www/. EVERY PUBLIC URL IS UNCHANGED. Unlike the dictionaries in #455, most of this IS served (/writing/<slug>.txt, /index.md, /resume.md), so build.mjs stages src/content back into the served tree at the same paths. Source layout and URL layout are different questions; only the first one moved. Staged tree byte-identical across 1497 files, except three Worker sources whose COMMENTS name a moved path. Those reach the bundle and no served asset. TWO THINGS THE GATES CAUGHT, both from a path sweep that could not tell one kind of reference from another: * gen-md-twins.mjs's HAND_DIR was the string "www/md" with no trailing slash, so the sweep missed it and the three hand-authored twins stopped publishing. routes:check found it: /security.md, /lens.md, /coffee.md, /around.md and /terminal.md all 404. * the same script decides a COMMITTED twin wins by looking for it under www/. With index.md moved, that lookup silently failed and the generator wrote its own homepage twin over the hand-written one: 2170 bytes where the real file is 2642. Nothing errored. The byte control is what surfaced it. Both are the same lesson as the icons.svg path in #452: a path that names a repository location from inside a program keeps working right up until the location moves, and the failure is quiet. Gates: 305 tests, build, routes:check, lint, typecheck, pages:check, tools:check, perf-budget, photos:check, check-wrangler, cal, wrangler dry-run.
oddharsh
enabled auto-merge (squash)
August 18, 2026 15:39
Contributor
Wire-size diff vs merge base
Brotli q11, the quality the edge serves. Every number here is deterministic: Client assetsNo change. 21 files, 75.10 KiB Brotli total. PagesNo change. 48 files, 502.10 KiB Brotli total. Worker bundleNo change. 230.10 KiB gzip. Dictionary deltas (
|
oddharsh
added a commit
that referenced
this pull request
Aug 18, 2026
The last of the www/ split. 36 HTML documents become src/pages/; the other 804 files, which are bytes a browser fetches unchanged, become public/. The staged root renames with them: .build/www is .build/public, and wrangler.jsonc's assets.directory follows. Seventh and final slice of lifting the parked bun branch's renames onto main (#450, #451, #452, #453, #455, #456). The mapping needed no judgement: main's www/ held exactly 840 files, the branch's two destinations hold exactly those 840, and every one lands in exactly one of them. Every HTML is a page; nothing else is. EVERY SERVED ARTIFACT IS BYTE-IDENTICAL, 1497 compared with the root name normalised. The four remaining differences are path references inside cal, serendipity and the Worker: three comments and one JSON import specifier. THE BUILD COMPOSES THE SERVED TREE NOW rather than copying one directory. public/ + src/pages/ + src/content/ + src/client/ + src/styles/ all stage into .build/public, so the URL layout is untouched while the source layout says what each file IS. servedFiles() walks the three authored roots in one place, because a tripwire that walks only some of them reports a clean tree it never read. SIX THINGS THE GATES CAUGHT, and the pattern is worth stating: a blanket path sweep cannot tell a source read from a staged path, an asset from a document, or a path from a regex. * staticShellPages() read www/ for the freshness check * the Worker imported ../../www/images/hashes.json * gen-md-twins looked for page HTML under www/, then read the generated tier from the staged www/ root * the page generators in pipelines/ wrote into www/ * the .src.html twin read its AUTHORED source from the wrong root, so it fell into a catch and shipped the STAGED bytes: readable twins carrying rewritten /a/ hashes, which is the whole point of the twin lost silently. The build's own counter is what showed it, 47 from staged where main says 12. * and one false positive: `assert.match(lens, /… 401 && www/)` is a regex whose DELIMITER the sweep read as a path separator, rewriting the assertion out from under a real variable named www. Gates: 305 tests, build, lint, typecheck, routes:check, pages:check, tools:check, perf-budget, photos:check, check-wrangler, cal, wrangler dry-run. Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com>
oddharsh
added a commit
that referenced
this pull request
Aug 18, 2026
* docs: the layout table describes the tree that now exists Seven slices moved almost every path in this repository (#450, #451, #452, #453, #455, #456, #457), and the automated sweeps that repointed code also walked CLAUDE.md. That left the map wrong in two different ways. STALE: the table still said public/ holds "pages, client scripts, CSS, photos, dictionaries". It holds none of the first four now. Rows added for src/pages, src/content and src/dict; scripts/ folded into the tools/ row; every row's description checked against the tree rather than against its own history. FALSE: the sweep rewrote HISTORICAL names, so the file claimed the Worker lived at `public/_worker.js/` and the photo pipeline at `public/scripts/`. Neither ever existed. A stale note is a note somebody distrusts; a false one is a note somebody follows. The naming note now records the full sequence, holding -> www -> the split, and says explicitly that the rewrites deliberately left old mentions alone, so reading `www/` in an older note is correct rather than a typo. It also drops the "duplicate path" explanation, since scripts/ no longer exists to be confused with tools/photos/. And it states the test for where a new file goes, which the table never did: if a build step transforms it, it is src/; if it ships byte-for-byte, it is public/. * docs: the intro names the split tree too The bullet under the header still called public/ the live site including the _worker.js/ dispatcher, which is two moves out of date: the Worker left the served tree in #450 and the documents left it in #457. It now names what each root is for, which is the same question the table below answers per entry. --------- Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com>
oddharsh
added a commit
that referenced
this pull request
Aug 24, 2026
…26-08-14 `src/content/md/` holds seven hand-authored twins (/around, /bot, /coffee, /lens, /security, /terminal, /whoareyou). CLAUDE.md's key-files row, its layout table, `.assetsignore`'s comment and the generator's own header all said three, and all four still called the directory `public/md/`. The count could rot because the set is not a list anywhere in the code. `buildTwins` looks for `<path>.md` per SURFACE, so a page joins by someone dropping a file in: /terminal joined in #227 and /around, /coffee and /lens in #354, and nothing announced either. What the row now records is the mechanism rather than the membership, plus the fact that `checkTwinFacts()` pins only three of the seven, so the other four can drift from their page silently. Two neighbouring rows named prose that moved in the same #456 split: - `public/writing/` is `src/content/writing/`, and its render code is in `src/worker/` rather than `_worker.js`. - `public/index.md` is `src/content/index.md`. That path confusion has already cost something: gen-md-twins looked in `public/` after the move, silently stopped finding the hand twin, and overwrote it with a generated one 472 bytes shorter. The row records that now. `.assetsignore` also opened on "Files in `www/`" and called the deltas `www/ad/`. Its two paragraphs about `www/scripts` and the old dictionary location stay, since those are the record of why there is no entry at either path.
oddharsh
added a commit
that referenced
this pull request
Aug 24, 2026
…26-08-14 `src/content/md/` holds seven hand-authored twins (/around, /bot, /coffee, /lens, /security, /terminal, /whoareyou). CLAUDE.md's key-files row, its layout table, `.assetsignore`'s comment and the generator's own header all said three, and all four still called the directory `public/md/`. The count could rot because the set is not a list anywhere in the code. `buildTwins` looks for `<path>.md` per SURFACE, so a page joins by someone dropping a file in: /terminal joined in #227 and /around, /coffee and /lens in #354, and nothing announced either. What the row now records is the mechanism rather than the membership, plus the fact that `checkTwinFacts()` pins only three of the seven, so the other four can drift from their page silently. Two neighbouring rows named prose that moved in the same #456 split: - `public/writing/` is `src/content/writing/`, and its render code is in `src/worker/` rather than `_worker.js`. - `public/index.md` is `src/content/index.md`. That path confusion has already cost something: gen-md-twins looked in `public/` after the move, silently stopped finding the hand twin, and overwrote it with a generated one 472 bytes shorter. The row records that now. `.assetsignore` also opened on "Files in `www/`" and called the deltas `www/ad/`. Its two paragraphs about `www/scripts` and the old dictionary location stay, since those are the record of why there is no entry at either path.
oddharsh
added a commit
that referenced
this pull request
Aug 24, 2026
…#563) * docs: the runbooks still describe the pnpm tree and the www directory `pnpm exec` refuses on a bun tree outright (it reads package.json's `packageManager`), and there is no pnpm workspace left for `--filter` to read, so every pnpm command in these files fails rather than degrading. Fixed in the clone-and-verify recipe, cal/README.md, `checkpoints:check`, `bun why esbuild`, and three live instructions in CLAUDE.md (`deploy:direct`, `infra:apply`, the cal secrets block). Four claims contradicted a value something else checks: - MAINTENANCE.md's rollout recipe told you to type `pnpm exec wrangler versions upload` into the Workers Builds dashboard, where infra.json declares `bash .github/deploy-wrangler.sh versions upload` and check-infra.mjs exact-matches it. Following the recipe reddens `validate`. CLAUDE.md's gotcha 29 carried the same stale string, and infra.json's own prose said "both moved to `pnpm exec`" fifteen lines above the value that is the wrapper. - MAINTENANCE.md said the wrapper picks its invocation from the lockfile. It stopped doing that on 2026-08-20 and runs the pinned entry file under node, because wrangler does not support bun and the refusal is per-command. - CLAUDE.md said the ramp calls `pnpm exec wrangler`. Spawns go through `wranglerCommand()` in tools/lib/wrangler-bin.ts, which names no package manager. This one already cost a release: five tools were still spawning `pnpm exec` the day the tree became bun, and two of them swallowed the refusal and reported a build that measured nothing. - CLAUDE.md's root-files list named `pnpm-workspace.yaml` and `pnpm-lock.yaml`. The lockfile is `bun.lock` and package.json carries the four workspaces. `www/` survived in two places. design/DESIGN.md cited `www/index.html` and `www/garage/*` for the two canonical Luna surfaces, and src/content/README.md was a whole fossil of the old directory, titled `# www/`, describing `_worker.js` and `scripts/` and linking a MAINTENANCE.md that resolves to nothing from where it now sits. That file BUILDS to .build/public/README.md, so it has been serving at aadhar.sh/README.md the whole time. Gotchas 29 and 30 keep their pnpm, since they are the record of that era, and so does the note that one dashboard string has to suit a pnpm branch and a bun one. Where a fix landed inside those blocks the old state is kept and the newer move appended rather than overwritten. * docs(twins): the hand-twin set says three and has been seven since 2026-08-14 `src/content/md/` holds seven hand-authored twins (/around, /bot, /coffee, /lens, /security, /terminal, /whoareyou). CLAUDE.md's key-files row, its layout table, `.assetsignore`'s comment and the generator's own header all said three, and all four still called the directory `public/md/`. The count could rot because the set is not a list anywhere in the code. `buildTwins` looks for `<path>.md` per SURFACE, so a page joins by someone dropping a file in: /terminal joined in #227 and /around, /coffee and /lens in #354, and nothing announced either. What the row now records is the mechanism rather than the membership, plus the fact that `checkTwinFacts()` pins only three of the seven, so the other four can drift from their page silently. Two neighbouring rows named prose that moved in the same #456 split: - `public/writing/` is `src/content/writing/`, and its render code is in `src/worker/` rather than `_worker.js`. - `public/index.md` is `src/content/index.md`. That path confusion has already cost something: gen-md-twins looked in `public/` after the move, silently stopped finding the hand twin, and overwrote it with a generated one 472 bytes shorter. The row records that now. `.assetsignore` also opened on "Files in `www/`" and called the deltas `www/ad/`. Its two paragraphs about `www/scripts` and the old dictionary location stay, since those are the record of why there is no entry at either path. --------- Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
www/writing/,www/md/and the four root.mddocuments becomesrc/content/. The writing posts and theirposts.json, the hand-authored twins for the three Worker-rendered pages, andindex/README/auth/resumeare authored text, not assets that happen to sit in the served tree.Sixth slice of lifting the parked bun branch's renames onto
main, and the second of three that finishwww/.Every public URL is unchanged
Unlike the dictionaries in #455, most of this is served:
/writing/<slug>.txt,/index.md,/resume.md. Sobuild.mjsstagessrc/contentback into the served tree at the same paths. Source layout and URL layout are different questions, and only the first one moved.Staged tree byte-identical across 1497 files, except three Worker sources whose comments name a moved path. Those reach the bundle and no served asset.
Two silent failures the gates caught
Both from one path sweep that could not tell a source read from a served path:
routes:checkcaught the first.gen-md-twins.mjsholdsHAND_DIR = "www/md"with no trailing slash, so a sweep keyed onwww/md/missed it and the three hand-authored twins stopped publishing. Five routes went 404:/security.md,/lens.md,/coffee.md,/around.md,/terminal.md.The byte control caught the second, and nothing else would have. The same script decides a committed twin wins by looking for it under
www/. Withindex.mdmoved, that lookup silently failed and the generator wrote its own homepage twin over the hand-written one: 2170 bytes where the real file is 2642. No error, no warning, a live URL quietly degraded to a machine extraction of the page.Both are the lesson from
icons.svgin #452 in a different costume: a path naming a repository location from inside a program keeps working right up until the location moves, and the failure is quiet.Gates
305 tests, build,
routes:check, lint, typecheck,pages:check,tools:check,perf-budget,photos:check,check-wrangler, the cal suite, and awrangler deploy --dry-run.What is left of the split
Only the largest piece: pages to
src/pages/, assets topublic/. That one renames the staged root and toucheswrangler.jsonc'sassets.directory, which is a different class of risk from these two, so it stays its own PR.