feat(marketing): phase 4 — the marketing pages #7
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/phase-4-marketing"
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?
PLAN.md §13 phase 4 —
/features/,/architecture/,/modules/,/integrations/, and/community/, plus the two scope items the phase table never assigned to anyone.What you approved before I wrote anything
Six decisions, now recorded in PLAN.md §10 as D20–D25 so they are not re-litigated:
/features/is the homepage's list with adetailline, not a second list. One data file, two renderings./architecture/draws reasons, not reference — three new inline SVGs, one per boundary. No endpoint tables or config keys; those are phase 8's and stay canonical indocs/./community/andcheckLinks.mjs.needsModule— the Teams correction below.The accuracy bug this found
Writing the
/features/detail line for Teams exposed a claim phase 3 shipped: the Community group said "everything here works on a deployment with no game module installed at all". That is false, andwebsitemainsays so plainly —teams.module_idisNOT NULL, there is no create route anywhere under/api/v1/admin/teams, and sync is gated onteamProvider.providerModuleId().Core owns the entire Team machinery — tables, roster resolver, forums, notification streams, Discord bridge, voice, activity feed,
/admin/teams— and deliberately cannot originate a Team, because core does not own the word for one. On a bare core the feature is present, correct and permanently empty. Teams and Team forums are now marked; the group summary is requalified; the homepage changed by one sentence and kept D18's five named groups.The two absorbed scope items
checkLinks.mjs(§12, previously unowned). It readsdist/clientrather thansrc/, and that is the design: half the links these pages carry are assembled from data files and template literals, and a source scan sees an expression rather than a URL. It fetches nothing — the outbound rule is about the shape of a URL, and a check that fails when someone else's host is slow is a check people learn to ignore.Its one exemption list,
PLANNED_ROUTES, exists because §10's convention is that the header, footer and homepage link the final routes rather than growing links phase by phase. That is safe only because it is checked in both directions: a link to a route that is neither built nor listed fails, and an entry whose route has since been built also fails, so it cannot rot into a permanent exemption once the page arrives. It currently holds one live entry (/app/, phase 5)./community/— specified in §10 and §14 N3, linked from the header and footer since phase 1, built by no phase. It describes the honest split N3 asks for: Discord is the front door in fact, because Gitea registration is disabled and nobody outside the org can file anything. The sentence that changes if registration is reopened is marked in the source.The demo deep links
brand.jsonhas promised/features/a "per-capability affordance" since phase 2 without one ever being defined. D25 defines it, and it needed the branding pipeline extended: the phase-3 slot is a literal swap of a whole URL, so it can only ever put the demo's root in anhref, and reversing it would not even find a deep link — whosehrefis the root plus a path, matching no literal the script knows.applyBrand.mjsgained a second pass that recomputes all three attributes from the immutabledata-demo-path, making it idempotent and exactly reversible.checkBrand.mjsgained a guard that lifts the pattern out ofapplyBrand.mjsand runs it against the stock markup, so a template and a script sharing no code cannot drift. Proved against a real mount in both directions: 12 links filled and 12 reversed with zero traces left.A cascade bug no check could see
[data-demo-url=''] { display: none }is specificity 0,1,0 — and so is the scoped class Astro puts on the same element. Component styles are emitted afterglobal.css, so/features/'s.demo-link { display: inline-flex }won on source order, and twelve links to a demo that does not exist rendered on the page, each pointing athref=""— which a browser resolves to the page it is already on.checkBrand.mjswas green throughout: the attributes were perfect and the defect was three files away, in the cascade. It was found by looking at the rendered page at 390px. The rule is now!importantand the stylesheet says why.Also in here
src/styles/diagram.css— it was duplicated the moment a second diagram existed.DataPath.astrokeeps its own layout (its right column is a numbered walk, not a notes column).assertDetailCoverage()(a capability with no detail is a heading with nothing under it) andassertScopeNonEmpty()(an empty absences section is the one defect that looks deliberate). Both negative-tested.astro checkcaught a real type hole — the inferred per-group item union madedemoPathunreadable on/features/. Fixed with explicit JSDoc typedefs and acapabilityGroup(id)lookup that throws rather than returningundefined.Verification
From a clean checkout (
git archive→npm ci), not the working tree:checkTokens— 34 files, every colour from the token filecheckBrand— 19/brand/URLs resolve, demo slot + 1 deep-link site match their contractsastro check— 0 errorscheckLinks— 141 internal links resolve, 24 repository links point at a branchcheckFacts— 15 facts agree with their authoritiesLive browser pass on the built server: all five new routes 200, one
<h1>each, no<img>withoutalt, no<svg>withoutaria-hidden, no horizontal overflow at 390px on any of the five, and the demo links verified hidden with no mount and correct with one.Every new check was negative-tested before being trusted: a broken internal link, a commit permalink, a 40-hex ref on a branch path, the planned-route reverse check, reordered demo attributes, a missing detail and an empty scope all fail as intended.
🤖 Generated with Claude Code