Principle — library packages must be generic primitives
Status: ratified — warp#724 (re-mint of cancelled warp#693)
Filed under: ADR-113 (principles tier above initiative)
Cited by: ADR-124 (pipeline tooling is block-composition)
Enforced at PR review by: gyrum-curator persona (devtools/personas/curator.md)
Statement
Library packages must be generic primitives. Domain shape lives in product code, not shared libraries.
Concrete contrasts (✓ generic, ✗ domain):
pkg/queue✓.pkg/shopping-queue✗.pkg/auth.IsLogin✓ (generic verb).pkg/auth.HasShopperLogin✗ (domain noun).pkg/observ.Redact(pattern)✓.pkg/observ.RedactCreditCard✗.pkg/grant.OneTimeToken✓.pkg/bootstrap.GenerateGYQueueAdmin✗ (domain — belongs in the product's bootstrap code, not in shared substrate).
Why this rule
The factory's value proposition: 50 SaaS share substrate. Substrate fixes flow to all consumers. If pkg/billing contains domain leakage from one consumer's MVP, the leak fails the proposition — that consumer's code is in the substrate but no other consumer uses it. Substrate becomes monorepo-with-shared-code instead of factory.
Empirical evidence (2026-04-29 audit): pkg/billing 1112 LOC, pkg/email 716 LOC, pkg/sms, pkg/notification, pkg/document 611 LOC — many of these are single-consumer features that drifted into substrate. warp#609-617 substrate audits surfaced 30+ findings, most of them this shape.
Recursive application
The rule applies AT EVERY LAYER:
- Library packages (this principle).
- Pipeline blocks — warp#698 is the recursive sister principle: block names are abstract verbs; pipeline names are domain. ADR-124 cites THIS principle as the foundation.
- Module guidelines (ADR-117) — each module-type's guideline says "this module-type's symbols must be generic for that module shape, not domain-specific."
How to apply
- At write time — when adding a public symbol to a library package, ask: "is this name a generic verb/noun for the library's concern, or does it leak a single consumer's domain?" If domain, push the symbol into product code instead.
- At PR time —
gyrum-curator(warp#695) BLOCKs PRs that add domain-named symbols, citing this principle. - At graduation time — when extracting a primitive from a product MVP into substrate (warp#696 substrate convergence), the extracted form MUST be the generic shape, not the product-specific shape.
- At catalog time —
gyrum-fleet-library-drift(warp#641) treats domain-named packages as red flags during fleet review.
Cross-link
- warp#724 — this principle's live ticket (re-mints cancelled warp#693)
- warp#693 — original ticket, cancelled as a duplicate-of-warp#694; preserved here as historical context
- warp#698 + ADR-124 — recursive application to pipeline tooling
- warp#695 — gyrum-curator persona (the enforcement at PR review)
- warp#641 — fleet drift visibility (empirical signal for adherence)
- warp#696 — substrate convergence (applies this principle at extraction)
- ADR-113 — principles tier (the schema this is filed under)
- ADR-115 — principle-aware reviewers (how curator fetches this for review)
Notes on the cancellation
The original warp#693 was cancelled as "duplicate of warp#694 (same title, both filed)" — but the cancellation was wrong on intent. warp#693 was meant to be the principle ticket; warp#694 was the Library-aware Blueprint feature. They had identical titles by accident in the staged drafts. warp#724 corrects the cancellation by re-minting the principle as a live kind: principle ticket.