build-goals-registry.md
raw
· source
slug: build-goals-registry title: Build /goals registry + site surface (goal #1) date: 2026-05-25 branch: goals-registry-build pr_number: 45 merge_sha: e923da8 status: shipped related_posts: [sama-v2-goal-chain-gap]
Goal: Persist /goal slash commands into git as first-class artifacts, mirroring the /blog and /sama patterns. New top-level directory goals/ holds each goal as a markdown file with YAML frontmatter; the registry lives at src/a31_goals.ts; the site renders /goals (index) and /goals/
Done when:
- New top-level
goals/directory exists; first migrated goal lives at goals/git-url-drop-owner.md (a placeholder file with the /goal text from PR #42 is fine — goal #2 will do the proper migration). Frontmatter format defined and parsed:
slug:
title: date: branch: pr_number: <int|null> merge_sha: <short sha|null> status: pending|shipped|abandoned related_posts: [ , ...] - Layer 0 registry at src/a31_goals.ts: export interface GoalEntry { slug, title, date, branch, prNumber, mergeSha, status, relatedPosts } export const ALL_GOALS: GoalEntry[] = [...] Same shape as ALL_POSTS — drives /goals, /goals/:slug, and the sitemap.
- Layer 1 helper src/b32_goals_meta.ts: pure functions
parseGoalFrontmatter(body: string) → { meta, body } (no I/O)
findGoalByMergeSha(sha: string, all: ReadonlyArray
) → GoalEntry | null Sibling test src/b32_goals_meta.test.ts covers: full frontmatter, missing optional fields, malformed frontmatter (returns null), SHA lookup hit/miss, short-vs-full SHA prefix matching (so /GIT/tdd.md/commit/968890f finds a goal whose merge_sha is 968890f8a3bc...). - Layer 3 handlers in src/d21_handlers_goals.ts: goalsLandingHandler → /goals index (table: date · title · status · PR · commit) goalSlugHandler → /goals/:slug detail (rendered markdown, frontmatter badges, links to PR + commit + related posts)
- /goals routes registered in src/d21_app.ts.
- /goals link added to the main nav in src/b51_render_layout.ts:47 (between /sama and /blog).
- Sitemap automatically lists every ALL_GOALS entry via the existing b32_sitemap helper — extend src/d21_app.ts "/sitemap.xml" handler to map ALL_GOALS → /goals/
; add "/goals" to STATIC_PATHS in src/b32_sitemap.ts. - /goals/
pages reference their merge commit via the new /GIT/tdd.md/commit/ link AND back-reference any related blog posts in related_posts[]. - All 388+ tests still pass; new helper test adds 5-7 cases.
- /sama/v2/verify still reports 7/7 ✓ (anti-fudge).
- Deployed; live-verify:
- curl https://tdd.md/goals → 200 with HTML listing
- curl https://tdd.md/goals/git-url-drop-owner → 200 with the /goal body rendered
- curl https://tdd.md/sitemap.xml | grep -c /goals/ → at least 1
- Goals index appears in main nav on every page
Constraints (anti-fudge):
- One markdown file per goal — no JSON, no multi-goal files, no goal-text embedded inside another file.
- Filename is the slug (e.g. git-url-drop-owner.md), NOT the merge SHA. SHA lookup works via the frontmatter field. Rationale: readable URLs, no chicken-and-egg, /goals/
is the canonical permalink. Documented in the file header of a31_goals.ts. - ALL_GOALS is the single source of truth — no second list of goals in handlers or rendered HTML.
- Site language English-only.
- GitHub flow via flatpak-spawn.
- Do NOT change any §4 verifier logic.
- Frontmatter parser stays in Layer 1 (pure string-in, struct-out) — no fs.readFile, no path joining.
Load-bearing files to read FIRST:
- src/a31_blog.ts (the registry pattern that ALL_GOALS should mirror)
- src/a31_sama.ts (same — second example of the pattern)
- src/d21_handlers_sama.ts (samaLandingHandler + samaSlugHandler — the index + detail pattern)
- src/d21_app.ts (route table — where /goals routes get registered)
- src/b32_sitemap.ts (extend STATIC_PATHS + add goals URLs to the handler's url list in d21_app.ts)
- src/b51_render_layout.ts:47 (nav strip — where /goals link goes)
- content/blog/sama-v2-sitemap-implementation-plan.md (the sitemap impl plan post is the closest existing pattern for this kind of registry-driven feature)