-
Notifications
You must be signed in to change notification settings - Fork 0
primitives ids
Domain IDs are the branded slug types that identify quests, levels, packs, and features throughout Garnish. QuestId, LevelId, PackId, and FeatureId are defined in src/core/ids.ts as Zod schemas with .brand<"...">(). Branding gives each ID kind a distinct nominal type at compile time, so a QuestId cannot be passed where a LevelId is expected even though both are strings at runtime. These IDs appear in every subsystem.
| Type | File | Pattern | Description |
|---|---|---|---|
QuestId |
src/core/ids.ts |
slugPattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$
|
Lowercase slug identifying a quest (e.g. install-certified-pi). |
LevelId |
src/core/ids.ts |
slugPattern |
Lowercase slug identifying a level (e.g. tutorial-island). |
PackId |
src/core/ids.ts |
slugPattern |
Lowercase slug identifying a pack (e.g. l0-tutorial-island). |
FeatureId |
src/core/ids.ts |
featurePattern: `^[a-z][a-z0-9]*(?:(?:- |
: |
Each schema is z.string().min(1).regex(pattern).brand<"Kind">(). The brand call wraps the inferred TypeScript type in a nominal brand, so z.infer<typeof QuestIdSchema> is { readonly [brand]: "QuestId" } & string rather than plain string. This means a function typed to take a LevelId will refuse a QuestId value at compile time, even though both validate against the same slug regex. The runtime validation is identical; the brand is a compile-time guard against mixing ID kinds.
slugPattern (^[a-z0-9]+(?:-[a-z0-9]+)*$) accepts lowercase alphanumeric segments joined by single hyphens. featurePattern (^[a-z][a-z0-9]*(?:(?:-|:|\.)[a-z0-9]+)*$) is broader: it allows dots and colons as separators so feature keys like tool:file and tool:shell validate, while still requiring a lowercase letter first and lowercase alphanumeric segments. Both patterns reject uppercase, leading or trailing hyphens, and consecutive separators.
These IDs appear across the codebase:
-
Domain model (
src/core/):Quest.idis aQuestId,Quest.levelis aLevelId,Quest.unlocksandLevel.unlocksareFeatureId[],Pack.idis aPackId. See domain model. -
Progression events (
src/core/progression.ts):quest_completedcarriesQuestIdandLevelId;unlocktargets aFeatureIdorLevelId. See progression events. -
Adapter (
src/adapter/gates.ts):FeatureIdis the gate key, the catalog key that maps to Pi config surfaces. See capability gating. -
Loader (
src/loader/index.ts): validates quest, level, and pack IDs against these schemas and builds the quest graph keyed by them. -
Verifier (
src/verifier/index.ts):EventAftercan be aQuestId(the boundary an event check scans from). - CLI and extension: render and match IDs when displaying state and routing unlocks.
- Min length 1: every schema requires at least one character.
-
Slug pattern:
QuestId,LevelId, andPackIdmust matchslugPattern. -
Feature pattern:
FeatureIdmust matchfeaturePattern. -
Brand: each schema brands its output, so the inferred type is nominally distinct from plain
stringand from the other ID kinds. -
Strict reuse: because the same
QuestIdSchemavalidatesQuest.id,Quest.prereqsentries, andEventAfterquest references, a typo in a prereq orafterreference fails validation at load time rather than at evaluation time.
| File | Purpose |
|---|---|
src/core/ids.ts |
QuestIdSchema, LevelIdSchema, PackIdSchema, FeatureIdSchema, slugPattern, featurePattern, and the branded types. |
src/core/index.ts |
Re-exports the ID schemas and types. |
Cross-link: domain model, progression events, capability gating, Pi adapter.