"A boundary you can't compute is a boundary you don't have."
One Level Deep, cwk-Prefixed, Support Source Excluded
A hub that manages 'the family' needs an exact, mechanical answer to 'who is in the family?' Firelink's is deliberately narrow: direct child projects of one projects directory whose names begin with cwk, enumerated exactly one level deep. The reserved cwkFamilyAppBirthTemplate support repository is explicitly excluded even though its name matches the prefix. Nested repositories, adjacent non-cwk folders, and 'ancestors' or 'adjacent repos' mentioned only in roster prose do not qualify.
This sounds almost too simple, and that's the point. A membership rule you can run in a loop is a rule that can't drift. The moment 'membership' depends on human judgment — 'well, that one kind of counts' — the census stops being reproducible and the hub starts lying about what it manages.
Prose Never Enrolls a Member
Firelink reads roster and network documents to decorate members with titles, one-liners, and lifecycle status. But those documents can also contain lineage notes, 'ancestors', and 'adjacent repos' sections written for humans. A critical rule: that prose never expands the managed set. A roster entry that sits outside the direct-project scope is reference material — not drift, not a card, not something to reconcile. The project root is the scope boundary; the documents decorate what's inside it and are powerless to enroll what's outside.
Birth Produces a Member; the Template Is Not One
Firelink Birth copies cwkFamilyAppBirthTemplate into a plan-scoped staging area, materializes the new app's identity and contracts, initializes and pushes its private Git repository, and then publishes the resulting shell as a new direct child of the projects directory. The template remains a support source and never appears as a family card. The new app enters the census because its published destination satisfies the membership rule — not because its source template or a document enrolled it.