Principles

Principle — library packages must be generic primitives

**Library packages must be generic primitives. Domain shape lives in product code, not shared libraries.**

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 blockswarp#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

  1. 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.
  2. At PR timegyrum-curator (warp#695) BLOCKs PRs that add domain-named symbols, citing this principle.
  3. 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.
  4. At catalog timegyrum-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.