Files
community-rule/lib/create/deckTypes.ts
T
adilalloandCursor bcbc6f30d9 Import the remade decks on stable ids and recommend one card per job, so a saved draft still loads after a chip is renamed.
The real-group profiles stay as a test, so a change that moves a pick fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-04 14:22:54 -07:00

138 lines
3.1 KiB
TypeScript

/** Deck engine types. Shape matches the 2 Nov 2026 deck package. */
export const DECK_IDS = [
"decisionApproaches",
"membership",
"conflictManagement",
"communication",
] as const;
export type DeckId = (typeof DECK_IDS)[number];
export const SIZE_BANDS = [
"oneMember",
"twoToFive",
"sixToTwelve",
"thirteenToOneHundred",
"oneHundredToOneHundredK",
] as const;
export type SizeBand = (typeof SIZE_BANDS)[number];
export const KINDS = [
"workersCoop",
"mutualAid",
"nonprofit",
"forProfit",
"openSource",
"dao",
] as const;
export type Kind = (typeof KINDS)[number];
export const SCALES = ["local", "regional", "national", "global"] as const;
export type Scale = (typeof SCALES)[number];
export const STAGES = [
"earlyStage",
"growthStage",
"established",
"enterprise",
] as const;
export type Stage = (typeof STAGES)[number];
export const TRAIT_KEYS = [
"network",
"nonvoters",
"employer",
"sponsor",
"records",
"risky",
] as const;
export type TraitKey = (typeof TRAIT_KEYS)[number];
export const DISPLAY_TIERS = ["frame", "safety", "fitted", "floor", "none"] as const;
export type DisplayTier = (typeof DISPLAY_TIERS)[number];
export type RankTier = Exclude<DisplayTier, "none"> | "answers";
export interface CardFacets {
size: Record<SizeBand, boolean>;
orgType: Record<Kind, boolean>;
scale: Record<Scale, boolean>;
maturity: Record<Stage, boolean>;
}
export type FacetFile = Record<string, CardFacets>;
export interface CardTraits {
beside?: TraitKey[];
besideJob?: string;
fits?: TraitKey[];
opens?: TraitKey[];
}
export interface CardEngineEntry {
job: string;
priority: number;
everyRuleHas?: boolean;
traits?: CardTraits;
}
export interface JobDefinition {
id: string;
label: string;
displayTier: DisplayTier;
rank?: number;
why: string;
}
export interface DeckEngine {
jobs: JobDefinition[];
addedOrder: string[];
cards: Record<string, CardEngineEntry>;
}
export interface JobsFile {
about: string;
version: string;
displayLimit: number;
maxAddedInSeven: number;
tierOrder: RankTier[];
traitKeys: TraitKey[];
sizeAnswers: Record<string, SizeBand>;
decks: Record<DeckId, DeckEngine>;
}
export interface GroupAnswers {
size?: string | null;
mainKind?: Kind | null;
otherKinds?: Kind[];
scale?: Scale[];
stage?: Stage | null;
traits?: Partial<Record<TraitKey, boolean>>;
}
export type MatchedFacet = "size" | "kind" | "scale" | "stage";
export type RecommendationReason =
| { kind: "fit"; matched: MatchedFacet[]; answer?: TraitKey }
| { kind: "opened"; matched: MatchedFacet[]; answer: TraitKey }
| { kind: "added"; answer: TraitKey };
export interface RecommendedCard {
id: string;
job: string;
showsWith: string;
tier: RankTier;
tag: "recommended" | "everyRuleHas";
reason: RecommendationReason;
alternative?: string;
score?: number;
decidedBy?: "only" | "score" | "otherKinds" | "rowOrder";
}
export interface DeckRecommendation {
deck: DeckId;
fallback: boolean;
recommended: RecommendedCard[];
shown: RecommendedCard[];
waiting: RecommendedCard[];
seeAll: string[];
}