@odla-ai/brand 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/errors.ts","../src/deps.ts","../src/schema.ts","../src/rules.ts","../src/validate.ts","../src/ops/books.ts","../src/ops/sections.ts","../src/ops/palettes.ts","../src/ops/assets.ts","../src/skill/asset-tools.ts","../src/skill/book-tools.ts","../src/skill/palette-tools.ts","../src/skill/read-tools.ts","../src/skill/skill.ts","../src/skill/persona.ts","../src/routes/http.ts","../src/routes/assets.ts","../src/routes/books.ts","../src/routes/tokens.ts","../src/routes/index.ts","../src/triggers.ts","../src/dispatch.ts","../src/descriptor.ts"],"sourcesContent":["// Namespaces + closed vocabularies for @odla-ai/brand. One brand book is a\n// row-tree across five namespaces: the book (auth roster + compiled tokens),\n// its sections (one per kind, natural-keyed `${bookId}:${kind}`), palettes\n// (the atomic proposal/approval unit), proposals (human-gated agent output),\n// and assets (worker-mediated uploads mirroring real R2 objects).\n\n/** The odla-db namespaces @odla-ai/brand installs and writes. */\nexport const BRAND_NS = {\n book: \"brand_book\",\n section: \"brand_section\",\n palette: \"brand_palette\",\n proposal: \"brand_proposal\",\n asset: \"brand_asset\",\n} as const;\n\n/** Brand-book lifecycle: authored → adopted → retired (delete is owner-only). */\nexport const BOOK_STATUSES = [\"draft\", \"active\", \"archived\"] as const;\n/** Where a brand book stands in its lifecycle. */\nexport type BookStatus = (typeof BOOK_STATUSES)[number];\n\n/** The section kinds a book carries — one row per kind, upserted by natural key. */\nexport const SECTION_KINDS = [\"palette\", \"typography\", \"voice\", \"logo\", \"imagery\"] as const;\n/** Which facet of the brand a section documents. */\nexport type SectionKind = (typeof SECTION_KINDS)[number];\n\n/** Section review state: agent drafts, a human approves. */\nexport const SECTION_STATUSES = [\"draft\", \"approved\"] as const;\n/** Whether a section's content has human sign-off. */\nexport type SectionStatus = (typeof SECTION_STATUSES)[number];\n\n/** Palette lifecycle — palettes are never row-deleted, only archived. */\nexport const PALETTE_STATUSES = [\"active\", \"archived\"] as const;\n/** Whether a palette is the live one or a retired predecessor. */\nexport type PaletteStatus = (typeof PALETTE_STATUSES)[number];\n\n/** How a palette came to be: pulled from an asset, derived from a seed color,\n * or entered by hand. */\nexport const PALETTE_SOURCES = [\"extracted\", \"derived\", \"manual\"] as const;\n/** Provenance of a palette's swatches. */\nexport type PaletteSource = (typeof PALETTE_SOURCES)[number];\n\n/** What a proposal proposes (palettes are the first-class case). */\nexport const PROPOSAL_KINDS = [\"palette\", \"typography\", \"voice\", \"logo\"] as const;\n/** Which brand facet a proposal targets. */\nexport type ProposalKind = (typeof PROPOSAL_KINDS)[number];\n\n/** Proposal lifecycle: open until a HUMAN accepts/rejects it (or a newer\n * proposal supersedes it) — agents never resolve their own proposals. */\nexport const PROPOSAL_STATUSES = [\"open\", \"accepted\", \"rejected\", \"superseded\"] as const;\n/** Where a proposal stands in the human-gated review flow. */\nexport type ProposalStatus = (typeof PROPOSAL_STATUSES)[number];\n\n/** What kind of upload an asset row records. */\nexport const ASSET_KINDS = [\"logo\", \"wordmark\", \"inspiration\", \"document\", \"font\", \"other\"] as const;\n/** The declared purpose of an uploaded asset. */\nexport type AssetKind = (typeof ASSET_KINDS)[number];\n\n/** Every swatch role a palette may assign. `chart` may repeat (a series);\n * `custom` is the escape hatch for roles the token compiler doesn't map. */\nexport const SWATCH_ROLES = [\n \"primary\",\n \"secondary\",\n \"highlight\",\n \"bg\",\n \"surface\",\n \"text\",\n \"neutral\",\n \"good\",\n \"warn\",\n \"danger\",\n \"chart\",\n \"custom\",\n] as const;\n","/** Caller-fault error (bad hex, oversized payload, blocked transition…) — the\n * route layer maps it to a 400. `fields` carries per-field messages when the\n * failure came from input validation. */\nexport class BrandInputError extends Error {\n readonly fields?: Record<string, string>;\n constructor(message: string, fields?: Record<string, string>) {\n super(message);\n this.name = \"BrandInputError\";\n this.fields = fields;\n }\n}\n\n/** Missing entity — the route layer maps it to a 404. */\nexport class BrandNotFoundError extends Error {\n constructor(what: string) {\n super(`${what} not found`);\n this.name = \"BrandNotFoundError\";\n }\n}\n","// The dependency bundle brand operations take. `now`/`newId` are injectable\n// so tests can pin time and ids and assert exact written attrs; `fetchBytes`\n// is the one network seam (asset bytes for vision), injectable so tests and\n// service-binding hosts never touch the public internet.\nimport type { BrandDb } from \"./types\";\n\n/** What `fetchBytes` resolves to: raw bytes plus the served content type. */\nexport interface BrandFetchedBytes {\n bytes: Uint8Array;\n contentType: string;\n}\n\n/** What every brand operation needs: the injected db, plus test overrides. */\nexport interface BrandDeps {\n db: BrandDb;\n /** Clock override (default `Date.now`). */\n now?: () => number;\n /** Id factory override (default `crypto.randomUUID`). */\n newId?: () => string;\n /** Asset-byte fetcher override (default: global `fetch`). */\n fetchBytes?: (url: string) => Promise<BrandFetchedBytes>;\n}\n\n/** {@link BrandDeps} with the injectable defaults filled in. */\nexport interface ResolvedBrandDeps {\n db: BrandDb;\n now: () => number;\n newId: () => string;\n fetchBytes: (url: string) => Promise<BrandFetchedBytes>;\n}\n\nasync function defaultFetchBytes(url: string): Promise<BrandFetchedBytes> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`asset fetch failed: ${res.status} for ${url}`);\n return {\n bytes: new Uint8Array(await res.arrayBuffer()),\n contentType: res.headers.get(\"content-type\") ?? \"application/octet-stream\",\n };\n}\n\n/** Fill the injectable defaults. */\nexport function resolveDeps(deps: BrandDeps): ResolvedBrandDeps {\n return {\n db: deps.db,\n now: deps.now ?? Date.now,\n newId: deps.newId ?? (() => crypto.randomUUID()),\n fetchBytes: deps.fetchBytes ?? defaultFetchBytes,\n };\n}\n","// The odla-db schema @odla-ai/brand installs (POST to `/app/:id/schema` as\n// `{ schema: BRAND_SCHEMA }`). Ships pre-serialized (the wire shape) so\n// provisioning needs no schema-builder dependency, mirroring @odla-ai/chat\n// and @odla-ai/crm. The serialized types are inlined so the package has zero\n// deps.\n//\n// Design notes (grounded in the odla-db engine):\n// - Swatches are json ON `brand_palette`, NOT their own namespace: the\n// palette is the atomic proposal/approval unit — a human accepts or rejects\n// a palette whole, and swatches are never queried across palettes.\n// - Access control is fully DENORMALIZED (no graph edges, `links: {}`):\n// `brand_book.memberIds` is the auth roster (including the bot agent's id),\n// and every child row carries an `audience` snapshot of it, so the CEL\n// rules never need the engine's single-hop `ref`.\n// - Entity ids are not attributes in odla-db (`where: { id }` matches\n// nothing), so id-addressed rows mirror their id as a unique attr — the\n// crm pattern.\nimport { BRAND_NS } from \"./constants\";\n\n/** Wire-shape attribute value kinds odla-db stores. */\nexport type AttrType = \"string\" | \"number\" | \"boolean\" | \"date\" | \"json\";\n/** One serialized attribute: its type and index/uniqueness flags. */\nexport interface SerializedAttr {\n type: AttrType;\n unique: boolean;\n indexed: boolean;\n optional: boolean;\n}\n/** One serialized namespace: its attribute map. */\nexport interface SerializedEntity {\n attrs: Record<string, SerializedAttr>;\n}\n/** One end of a serialized schema link. */\nexport interface SerializedLinkEnd {\n on: string;\n has: \"one\" | \"many\";\n label: string;\n}\n/** A serialized schema link (unused by brand — audiences are denormalized). */\nexport interface SerializedLink {\n forward: SerializedLinkEnd;\n reverse: SerializedLinkEnd;\n}\n/** The wire-shape schema POSTed to `/app/:id/schema`. */\nexport interface SerializedSchema {\n entities: Record<string, SerializedEntity>;\n links: Record<string, SerializedLink>;\n}\n\ntype Opt = Partial<Omit<SerializedAttr, \"type\">>;\nconst a = (type: AttrType, o: Opt = {}): SerializedAttr => ({\n type,\n unique: false,\n indexed: false,\n optional: false,\n ...o,\n});\nconst uniq = (type: AttrType): SerializedAttr => a(type, { unique: true, indexed: true });\nconst idx = (type: AttrType, optional = false): SerializedAttr => a(type, { indexed: true, optional });\nconst opt = (type: AttrType): SerializedAttr => a(type, { optional: true });\n\n/**\n * The pre-serialized (wire-shape) odla-db schema for the five brand\n * namespaces; POST it to `/app/:id/schema` as `{ schema: BRAND_SCHEMA }`.\n * Natural keys (`book.slug`, `section.key`) make provisioning and section\n * upserts idempotent; mirrored `id` attrs make rows addressable by\n * `where: { id }`.\n */\nexport const BRAND_SCHEMA: SerializedSchema = {\n entities: {\n [BRAND_NS.book]: {\n attrs: {\n id: uniq(\"string\"),\n slug: uniq(\"string\"),\n name: idx(\"string\"),\n status: idx(\"string\"), // draft | active | archived\n ownerId: idx(\"string\"),\n memberIds: a(\"json\"), // the auth roster, incl. the bot agent id\n channelId: idx(\"string\", true),\n activePaletteId: opt(\"string\"),\n tokens: opt(\"json\"), // { light, dark, warnings, compiledAt }\n summary: opt(\"string\"),\n createdAt: idx(\"date\"),\n updatedAt: idx(\"date\"),\n },\n },\n [BRAND_NS.section]: {\n attrs: {\n key: uniq(\"string\"), // `${bookId}:${kind}` — one section per kind\n bookId: idx(\"string\"),\n kind: idx(\"string\"), // palette | typography | voice | logo | imagery\n status: idx(\"string\"), // draft | approved\n content: a(\"json\"),\n audience: a(\"json\"),\n updatedBy: a(\"string\"),\n updatedAt: idx(\"date\"),\n },\n },\n [BRAND_NS.palette]: {\n attrs: {\n id: uniq(\"string\"),\n bookId: idx(\"string\"),\n name: a(\"string\"),\n status: idx(\"string\"), // active | archived\n swatches: a(\"json\"), // Swatch[] — see the header design note\n seedHex: opt(\"string\"),\n source: a(\"string\"), // extracted | derived | manual\n rationale: opt(\"string\"),\n proposalId: opt(\"string\"),\n audience: a(\"json\"),\n createdAt: idx(\"date\"),\n updatedAt: idx(\"date\"),\n },\n },\n [BRAND_NS.proposal]: {\n attrs: {\n id: uniq(\"string\"),\n bookId: idx(\"string\"),\n kind: idx(\"string\"), // palette | typography | voice | logo\n status: idx(\"string\"), // open | accepted | rejected | superseded\n payload: a(\"json\"),\n rationale: a(\"string\"),\n sourceAssetId: opt(\"string\"),\n messageId: opt(\"string\"),\n audience: a(\"json\"),\n createdBy: a(\"string\"),\n createdAt: idx(\"date\"),\n resolvedBy: opt(\"string\"),\n resolvedAt: opt(\"date\"),\n resolutionNote: opt(\"string\"),\n },\n },\n [BRAND_NS.asset]: {\n attrs: {\n id: uniq(\"string\"),\n bookId: idx(\"string\"),\n kind: idx(\"string\"), // logo | wordmark | inspiration | document | font | other\n path: idx(\"string\"),\n url: a(\"string\"),\n contentType: a(\"string\"),\n size: a(\"number\"),\n title: opt(\"string\"),\n analysis: opt(\"json\"), // { description, dominantColors: hex[], tags }\n analyzedAt: opt(\"date\"),\n audience: a(\"json\"),\n uploadedBy: a(\"string\"),\n createdAt: idx(\"date\"),\n deletedAt: opt(\"date\"), // tombstone — asset rows are never row-deleted\n },\n },\n },\n links: {},\n};\n","// Default-deny CEL rules for the brand namespaces (POST to\n// `/app/:id/admin/rules`). Access is denormalized (see schema.ts): books gate\n// on `data.memberIds`, child rows on their `data.audience` snapshot — no\n// `ref()`. The bot agent passes these checks because its agent id is written\n// into `memberIds`/`audience`, exactly like a human member.\n//\n// `brand_asset` is closed entirely: asset rows must mirror real R2 uploads,\n// and only the worker (admin key, bypasses rules) performs the\n// upload-then-row / delete-then-tombstone pairs that keep them in sync.\nimport { BRAND_NS } from \"./constants\";\n\n/** Per-namespace CEL rule strings (missing action = deny). */\nexport interface BrandRule {\n view?: string;\n create?: string;\n update?: string;\n delete?: string;\n}\n/** Namespace → rule set, as installed at `/app/:id/admin/rules`. */\nexport type BrandRules = Record<string, BrandRule>;\n\n// Membership in the audience snapshot — implies a signed identity, since an\n// anonymous auth.id is never written into an audience.\nconst AUDIENCE = \"auth.id in data.audience\";\n\n/**\n * Default-deny CEL rules for the five brand namespaces; install at\n * `/app/:id/admin/rules`. Books gate on the `memberIds` roster (owner-only\n * writes); sections/palettes/proposals gate on their denormalized `audience`\n * and are never client-deletable (archive via `status` instead); assets are\n * fully worker-mediated. Use {@link brandRules} for a per-install copy.\n */\nexport const BRAND_RULES: BrandRules = {\n [BRAND_NS.book]: {\n view: \"auth.id in data.memberIds\",\n // Creator is the owner and must include itself in the roster.\n create: \"auth.signedIn && auth.id == data.ownerId && auth.id in data.memberIds\",\n update: \"auth.id == data.ownerId\",\n delete: \"auth.id == data.ownerId\",\n },\n [BRAND_NS.section]: {\n view: AUDIENCE,\n create: AUDIENCE,\n update: AUDIENCE,\n delete: \"false\", // sections are upserted in place, never removed\n },\n [BRAND_NS.palette]: {\n view: AUDIENCE,\n create: AUDIENCE,\n update: AUDIENCE,\n delete: \"false\", // archive via status, keep provenance\n },\n [BRAND_NS.proposal]: {\n view: AUDIENCE,\n create: AUDIENCE,\n update: AUDIENCE,\n delete: \"false\", // resolution history is the audit trail\n },\n [BRAND_NS.asset]: {\n view: \"false\",\n create: \"false\",\n update: \"false\",\n delete: \"false\",\n },\n};\n\n/**\n * Rules factory, mirroring `chatRules()`/`crmRules()`. Today it returns a\n * fresh copy of {@link BRAND_RULES}; it exists so a future option (e.g.\n * locking views to an org email domain) can widen or tighten namespaces\n * without apps changing their provisioning call shape.\n */\nexport function brandRules(): BrandRules {\n return Object.fromEntries(Object.entries(BRAND_RULES).map(([ns, r]) => [ns, { ...r }]));\n}\n","// Input validation for brand writes — THE enforcement layer. Taint marking on\n// tool output is advisory; nothing an agent (or a route caller) produces\n// reaches odla-db without passing these checks. Every failure throws\n// {@link BrandInputError} with an actionable message.\nimport { SECTION_KINDS, SWATCH_ROLES } from \"./constants\";\nimport { BrandInputError } from \"./errors\";\nimport type {\n AssetAnalysis,\n ImagerySection,\n LogoSection,\n PaletteSection,\n Swatch,\n SwatchRole,\n TypographySection,\n VoiceSection,\n} from \"./types\";\n\n/** Most swatches a single palette may carry. */\nexport const MAX_SWATCHES = 24;\n\n/** Upload content types the asset pipeline accepts. */\nexport const ASSET_CONTENT_TYPES: ReadonlySet<string> = new Set([\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"image/svg+xml\",\n \"application/pdf\",\n]);\n\nconst HEX_RGB = /^#[0-9a-f]{3}$/;\nconst HEX_RRGGBB = /^#[0-9a-f]{6}$/;\nconst HEX_ALPHA = /^#[0-9a-f]{4}$|^#[0-9a-f]{8}$/;\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/**\n * Assert `value` is a `#rgb`/`#rrggbb` hex color and normalize it to\n * lowercase `#rrggbb`. Alpha channels (`#rgba`/`#rrggbbaa`) and every other\n * color syntax are rejected — tokens and contrast math are defined on opaque\n * sRGB hex.\n */\nexport function assertHex(value: unknown, label = \"color\"): string {\n if (typeof value !== \"string\")\n throw new BrandInputError(`${label} must be a hex string like #1a2b3c`);\n const hex = value.trim().toLowerCase();\n if (HEX_ALPHA.test(hex))\n throw new BrandInputError(`${label} must not carry alpha (got ${value}); use #rrggbb`);\n if (HEX_RGB.test(hex)) return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;\n if (!HEX_RRGGBB.test(hex))\n throw new BrandInputError(`${label} must be #rgb or #rrggbb hex (got ${value})`);\n return hex;\n}\n\n/** Assert a trimmed non-empty string of at most `max` characters. */\nexport function capString(value: unknown, label: string, max: number): string {\n if (typeof value !== \"string\") throw new BrandInputError(`${label} must be a string`);\n const s = value.trim();\n if (s === \"\") throw new BrandInputError(`${label} must not be empty`);\n if (s.length > max)\n throw new BrandInputError(`${label} must be at most ${max} characters (got ${s.length})`);\n return s;\n}\n\n/** Assert an array of capped strings (each trimmed and non-empty). */\nexport function capStringArray(\n value: unknown,\n label: string,\n opts: { maxItems: number; maxLen: number; minItems?: number },\n): string[] {\n if (!Array.isArray(value)) throw new BrandInputError(`${label} must be an array of strings`);\n const min = opts.minItems ?? 0;\n if (value.length < min)\n throw new BrandInputError(`${label} must have at least ${min} item${min === 1 ? \"\" : \"s\"}`);\n if (value.length > opts.maxItems)\n throw new BrandInputError(`${label} must have at most ${opts.maxItems} items`);\n return value.map((v, i) => capString(v, `${label}[${i}]`, opts.maxLen));\n}\n\n/**\n * Assert a swatch list: 1–{@link MAX_SWATCHES} entries, each with a known\n * role, a valid hex (normalized), and capped optional name/rationale.\n * Returns the normalized copy — write THAT, never the raw input.\n */\nexport function assertSwatches(value: unknown): Swatch[] {\n if (!Array.isArray(value) || value.length === 0)\n throw new BrandInputError(\"swatches must be a non-empty array\");\n if (value.length > MAX_SWATCHES)\n throw new BrandInputError(`swatches must have at most ${MAX_SWATCHES} entries`);\n return value.map((raw, i) => {\n if (!isRecord(raw)) throw new BrandInputError(`swatches[${i}] must be an object`);\n const role = raw.role;\n if (typeof role !== \"string\" || !(SWATCH_ROLES as readonly string[]).includes(role))\n throw new BrandInputError(\n `swatches[${i}].role must be one of: ${SWATCH_ROLES.join(\", \")}`,\n );\n const out: Swatch = { role: role as SwatchRole, hex: assertHex(raw.hex, `swatches[${i}].hex`) };\n if (raw.name !== undefined) out.name = capString(raw.name, `swatches[${i}].name`, 80);\n if (raw.rationale !== undefined)\n out.rationale = capString(raw.rationale, `swatches[${i}].rationale`, 500);\n return out;\n });\n}\n\nfunction assertPaletteSection(c: Record<string, unknown>): PaletteSection {\n return {\n paletteId: capString(c.paletteId, \"content.paletteId\", 128),\n name: capString(c.name, \"content.name\", 120),\n swatches: assertSwatches(c.swatches),\n };\n}\n\nfunction assertTypographySection(c: Record<string, unknown>): TypographySection {\n const out: TypographySection = {};\n if (c.fontDisplay !== undefined) out.fontDisplay = capString(c.fontDisplay, \"content.fontDisplay\", 120);\n if (c.fontBody !== undefined) out.fontBody = capString(c.fontBody, \"content.fontBody\", 120);\n if (c.fontMono !== undefined) out.fontMono = capString(c.fontMono, \"content.fontMono\", 120);\n if (c.scale !== undefined) {\n if (typeof c.scale !== \"number\" || !Number.isFinite(c.scale) || c.scale <= 1 || c.scale > 2)\n throw new BrandInputError(\"content.scale must be a modular type-scale ratio in (1, 2]\");\n out.scale = c.scale;\n }\n if (c.notes !== undefined) out.notes = capString(c.notes, \"content.notes\", 2000);\n return out;\n}\n\nfunction assertVoiceSection(c: Record<string, unknown>): VoiceSection {\n const out: VoiceSection = {\n tone: capString(c.tone, \"content.tone\", 200),\n principles: capStringArray(c.principles, \"content.principles\", { maxItems: 12, maxLen: 200, minItems: 1 }),\n };\n if (c.examples !== undefined)\n out.examples = capStringArray(c.examples, \"content.examples\", { maxItems: 12, maxLen: 500 });\n return out;\n}\n\nfunction assertLogoSection(c: Record<string, unknown>): LogoSection {\n const out: LogoSection = {\n usage: capStringArray(c.usage, \"content.usage\", { maxItems: 16, maxLen: 300, minItems: 1 }),\n donts: capStringArray(c.donts, \"content.donts\", { maxItems: 16, maxLen: 300 }),\n };\n if (c.clearspace !== undefined) out.clearspace = capString(c.clearspace, \"content.clearspace\", 120);\n if (c.minSize !== undefined) out.minSize = capString(c.minSize, \"content.minSize\", 120);\n return out;\n}\n\nfunction assertImagerySection(c: Record<string, unknown>): ImagerySection {\n return {\n style: capString(c.style, \"content.style\", 200),\n guidance: capStringArray(c.guidance, \"content.guidance\", { maxItems: 16, maxLen: 300, minItems: 1 }),\n };\n}\n\n/**\n * Validate + normalize a section's `content` payload for its kind. Returns\n * the normalized content to write; throws {@link BrandInputError} on an\n * unknown kind or an invalid payload.\n */\nexport function assertSectionContent(kind: string, content: unknown): Record<string, unknown> {\n if (!isRecord(content)) throw new BrandInputError(\"content must be an object\");\n switch (kind) {\n case \"palette\":\n return { ...assertPaletteSection(content) };\n case \"typography\":\n return { ...assertTypographySection(content) };\n case \"voice\":\n return { ...assertVoiceSection(content) };\n case \"logo\":\n return { ...assertLogoSection(content) };\n case \"imagery\":\n return { ...assertImagerySection(content) };\n default:\n throw new BrandInputError(`unknown section kind ${kind}; expected one of: ${SECTION_KINDS.join(\", \")}`);\n }\n}\n\n/**\n * Sanitize an upload's file name for use in an R2 key: strips path\n * separators, control characters, and leading dots, then caps at 120\n * characters. Throws when nothing survives sanitizing.\n */\nexport function safeFileName(name: unknown): string {\n if (typeof name !== \"string\") throw new BrandInputError(\"file name must be a string\");\n const cleaned = name\n .replace(/[/\\\\]/g, \"\")\n // eslint-disable-next-line no-control-regex\n .replace(/[\\u0000-\\u001f\\u007f]/g, \"\")\n .trim()\n .replace(/^\\.+/, \"\");\n if (cleaned === \"\") throw new BrandInputError(\"file name is empty after sanitizing\");\n return cleaned.slice(0, 120);\n}\n\n/**\n * Assert an upload content type is on the {@link ASSET_CONTENT_TYPES}\n * allowlist. Normalizes case and strips parameters (`; charset=…`) before\n * checking; returns the normalized bare type.\n */\nexport function assertAssetContentType(value: unknown): string {\n if (typeof value !== \"string\") throw new BrandInputError(\"contentType must be a string\");\n const ct = value.split(\";\")[0]!.trim().toLowerCase();\n if (!ASSET_CONTENT_TYPES.has(ct))\n throw new BrandInputError(\n `unsupported content type ${ct || \"(empty)\"}; allowed: ${[...ASSET_CONTENT_TYPES].join(\", \")}`,\n );\n return ct;\n}\n\n/**\n * Validate + normalize an agent's asset analysis: description ≤ 2000 chars,\n * ≤ 12 dominant colors (each normalized hex), ≤ 24 tags of ≤ 60 chars.\n */\nexport function assertAnalysis(value: unknown): AssetAnalysis {\n if (!isRecord(value)) throw new BrandInputError(\"analysis must be an object\");\n const colors = value.dominantColors;\n if (!Array.isArray(colors)) throw new BrandInputError(\"analysis.dominantColors must be an array\");\n if (colors.length > 12)\n throw new BrandInputError(\"analysis.dominantColors must have at most 12 entries\");\n return {\n description: capString(value.description, \"analysis.description\", 2000),\n dominantColors: colors.map((c, i) => assertHex(c, `analysis.dominantColors[${i}]`)),\n tags: capStringArray(value.tags, \"analysis.tags\", { maxItems: 24, maxLen: 60 }),\n };\n}\n","// Pure op-builders for brand_book rows: (input) -> BrandOp[]. No I/O — this\n// is the unit-test seam (assert the emitted ops); routes and the skill share\n// these so every write path commits identical shapes.\nimport { BOOK_STATUSES, BRAND_NS, type BookStatus } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport type { BrandAttrs, BrandBook, BrandEntityRef, BrandOp } from \"../types\";\nimport { capString } from \"../validate\";\n\nconst SLUG_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;\n\n/** Input to {@link createBookOps}. `memberIds` is the full auth roster —\n * include the bot agent's id so it can pass the audience rules. */\nexport interface CreateBookInput {\n id: string;\n slug: string;\n name: string;\n ownerId: string;\n memberIds: string[];\n channelId?: string;\n now: number;\n}\n\n/**\n * Ops to create a brand book: one `brand_book` row in `draft` status with the\n * id mirrored as an attr (odla-db ids aren't attrs), the owner always folded\n * into the deduplicated `memberIds` roster (the create rule requires it), and\n * both timestamps set to `now`.\n */\nexport function createBookOps(input: CreateBookInput): BrandOp[] {\n const slug = capString(input.slug, \"slug\", 80);\n if (!SLUG_RE.test(slug))\n throw new BrandInputError(\"slug must be lowercase letters, digits, and inner hyphens\");\n const name = capString(input.name, \"name\", 120);\n const memberIds = Array.from(new Set([input.ownerId, ...input.memberIds]));\n return [\n {\n t: \"update\",\n ns: BRAND_NS.book,\n id: input.id,\n attrs: {\n id: input.id,\n slug,\n name,\n status: \"draft\",\n ownerId: input.ownerId,\n memberIds,\n createdAt: input.now,\n updatedAt: input.now,\n ...(input.channelId ? { channelId: input.channelId } : {}),\n },\n },\n ];\n}\n\n// Patchable book columns, and which of them may be cleared with `null`\n// (required attrs can't be retracted — the final-state schema check fails).\nconst PATCHABLE = new Set([\"name\", \"status\", \"channelId\", \"summary\", \"activePaletteId\", \"tokens\"]);\nconst CLEARABLE = new Set([\"channelId\", \"summary\", \"activePaletteId\", \"tokens\"]);\n\nfunction validateBookField(key: string, value: unknown): unknown {\n switch (key) {\n case \"name\":\n return capString(value, \"name\", 120);\n case \"status\":\n if (typeof value !== \"string\" || !(BOOK_STATUSES as readonly string[]).includes(value))\n throw new BrandInputError(`status must be one of: ${BOOK_STATUSES.join(\", \")}`);\n return value as BookStatus;\n case \"channelId\":\n return capString(value, \"channelId\", 128);\n case \"summary\":\n return capString(value, \"summary\", 2000);\n case \"activePaletteId\":\n return capString(value, \"activePaletteId\", 128);\n default: {\n // tokens: the compiled-token cache; shaped by our own compiler, so only\n // require an object here.\n if (typeof value !== \"object\" || value === null || Array.isArray(value))\n throw new BrandInputError(\"tokens must be an object\");\n return value;\n }\n }\n}\n\n/**\n * Ops to patch a brand book. `null` means CLEAR (a `retract` op — odla-db has\n * no storable scalar null) and is only allowed on optional columns;\n * `undefined` keys are dropped. Any write stamps `updatedAt`; an empty\n * effective patch emits no ops at all.\n */\nexport function updateBookOps(\n bookId: BrandEntityRef,\n patch: Record<string, unknown>,\n now: number,\n): BrandOp[] {\n const attrs: BrandAttrs = {};\n const retract: string[] = [];\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) continue;\n if (!PATCHABLE.has(key)) throw new BrandInputError(`unknown book field: ${key}`);\n if (value === null) {\n if (!CLEARABLE.has(key)) throw new BrandInputError(`${key} is required and cannot be cleared`);\n retract.push(key);\n continue;\n }\n attrs[key] = validateBookField(key, value);\n }\n if (Object.keys(attrs).length === 0 && retract.length === 0) return [];\n const ops: BrandOp[] = [\n { t: \"update\", ns: BRAND_NS.book, id: bookId, attrs: { ...attrs, updatedAt: now } },\n ];\n if (retract.length > 0) ops.push({ t: \"retract\", ns: BRAND_NS.book, id: bookId, attrs: retract });\n return ops;\n}\n\n/** The child rows whose `audience` snapshots a roster change must rewrite.\n * Pass the rows you queried — the builder stays pure. */\nexport interface AudienceChildren {\n sections?: Array<{ id: string }>;\n palettes?: Array<{ id: string }>;\n proposals?: Array<{ id: string }>;\n assets?: Array<{ id: string }>;\n}\n\n/**\n * Ops to change a book's roster: rewrite `memberIds` (owner always kept) and\n * fan the new list out to every child row's denormalized `audience` snapshot.\n * Query the children first and pass them in — this builder does no I/O, so\n * tests can assert the exact fan-out.\n */\nexport function audienceFanoutOps(\n book: Pick<BrandBook, \"id\" | \"ownerId\">,\n newMemberIds: string[],\n children: AudienceChildren,\n now: number,\n): BrandOp[] {\n const memberIds = Array.from(new Set([book.ownerId, ...newMemberIds]));\n const ops: BrandOp[] = [\n { t: \"update\", ns: BRAND_NS.book, id: book.id, attrs: { memberIds, updatedAt: now } },\n ];\n const fan = (ns: string, rows?: Array<{ id: string }>) => {\n for (const row of rows ?? []) ops.push({ t: \"update\", ns, id: row.id, attrs: { audience: memberIds } });\n };\n fan(BRAND_NS.section, children.sections);\n fan(BRAND_NS.palette, children.palettes);\n fan(BRAND_NS.proposal, children.proposals);\n fan(BRAND_NS.asset, children.assets);\n return ops;\n}\n","// Pure op-builder for brand_section rows. One section per (book, kind),\n// upserted through a natural-key Lookup ref so re-writing the same section\n// binds to the same row (no read-modify-write race, idempotent installs).\nimport { BRAND_NS, SECTION_STATUSES, type SectionKind, type SectionStatus } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport type { BrandOp } from \"../types\";\nimport { assertSectionContent } from \"../validate\";\n\n/** The natural key a section row is upserted by: `${bookId}:${kind}`. */\nexport function sectionKey(bookId: string, kind: SectionKind): string {\n return `${bookId}:${kind}`;\n}\n\n/** Input to {@link upsertSectionOps}. `audience` is the book's roster\n * snapshot; `status` defaults to `draft` (a human approves later). */\nexport interface UpsertSectionInput {\n bookId: string;\n kind: SectionKind;\n content: Record<string, unknown>;\n status?: SectionStatus;\n audience: string[];\n updatedBy: string;\n now: number;\n}\n\n/**\n * Ops to create-or-replace a book's section of one kind: a single `update`\n * addressed by the `{ ns, attr: \"key\", value }` Lookup ref, carrying the\n * validated + normalized content (see `assertSectionContent`), the audience\n * snapshot, and the author/timestamp.\n */\nexport function upsertSectionOps(input: UpsertSectionInput): BrandOp[] {\n const status = input.status ?? \"draft\";\n if (!(SECTION_STATUSES as readonly string[]).includes(status))\n throw new BrandInputError(`status must be one of: ${SECTION_STATUSES.join(\", \")}`);\n const content = assertSectionContent(input.kind, input.content);\n const key = sectionKey(input.bookId, input.kind);\n return [\n {\n t: \"update\",\n ns: BRAND_NS.section,\n id: { ns: BRAND_NS.section, attr: \"key\", value: key },\n attrs: {\n key,\n bookId: input.bookId,\n kind: input.kind,\n status,\n content,\n audience: input.audience,\n updatedBy: input.updatedBy,\n updatedAt: input.now,\n },\n },\n ];\n}\n","// Pure op-builders for the palette proposal flow: the agent proposes, a\n// HUMAN accepts or rejects. Acceptance is one atomic transact — palette row,\n// approved palette section, the book's `activePaletteId`, and the proposal's\n// resolution — so a book can never point at a palette that wasn't written.\n//\n// Note on op kinds: the design doc says \"book merge {activePaletteId}\", but\n// odla-db's `merge` op deep-merges JSON attributes only (the engine rejects\n// it on scalars) — a scalar write on an existing row is an attr-merge\n// `update`, which is what these builders emit.\nimport { BRAND_NS } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport type { BrandOp, BrandProposal } from \"../types\";\nimport { assertHex, assertSwatches, capString } from \"../validate\";\nimport { upsertSectionOps } from \"./sections\";\n\n/** Input to {@link proposePaletteOps}. `audience` is the book's roster\n * snapshot; `contrastReport` is stored verbatim in the payload for the\n * human reviewer. */\nexport interface ProposePaletteInput {\n id: string;\n bookId: string;\n name: string;\n rationale: string;\n swatches: unknown;\n seedHex?: string;\n contrastReport?: unknown;\n createdBy: string;\n audience: string[];\n sourceAssetId?: string;\n messageId?: string;\n now: number;\n}\n\n/**\n * Ops to park a palette proposal for human review: one `brand_proposal` row,\n * `kind: \"palette\"`, `status: \"open\"`, with the validated swatches (and\n * optional seed/contrast report) in `payload`.\n */\nexport function proposePaletteOps(input: ProposePaletteInput): BrandOp[] {\n const name = capString(input.name, \"name\", 120);\n const rationale = capString(input.rationale, \"rationale\", 2000);\n const swatches = assertSwatches(input.swatches);\n const seedHex = input.seedHex === undefined ? undefined : assertHex(input.seedHex, \"seedHex\");\n const payload: Record<string, unknown> = {\n name,\n swatches,\n ...(seedHex ? { seedHex } : {}),\n ...(input.contrastReport !== undefined ? { contrastReport: input.contrastReport } : {}),\n };\n return [\n {\n t: \"update\",\n ns: BRAND_NS.proposal,\n id: input.id,\n attrs: {\n id: input.id,\n bookId: input.bookId,\n kind: \"palette\",\n status: \"open\",\n payload,\n rationale,\n audience: input.audience,\n createdBy: input.createdBy,\n createdAt: input.now,\n ...(input.sourceAssetId ? { sourceAssetId: input.sourceAssetId } : {}),\n ...(input.messageId ? { messageId: input.messageId } : {}),\n },\n },\n ];\n}\n\n/** Input to {@link acceptProposalOps}: the proposal row as read back, the id\n * to mint the palette under, and who resolved it. */\nexport interface AcceptProposalInput {\n proposal: BrandProposal;\n paletteId: string;\n resolvedBy: string;\n now: number;\n resolutionNote?: string;\n}\n\n/**\n * Ops to accept an OPEN palette proposal, all in one transact:\n * 1. the `brand_palette` row (source: `extracted` when the proposal came from\n * an asset, `derived` when seeded, else `manual`),\n * 2. the approved `palette` section upsert,\n * 3. the book's `activePaletteId` pointer,\n * 4. the proposal flipped to `accepted` with resolver + timestamp.\n * Throws on a non-palette or already-resolved proposal, or a payload that no\n * longer validates.\n */\nexport function acceptProposalOps(input: AcceptProposalInput): BrandOp[] {\n const { proposal, paletteId, resolvedBy, now } = input;\n if (proposal.kind !== \"palette\")\n throw new BrandInputError(`proposal ${proposal.id} is a ${proposal.kind} proposal, not a palette`);\n if (proposal.status !== \"open\")\n throw new BrandInputError(`proposal ${proposal.id} is ${proposal.status}, not open`);\n const payload = proposal.payload;\n const name = capString(payload.name, \"payload.name\", 120);\n const swatches = assertSwatches(payload.swatches);\n const seedHex = payload.seedHex === undefined ? undefined : assertHex(payload.seedHex, \"payload.seedHex\");\n const source = proposal.sourceAssetId ? \"extracted\" : seedHex ? \"derived\" : \"manual\";\n return [\n {\n t: \"update\",\n ns: BRAND_NS.palette,\n id: paletteId,\n attrs: {\n id: paletteId,\n bookId: proposal.bookId,\n name,\n status: \"active\",\n swatches,\n source,\n rationale: proposal.rationale,\n proposalId: proposal.id,\n audience: proposal.audience,\n createdAt: now,\n updatedAt: now,\n ...(seedHex ? { seedHex } : {}),\n },\n },\n ...upsertSectionOps({\n bookId: proposal.bookId,\n kind: \"palette\",\n content: { paletteId, name, swatches },\n status: \"approved\",\n audience: proposal.audience,\n updatedBy: resolvedBy,\n now,\n }),\n {\n t: \"update\",\n ns: BRAND_NS.book,\n id: proposal.bookId,\n attrs: { activePaletteId: paletteId, updatedAt: now },\n },\n {\n t: \"update\",\n ns: BRAND_NS.proposal,\n id: proposal.id,\n attrs: {\n status: \"accepted\",\n resolvedBy,\n resolvedAt: now,\n ...(input.resolutionNote ? { resolutionNote: input.resolutionNote } : {}),\n },\n },\n ];\n}\n\n/** Input to {@link rejectProposalOps}. */\nexport interface RejectProposalInput {\n proposal: BrandProposal;\n resolvedBy: string;\n now: number;\n resolutionNote?: string;\n}\n\n/**\n * Ops to reject an OPEN proposal (any kind): flip it to `rejected` with\n * resolver, timestamp, and the optional note. Nothing else is touched — the\n * proposal row itself is the audit trail.\n */\nexport function rejectProposalOps(input: RejectProposalInput): BrandOp[] {\n const { proposal, resolvedBy, now } = input;\n if (proposal.status !== \"open\")\n throw new BrandInputError(`proposal ${proposal.id} is ${proposal.status}, not open`);\n return [\n {\n t: \"update\",\n ns: BRAND_NS.proposal,\n id: proposal.id,\n attrs: {\n status: \"rejected\",\n resolvedBy,\n resolvedAt: now,\n ...(input.resolutionNote ? { resolutionNote: input.resolutionNote } : {}),\n },\n },\n ];\n}\n","// Pure op-builders for brand_asset rows. Asset rows are worker-mediated\n// (rules deny everything): the caller uploads to storage FIRST, then commits\n// the mirroring row — and \"delete\" is a `deletedAt` tombstone (an attr-merge\n// `update`; odla-db's `merge` op is json-only), never a row delete, so\n// analyses and proposals that reference the asset stay coherent.\nimport { ASSET_KINDS, BRAND_NS, type AssetKind } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport type { BrandEntityRef, BrandOp } from \"../types\";\nimport { assertAnalysis, assertAssetContentType, capString } from \"../validate\";\n\n/** Input to {@link createAssetOps} — the storage upload's receipt fields\n * (`path`/`url`/`size`) plus the declared kind and the book's audience. */\nexport interface CreateAssetInput {\n id: string;\n bookId: string;\n kind: AssetKind;\n path: string;\n url: string;\n contentType: string;\n size: number;\n uploadedBy: string;\n audience: string[];\n title?: string;\n now: number;\n}\n\n/**\n * Ops to record one uploaded asset: a single `brand_asset` row mirroring the\n * storage object, with the content type re-checked against the allowlist and\n * the size required to be a positive byte count.\n */\nexport function createAssetOps(input: CreateAssetInput): BrandOp[] {\n if (!(ASSET_KINDS as readonly string[]).includes(input.kind))\n throw new BrandInputError(`kind must be one of: ${ASSET_KINDS.join(\", \")}`);\n const contentType = assertAssetContentType(input.contentType);\n if (typeof input.size !== \"number\" || !Number.isFinite(input.size) || input.size <= 0)\n throw new BrandInputError(\"size must be a positive byte count\");\n const title = input.title === undefined ? undefined : capString(input.title, \"title\", 160);\n return [\n {\n t: \"update\",\n ns: BRAND_NS.asset,\n id: input.id,\n attrs: {\n id: input.id,\n bookId: input.bookId,\n kind: input.kind,\n path: capString(input.path, \"path\", 512),\n url: capString(input.url, \"url\", 1024),\n contentType,\n size: input.size,\n audience: input.audience,\n uploadedBy: input.uploadedBy,\n createdAt: input.now,\n ...(title ? { title } : {}),\n },\n },\n ];\n}\n\n/**\n * Ops to tombstone an asset after its storage object was deleted: stamp\n * `deletedAt` in place. List reads exclude tombstoned rows; the row itself\n * stays for provenance.\n */\nexport function tombstoneAssetOps(assetId: BrandEntityRef, now: number): BrandOp[] {\n return [{ t: \"update\", ns: BRAND_NS.asset, id: assetId, attrs: { deletedAt: now } }];\n}\n\n/**\n * Ops to record an agent's analysis of an asset: the validated + capped\n * analysis json plus `analyzedAt`. Replaces any prior analysis whole.\n */\nexport function recordAnalysisOps(assetId: BrandEntityRef, analysis: unknown, now: number): BrandOp[] {\n return [\n {\n t: \"update\",\n ns: BRAND_NS.asset,\n id: assetId,\n attrs: { analysis: assertAnalysis(analysis), analyzedAt: now },\n },\n ];\n}\n","// Asset tools: view_asset feeds real uploaded bytes to the model as an\n// image/document block inside the tool result (the vision path), and\n// record_asset_analysis persists what the model saw through the validated\n// ops layer. view_asset output is model-visible content fetched from\n// storage, so the tool declares `tool_untrusted:view_asset` taint.\n// @odla-ai/ai is imported for types only.\nimport type { DocumentBlock, ImageBlock, ImageMediaType, TextBlock, ToolDef, ToolOutput } from \"@odla-ai/ai\";\nimport { BRAND_NS } from \"../constants\";\nimport { BrandNotFoundError } from \"../errors\";\nimport { recordAnalysisOps } from \"../ops/assets\";\nimport type { BrandAsset } from \"../types\";\nimport { assertAnalysis } from \"../validate\";\nimport type { BrandToolCtx } from \"./skill\";\n\n/** Byte cap for in-conversation asset viewing (4.5 MiB — providers reject\n * larger inline payloads well before context does). */\nexport const MAX_VIEW_BYTES = 4_718_592;\n\nconst IMAGE_TYPES: ReadonlySet<string> = new Set([\"image/png\", \"image/jpeg\", \"image/gif\", \"image/webp\"]);\n\n/**\n * Base64-encode bytes without assuming a platform: `btoa` over a chunked\n * binary string where available (workerd, browsers, Node ≥ 16), `Buffer`\n * otherwise. Chunking keeps `String.fromCharCode` off the argument-count\n * cliff for multi-megabyte assets.\n */\nexport function base64FromBytes(bytes: Uint8Array): string {\n if (typeof btoa === \"function\") {\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 0x2000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x2000));\n }\n return btoa(binary);\n }\n return Buffer.from(bytes).toString(\"base64\");\n}\n\nconst bareType = (ct: string): string => (ct.split(\";\")[0] ?? \"\").trim().toLowerCase();\n\nfunction viewOutput(asset: BrandAsset, bytes: Uint8Array, contentType: string): ToolOutput {\n const caption: TextBlock = {\n type: \"text\",\n text: `Asset ${asset.id} (${asset.kind}, ${contentType}, ${bytes.byteLength} bytes${asset.title ? `, \"${asset.title}\"` : \"\"}):`,\n };\n if (IMAGE_TYPES.has(contentType)) {\n const image: ImageBlock = {\n type: \"image\",\n source: { type: \"base64\", mediaType: contentType as ImageMediaType, data: base64FromBytes(bytes) },\n };\n return { content: [caption, image] };\n }\n const document: DocumentBlock = {\n type: \"document\",\n source: { type: \"base64\", mediaType: \"application/pdf\", data: base64FromBytes(bytes) },\n };\n return { content: [caption, document] };\n}\n\n/**\n * The asset tools, scoped to the context's book: `view_asset` (fetch the\n * stored bytes and return them as an image/PDF block, with size and type\n * gates) and `record_asset_analysis` (persist the model's description,\n * dominant colors, and tags onto the asset row).\n */\nexport function assetTools(ctx: BrandToolCtx): ToolDef[] {\n const loadAsset = async (assetId: string): Promise<BrandAsset> => {\n const res = await ctx.db.query({\n [BRAND_NS.asset]: { $: { where: { id: assetId, bookId: ctx.bookId } } },\n });\n const row = (res[BRAND_NS.asset] ?? [])[0] as BrandAsset | undefined;\n if (!row || row.deletedAt) throw new BrandNotFoundError(`asset ${assetId}`);\n return row;\n };\n\n const viewAsset: ToolDef = {\n name: \"view_asset\",\n description:\n \"Look at an uploaded asset: fetches its bytes and returns the image (png/jpeg/gif/webp) or PDF for you to view. Other types cannot be viewed in-conversation.\",\n inputSchema: {\n type: \"object\",\n required: [\"assetId\"],\n properties: { assetId: { type: \"string\", description: \"The asset row id from list_assets.\" } },\n },\n outputTaint: [\"tool_untrusted:view_asset\"],\n handler: ctx.guard(async (input) => {\n const asset = await loadAsset(String(input.assetId));\n if (!ctx.visionInToolResults) {\n return {\n content:\n `This model cannot take images inside tool results. Asset ${asset.id} must be attached ` +\n \"as a pre-turn image by the host instead — ask the human to re-send their message \" +\n \"referencing the asset (the dispatcher attaches it up front), or describe it from \" +\n \"what they tell you.\",\n };\n }\n const url = asset.url.startsWith(\"http\") ? asset.url : ctx.fileBaseUrl + asset.url;\n const fetched = await ctx.fetchBytes(url);\n if (fetched.bytes.byteLength > MAX_VIEW_BYTES) {\n return {\n content:\n `Asset ${asset.id} is ${fetched.bytes.byteLength} bytes — over the ${MAX_VIEW_BYTES}-byte ` +\n \"(4.5 MB) in-conversation viewing cap. Ask the human for a smaller export of this file.\",\n };\n }\n const served = bareType(fetched.contentType);\n const effective = IMAGE_TYPES.has(served) || served === \"application/pdf\" ? served : bareType(asset.contentType);\n if (!IMAGE_TYPES.has(effective) && effective !== \"application/pdf\") {\n return {\n content:\n `Asset ${asset.id} is ${effective} — stored but not viewable in-conversation. ` +\n \"Ask the human to describe it, or to upload a PNG/JPEG export you can view.\",\n };\n }\n return viewOutput(asset, fetched.bytes, effective);\n }),\n };\n\n const recordAnalysis: ToolDef = {\n name: \"record_asset_analysis\",\n description:\n \"Record what you observed in an asset you viewed: a description, its dominant colors as #rrggbb hex, and tags. Overwrites any prior analysis.\",\n inputSchema: {\n type: \"object\",\n required: [\"assetId\", \"description\", \"dominantColors\", \"tags\"],\n properties: {\n assetId: { type: \"string\" },\n description: { type: \"string\", description: \"What the asset shows (max 2000 chars).\" },\n dominantColors: { type: \"array\", items: { type: \"string\" }, maxItems: 12, description: \"Dominant colors as hex.\" },\n tags: { type: \"array\", items: { type: \"string\" }, maxItems: 24 },\n },\n },\n handler: ctx.guard(async (input) => {\n const asset = await loadAsset(String(input.assetId));\n const analysis = assertAnalysis({\n description: input.description,\n dominantColors: input.dominantColors,\n tags: input.tags,\n });\n await ctx.db.transact(recordAnalysisOps(asset.id, analysis, ctx.now()), { mutationId: ctx.newId() });\n return {\n content: `Recorded analysis for asset ${asset.id}: ${analysis.dominantColors.length} dominant color(s), ${analysis.tags.length} tag(s).`,\n };\n }),\n };\n\n return [viewAsset, recordAnalysis];\n}\n","// Book documentation tools: update_section upserts one section per kind\n// through the natural-key ops builder, and compile_tokens turns the active\n// (or named) palette + typography section into the @odla-ai/ui token cache\n// on the book row. Compile never throws on a bad palette — its warnings are\n// relayed for the agent to explain. @odla-ai/ai is types-only.\nimport type { ToolDef } from \"@odla-ai/ai\";\nimport { BRAND_NS, SECTION_KINDS, type SectionKind, type SectionStatus } from \"../constants\";\nimport { BrandInputError, BrandNotFoundError } from \"../errors\";\nimport { updateBookOps } from \"../ops/books\";\nimport { sectionKey, upsertSectionOps } from \"../ops/sections\";\nimport { compileBrandTokens } from \"../tokens/compile\";\nimport type { BrandPalette, BrandSection, BrandTokensSnapshot, TypographySection } from \"../types\";\nimport { capString } from \"../validate\";\nimport type { BrandToolCtx } from \"./skill\";\n\n/**\n * The book tools: `update_section` (validated per-kind content, upserted by\n * natural key with the book's audience snapshot) and `compile_tokens`\n * (palette + typography → light/dark token cache on the book row).\n */\nexport function bookTools(ctx: BrandToolCtx): ToolDef[] {\n const updateSection: ToolDef = {\n name: \"update_section\",\n description:\n \"Create or replace one brand-book section (palette, typography, voice, logo, or imagery). Content is validated per kind. Status defaults to draft; a human approves.\",\n inputSchema: {\n type: \"object\",\n required: [\"kind\", \"content\"],\n properties: {\n kind: { type: \"string\", enum: [...SECTION_KINDS] },\n content: { type: \"object\", description: \"The section payload for its kind.\" },\n status: { type: \"string\", enum: [\"draft\", \"approved\"] },\n },\n },\n handler: ctx.guard(async (input) => {\n const book = await ctx.loadBook();\n const kind = String(input.kind) as SectionKind;\n const ops = upsertSectionOps({\n bookId: ctx.bookId,\n kind,\n content: input.content as Record<string, unknown>,\n status: input.status === undefined ? undefined : (input.status as SectionStatus),\n audience: book.memberIds,\n updatedBy: ctx.self.selfId,\n now: ctx.now(),\n });\n await ctx.db.transact(ops, { mutationId: ctx.newId() });\n const status = input.status === undefined ? \"draft\" : String(input.status);\n return { content: `Saved ${kind} section as ${status} (key ${sectionKey(ctx.bookId, kind)}).` };\n }),\n };\n\n const compileTokens: ToolDef = {\n name: \"compile_tokens\",\n description:\n \"Compile the book's palette (paletteId argument, or the active palette) plus the typography section into light/dark @odla-ai/ui tokens, cached on the book. Returns the compiler's warnings.\",\n inputSchema: {\n type: \"object\",\n properties: { paletteId: { type: \"string\", description: \"Defaults to the book's active palette.\" } },\n },\n handler: ctx.guard(async (input) => {\n const book = await ctx.loadBook();\n const paletteId = input.paletteId === undefined ? book.activePaletteId : capString(input.paletteId, \"paletteId\", 128);\n if (!paletteId) {\n throw new BrandInputError(\"no palette to compile: pass paletteId, or get a palette proposal accepted first\");\n }\n const pres = await ctx.db.query({\n [BRAND_NS.palette]: { $: { where: { id: paletteId, bookId: ctx.bookId } } },\n });\n const palette = (pres[BRAND_NS.palette] ?? [])[0] as BrandPalette | undefined;\n if (!palette) throw new BrandNotFoundError(`palette ${paletteId}`);\n const sres = await ctx.db.query({\n [BRAND_NS.section]: { $: { where: { key: sectionKey(ctx.bookId, \"typography\") } } },\n });\n const typography = (sres[BRAND_NS.section] ?? [])[0] as BrandSection | undefined;\n const compiled = compileBrandTokens({\n swatches: palette.swatches,\n ...(typography ? { typography: typography.content as TypographySection } : {}),\n });\n const now = ctx.now();\n const snapshot: BrandTokensSnapshot = {\n light: compiled.light,\n dark: compiled.dark,\n warnings: compiled.warnings,\n compiledAt: now,\n };\n await ctx.db.transact(updateBookOps(ctx.bookId, { tokens: snapshot }, now), { mutationId: ctx.newId() });\n const count = compiled.warnings.length;\n const lines = [\n `Compiled ${Object.keys(compiled.light).length} light + ${Object.keys(compiled.dark).length} dark tokens from palette ${paletteId}; ${count} warning(s).`,\n ...compiled.warnings\n .slice(0, 3)\n .map((w) => `- ${w.token}: ${w.message}${w.adjustedFrom ? ` (adjusted from ${w.adjustedFrom})` : \"\"}`),\n ];\n if (count > 3) lines.push(`… and ${count - 3} more.`);\n return { content: lines.join(\"\\n\") };\n }),\n };\n\n return [updateSection, compileTokens];\n}\n","// Color-exploration + proposal tools. analyze_color / evaluate_contrast are\n// pure math over the color engine (the agent's grounding for every hex it\n// suggests); propose_palette PARKS a proposal for human review — it never\n// activates anything; resolve_proposal applies the human's verdict through\n// the atomic accept/reject op builders. @odla-ai/ai is types-only.\nimport type { ToolDef } from \"@odla-ai/ai\";\nimport { BRAND_NS } from \"../constants\";\nimport {\n analogous,\n complementary,\n contrastRatio,\n derivePalette,\n hexToOklch,\n meetsAA,\n meetsAAA,\n monochrome,\n nearestNamedColor,\n pickTextOn,\n relativeLuminance,\n splitComplementary,\n tetradic,\n tintShadeRamp,\n triadic,\n} from \"../color/index\";\nimport { BrandInputError, BrandNotFoundError } from \"../errors\";\nimport { acceptProposalOps, proposePaletteOps, rejectProposalOps } from \"../ops/palettes\";\nimport type { BrandProposal, Swatch, SwatchRole } from \"../types\";\nimport { assertHex, assertSwatches, capString } from \"../validate\";\nimport type { BrandToolCtx } from \"./skill\";\n\nconst r2 = (n: number): string => n.toFixed(2);\nconst pf = (ok: boolean): string => (ok ? \"pass\" : \"FAIL\");\n\nconst verdict = (ratio: number): string =>\n `${r2(ratio)}:1 — AA text ${pf(meetsAA(ratio))}, AA large/ui ${pf(meetsAA(ratio, \"large-text\"))}, AAA text ${pf(meetsAAA(ratio))}`;\n\n/** Harmony strategies propose_palette accepts, mapped to the seed companions\n * that replace the derived secondary/highlight (in that order). */\nconst HARMONY_COMPANIONS: Record<string, (seed: string) => string[]> = {\n complementary: (s) => [complementary(s)],\n analogous: (s) => [...analogous(s)],\n triadic: (s) => [...triadic(s)],\n split: (s) => [...splitComplementary(s)],\n tetradic: (s) => tetradic(s).slice(0, 2),\n monochrome: (s) => monochrome(s, 4).slice(1, 3),\n};\n\nfunction applyHarmony(swatches: Swatch[], seedHex: string, harmony: unknown): Swatch[] {\n if (typeof harmony !== \"string\" || !(harmony in HARMONY_COMPANIONS)) {\n throw new BrandInputError(`harmony must be one of: ${Object.keys(HARMONY_COMPANIONS).join(\", \")}`);\n }\n const [secondary, highlight] = HARMONY_COMPANIONS[harmony]!(seedHex);\n return swatches.map((s) => {\n const hex = s.role === \"secondary\" ? secondary : s.role === \"highlight\" ? highlight : undefined;\n if (!hex) return s;\n return { ...s, hex, name: nearestNamedColor(hex).name, rationale: `${harmony} companion of the seed` };\n });\n}\n\n/** WCAG ratios (2 dp) for the palette's key role pairs — stored verbatim in\n * the proposal payload so the human reviews numbers, not vibes. */\nfunction contrastReport(swatches: Swatch[]): Record<string, number> {\n const byRole = (role: SwatchRole): string | undefined => swatches.find((s) => s.role === role)?.hex;\n const bg = byRole(\"bg\") ?? \"#ffffff\";\n const report: Record<string, number> = {};\n const put = (label: string, fg?: string): void => {\n if (fg) report[label] = Math.round(contrastRatio(fg, bg) * 100) / 100;\n };\n put(\"text-on-bg\", byRole(\"text\"));\n put(\"primary-on-bg\", byRole(\"primary\"));\n put(\"good-on-bg\", byRole(\"good\"));\n put(\"warn-on-bg\", byRole(\"warn\"));\n put(\"danger-on-bg\", byRole(\"danger\"));\n const primary = byRole(\"primary\");\n if (primary) report[\"text-on-primary\"] = Math.round(contrastRatio(pickTextOn(primary), primary) * 100) / 100;\n return report;\n}\n\nconst INCLUDE_SECTIONS = [\"harmony\", \"ramp\"] as const;\n\nfunction analyzeLines(hex: string, include: string[]): string[] {\n const lch = hexToOklch(hex);\n const named = nearestNamedColor(hex);\n const lines = [\n `${hex} — nearest CSS name: ${named.name} (ΔEOK ${named.deltaEOK.toFixed(3)})`,\n `OKLCH: L ${lch.L.toFixed(3)}, C ${lch.C.toFixed(3)}, h ${lch.h.toFixed(1)}°`,\n `relative luminance ${relativeLuminance(hex).toFixed(3)}; contrast ${r2(contrastRatio(hex, \"#ffffff\"))}:1 on white, ${r2(contrastRatio(hex, \"#000000\"))}:1 on black`,\n `readable text on it: ${pickTextOn(hex)}`,\n ];\n if (include.includes(\"harmony\")) {\n const [aMinus, aPlus] = analogous(hex);\n const [tMinus, tPlus] = triadic(hex);\n const [sMinus, sPlus] = splitComplementary(hex);\n lines.push(\n `harmony — complementary ${complementary(hex)}; analogous ${aMinus} ${aPlus}; triadic ${tMinus} ${tPlus}; split ${sMinus} ${sPlus}`,\n );\n }\n if (include.includes(\"ramp\")) lines.push(`ramp — ${tintShadeRamp(hex).join(\" \")}`);\n return lines;\n}\n\n/**\n * The palette tools: `analyze_color`, `evaluate_contrast` (pure math),\n * `propose_palette` (writes an OPEN proposal with an automatic contrast\n * report), and `resolve_proposal` (applies the human's explicit verdict).\n */\nexport function paletteTools(ctx: BrandToolCtx): ToolDef[] {\n const analyzeColor: ToolDef = {\n name: \"analyze_color\",\n description:\n \"Analyze one color: nearest CSS name, OKLCH coordinates, luminance, contrast on white/black. Optionally include harmony companions and a tint/shade ramp.\",\n inputSchema: {\n type: \"object\",\n required: [\"hex\"],\n properties: {\n hex: { type: \"string\", description: \"#rgb or #rrggbb\" },\n include: { type: \"array\", items: { type: \"string\", enum: [...INCLUDE_SECTIONS] } },\n },\n },\n handler: ctx.guard(async (input) => {\n const hex = assertHex(input.hex, \"hex\");\n const include = input.include === undefined ? [] : input.include;\n if (!Array.isArray(include) || include.some((s) => !(INCLUDE_SECTIONS as readonly unknown[]).includes(s))) {\n throw new BrandInputError(`include entries must be one of: ${INCLUDE_SECTIONS.join(\", \")}`);\n }\n return { content: analyzeLines(hex, include as string[]).join(\"\\n\") };\n }),\n };\n\n const evaluateContrast: ToolDef = {\n name: \"evaluate_contrast\",\n description:\n \"WCAG 2.1 contrast: pass pairs ([{fg,bg}]) for specific combinations, or hexes ([…]) for every pairwise ratio. Reports AA/AAA verdicts.\",\n inputSchema: {\n type: \"object\",\n properties: {\n pairs: {\n type: \"array\",\n maxItems: 20,\n items: { type: \"object\", required: [\"fg\", \"bg\"], properties: { fg: { type: \"string\" }, bg: { type: \"string\" } } },\n },\n hexes: { type: \"array\", minItems: 2, maxItems: 8, items: { type: \"string\" } },\n },\n },\n handler: ctx.guard(async (input) => {\n if (Array.isArray(input.pairs) && input.pairs.length > 0) {\n if (input.pairs.length > 20) throw new BrandInputError(\"pairs must have at most 20 entries\");\n const lines = input.pairs.map((raw, i) => {\n const p = (raw ?? {}) as Record<string, unknown>;\n const fg = assertHex(p.fg, `pairs[${i}].fg`);\n const bg = assertHex(p.bg, `pairs[${i}].bg`);\n return `${fg} on ${bg}: ${verdict(contrastRatio(fg, bg))}`;\n });\n return { content: lines.join(\"\\n\") };\n }\n if (Array.isArray(input.hexes)) {\n if (input.hexes.length < 2 || input.hexes.length > 8) {\n throw new BrandInputError(\"hexes must have 2 to 8 entries\");\n }\n const hexes = input.hexes.map((h, i) => assertHex(h, `hexes[${i}]`));\n const lines: string[] = [];\n for (let i = 0; i < hexes.length; i++) {\n for (let j = i + 1; j < hexes.length; j++) {\n lines.push(`${hexes[i]} vs ${hexes[j]}: ${verdict(contrastRatio(hexes[i]!, hexes[j]!))}`);\n }\n }\n return { content: lines.join(\"\\n\") };\n }\n throw new BrandInputError(\"provide pairs ([{fg,bg}, …]) or hexes ([#rrggbb, …])\");\n }),\n };\n\n const proposePalette: ToolDef = {\n name: \"propose_palette\",\n description:\n \"Park a palette proposal for human review (does NOT change the brand). Pass explicit swatches, or a seedHex (and optional harmony) to derive a full palette. A WCAG contrast report is attached automatically.\",\n inputSchema: {\n type: \"object\",\n required: [\"name\", \"rationale\"],\n properties: {\n name: { type: \"string\" },\n rationale: { type: \"string\", description: \"Why these colors — cite assets, harmony, contrast.\" },\n seedHex: { type: \"string\" },\n harmony: { type: \"string\", enum: Object.keys(HARMONY_COMPANIONS) },\n swatches: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"role\", \"hex\"],\n properties: {\n role: { type: \"string\" },\n hex: { type: \"string\" },\n name: { type: \"string\" },\n rationale: { type: \"string\" },\n },\n },\n },\n },\n },\n handler: ctx.guard(async (input) => {\n const book = await ctx.loadBook();\n const seedHex = input.seedHex === undefined ? undefined : assertHex(input.seedHex, \"seedHex\");\n let swatches: Swatch[];\n if (input.swatches !== undefined) {\n swatches = assertSwatches(input.swatches);\n } else {\n if (!seedHex) throw new BrandInputError(\"provide swatches, or a seedHex to derive a palette from\");\n swatches = derivePalette(seedHex);\n if (input.harmony !== undefined) swatches = applyHarmony(swatches, seedHex, input.harmony);\n }\n const report = contrastReport(swatches);\n const id = ctx.newId();\n const ops = proposePaletteOps({\n id,\n bookId: ctx.bookId,\n name: String(input.name),\n rationale: String(input.rationale),\n swatches,\n seedHex,\n contrastReport: report,\n createdBy: ctx.self.selfId,\n audience: book.memberIds,\n now: ctx.now(),\n });\n await ctx.db.transact(ops, { mutationId: id });\n const reportText = Object.entries(report).map(([k, v]) => `${k} ${r2(v)}:1`).join(\", \");\n return {\n content:\n `Parked palette proposal ${id} (\"${String(input.name).trim()}\", ${swatches.length} swatches` +\n `${seedHex ? `, seeded from ${seedHex}` : \"\"}). Contrast: ${reportText}. ` +\n \"Awaiting explicit human approval — call resolve_proposal only after the human confirms.\",\n };\n }),\n };\n\n const resolveProposal: ToolDef = {\n name: \"resolve_proposal\",\n description:\n \"Apply the human's explicit verdict on an open proposal. ONLY call this after the human has clearly accepted or rejected in the conversation — never on your own initiative.\",\n inputSchema: {\n type: \"object\",\n required: [\"proposalId\", \"resolution\"],\n properties: {\n proposalId: { type: \"string\" },\n resolution: { type: \"string\", enum: [\"accepted\", \"rejected\"] },\n note: { type: \"string\" },\n },\n },\n handler: ctx.guard(async (input) => {\n const proposalId = String(input.proposalId);\n const res = await ctx.db.query({\n [BRAND_NS.proposal]: { $: { where: { id: proposalId, bookId: ctx.bookId } } },\n });\n const proposal = (res[BRAND_NS.proposal] ?? [])[0] as BrandProposal | undefined;\n if (!proposal) throw new BrandNotFoundError(`proposal ${proposalId}`);\n const note = input.note === undefined ? undefined : capString(input.note, \"note\", 1000);\n const now = ctx.now();\n if (input.resolution === \"accepted\") {\n const paletteId = ctx.newId();\n const ops = acceptProposalOps({ proposal, paletteId, resolvedBy: ctx.self.selfId, now, resolutionNote: note });\n await ctx.db.transact(ops, { mutationId: paletteId });\n return { content: `Proposal ${proposalId} accepted — palette ${paletteId} written and set as the book's active palette.` };\n }\n if (input.resolution === \"rejected\") {\n const ops = rejectProposalOps({ proposal, resolvedBy: ctx.self.selfId, now, resolutionNote: note });\n await ctx.db.transact(ops, { mutationId: ctx.newId() });\n return { content: `Proposal ${proposalId} rejected.` };\n }\n throw new BrandInputError('resolution must be \"accepted\" or \"rejected\"');\n }),\n };\n\n return [analyzeColor, evaluateContrast, proposePalette, resolveProposal];\n}\n","// Read-only brand tools: a compact structured-text snapshot of the book\n// (read_brand_book) and the live asset list (list_assets). Deterministic, no\n// AI calls, no writes — the agent's orientation step before it proposes\n// anything. @odla-ai/ai is imported for types only.\nimport type { ToolDef } from \"@odla-ai/ai\";\nimport { ASSET_KINDS, BRAND_NS } from \"../constants\";\nimport { BrandInputError, BrandNotFoundError } from \"../errors\";\nimport type { BrandAsset, BrandBook, BrandPalette, BrandProposal, BrandSection } from \"../types\";\nimport type { BrandToolCtx } from \"./skill\";\n\nconst iso = (ms: number): string => new Date(ms).toISOString();\n\nfunction bookLines(book: BrandBook): string[] {\n const lines = [\n `brand book \"${book.name}\" (${book.slug}) — ${book.status}`,\n `members: ${book.memberIds.join(\", \")}`,\n `active palette: ${book.activePaletteId ?? \"(none accepted yet)\"}`,\n book.tokens\n ? `tokens: compiled ${iso(book.tokens.compiledAt)} with ${book.tokens.warnings.length} warning(s)`\n : \"tokens: (not compiled)\",\n ];\n if (book.summary) lines.push(`summary: ${book.summary}`);\n return lines;\n}\n\nfunction childLines(sections: BrandSection[], palettes: BrandPalette[], proposals: BrandProposal[]): string[] {\n return [\n \"sections:\",\n ...(sections.length\n ? sections.map((s) => `- ${s.kind}: ${s.status}, updated ${iso(s.updatedAt)} by ${s.updatedBy}`)\n : [\"- (none)\"]),\n \"palettes:\",\n ...(palettes.length\n ? palettes.map((p) => `- ${p.id} \"${p.name}\" (${p.status}, ${p.source}, ${p.swatches.length} swatches)`)\n : [\"- (none)\"]),\n \"open proposals:\",\n ...(proposals.length\n ? proposals.map((p) => `- ${p.id} (${p.kind}) by ${p.createdBy}: ${p.rationale}`)\n : [\"- (none)\"]),\n ];\n}\n\n/**\n * The two read-only tools, scoped to the context's book:\n * `read_brand_book` (book + sections + palettes + open proposals as compact\n * text) and `list_assets` (live, non-tombstoned asset rows, optionally\n * filtered by kind).\n */\nexport function readTools(ctx: BrandToolCtx): ToolDef[] {\n const readBrandBook: ToolDef = {\n name: \"read_brand_book\",\n description:\n \"Read the current brand book: status, members, active palette, compiled tokens, sections, palettes, and open proposals.\",\n inputSchema: { type: \"object\", properties: {} },\n handler: ctx.guard(async () => {\n const res = await ctx.db.query({\n [BRAND_NS.book]: { $: { where: { id: ctx.bookId } } },\n [BRAND_NS.section]: { $: { where: { bookId: ctx.bookId }, order: { updatedAt: \"asc\" } } },\n [BRAND_NS.palette]: { $: { where: { bookId: ctx.bookId }, order: { createdAt: \"asc\" } } },\n [BRAND_NS.proposal]: { $: { where: { bookId: ctx.bookId, status: \"open\" }, order: { createdAt: \"asc\" } } },\n });\n const book = (res[BRAND_NS.book] ?? [])[0] as BrandBook | undefined;\n if (!book) throw new BrandNotFoundError(`brand book ${ctx.bookId}`);\n const sections = (res[BRAND_NS.section] ?? []) as BrandSection[];\n const palettes = (res[BRAND_NS.palette] ?? []) as BrandPalette[];\n const proposals = (res[BRAND_NS.proposal] ?? []) as BrandProposal[];\n return { content: [...bookLines(book), ...childLines(sections, palettes, proposals)].join(\"\\n\") };\n }),\n };\n\n const listAssets: ToolDef = {\n name: \"list_assets\",\n description:\n \"List the book's uploaded assets (id, kind, content type, size, title, analysis state). Tombstoned assets are excluded.\",\n inputSchema: {\n type: \"object\",\n properties: {\n kind: { type: \"string\", enum: [...ASSET_KINDS], description: \"Only assets of this kind.\" },\n },\n },\n handler: ctx.guard(async (input) => {\n const where: Record<string, unknown> = { bookId: ctx.bookId };\n if (input.kind !== undefined) {\n if (typeof input.kind !== \"string\" || !(ASSET_KINDS as readonly string[]).includes(input.kind)) {\n throw new BrandInputError(`kind must be one of: ${ASSET_KINDS.join(\", \")}`);\n }\n where.kind = input.kind;\n }\n const res = await ctx.db.query({ [BRAND_NS.asset]: { $: { where, order: { createdAt: \"asc\" } } } });\n const rows = ((res[BRAND_NS.asset] ?? []) as BrandAsset[]).filter((a) => !a.deletedAt);\n if (rows.length === 0) {\n return { content: input.kind ? `(no ${String(input.kind)} assets uploaded yet)` : \"(no assets uploaded yet)\" };\n }\n const lines = rows.map(\n (a) =>\n `${a.id} — ${a.kind}, ${a.contentType}, ${a.size} bytes` +\n `${a.title ? `, \"${a.title}\"` : \"\"}${a.analysis ? \" (analyzed)\" : \" (not analyzed)\"}`,\n );\n return { content: lines.join(\"\\n\") };\n }),\n };\n\n return [readBrandBook, listAssets];\n}\n","// The @odla-ai/ai Skill assembly for a brand book: one shared tool context\n// (injected db + identity + defaults), the workflow instructions, and the\n// tools from the four tool modules. @odla-ai/ai is an optional peer imported\n// for TYPES ONLY (chat's pattern) — the package works without it installed.\n//\n// Error contract with the agent loop: runAgent converts a handler throw into\n// a SANITIZED error tool_result (`Tool \"x\" failed.`) because arbitrary\n// handler messages may carry credentials. Brand's own validation errors are\n// crafted, secret-free, and actionable, so `guard` catches BrandInputError /\n// BrandNotFoundError and returns the message as an error output the model can\n// act on; anything unexpected still propagates into the loop's sanitizer.\nimport type { Skill, ToolHandler } from \"@odla-ai/ai\";\nimport { BRAND_NS } from \"../constants\";\nimport { resolveDeps, type BrandFetchedBytes } from \"../deps\";\nimport { BrandInputError, BrandNotFoundError } from \"../errors\";\nimport type { BrandBook, BrandDb } from \"../types\";\nimport { assetTools } from \"./asset-tools\";\nimport { bookTools } from \"./book-tools\";\nimport { paletteTools } from \"./palette-tools\";\nimport { readTools } from \"./read-tools\";\n\n/** The bot identity the skill writes as (`selfId` = the agent id carried in\n * the book's `memberIds` roster and every audience snapshot). */\nexport interface BrandSkillSelf {\n selfId: string;\n kind: \"bot\";\n displayName?: string;\n}\n\n/** Options for {@link brandSkill}. */\nexport interface BrandSkillOpts {\n /** The injected odla client (a real @odla-ai/db AdminDb satisfies it). */\n db: BrandDb;\n /** The one brand book this skill instance is scoped to. */\n bookId: string;\n /** The bot identity acting through these tools. */\n self: BrandSkillSelf;\n /** Origin prefixed onto relative asset urls (`url` starting with `/`). */\n fileBaseUrl: string;\n /** Asset-byte fetcher override (default: global fetch via resolveDeps). */\n fetchBytes?: (url: string) => Promise<BrandFetchedBytes>;\n /** False when the model cannot take image/document blocks inside a\n * tool_result — view_asset then steers to the pre-turn attachment path. */\n visionInToolResults?: boolean;\n /** Clock override (tests). */\n now?: () => number;\n /** Id factory override (tests). */\n newId?: () => string;\n}\n\n/** The resolved context every brand tool module builds its tools from. */\nexport interface BrandToolCtx {\n db: BrandDb;\n bookId: string;\n self: BrandSkillSelf;\n fileBaseUrl: string;\n fetchBytes: (url: string) => Promise<BrandFetchedBytes>;\n /** Whether image/document blocks may be returned inside tool results. */\n visionInToolResults: boolean;\n now: () => number;\n newId: () => string;\n /** Load the scoped book row; throws BrandNotFoundError when missing. */\n loadBook(): Promise<BrandBook>;\n /** Wrap a handler so Brand validation errors come back as actionable\n * error text instead of the loop's sanitized generic failure. */\n guard(handler: ToolHandler): ToolHandler;\n}\n\n/** Workflow guidance appended to the persona's system prompt as the skill's\n * instruction section. */\nexport const BRAND_INSTRUCTIONS =\n \"You help build and maintain ONE brand book. Workflow, in order:\\n\" +\n \"1. Understand the brand first: read_brand_book and list_assets before proposing anything.\\n\" +\n \"2. Look at the real material: view_asset on logos and inspiration, then record what you \" +\n \"saw with record_asset_analysis (description, dominant colors as hex, tags).\\n\" +\n \"3. Explore with the math tools: analyze_color and evaluate_contrast. Never invent a hex \" +\n \"without a rationale — ground every color in an asset's dominant color, a harmony \" +\n \"companion, or a contrast fix, and say which.\\n\" +\n \"4. propose_palette parks a proposal for review. It does NOT change the brand.\\n\" +\n \"5. WAIT for the human to explicitly accept or reject in the conversation before calling \" +\n \"resolve_proposal — never resolve a proposal on your own initiative.\\n\" +\n \"6. After acceptance, document the rest with update_section (typography, voice, logo, \" +\n \"imagery) and run compile_tokens.\\n\" +\n \"7. Relay compile warnings conversationally — explain what was adjusted and why, don't \" +\n \"just paste them.\";\n\n/**\n * Build the brand Skill: read/asset/palette/book tools scoped to one book,\n * acting as one bot identity, plus {@link BRAND_INSTRUCTIONS}. Attach it to\n * a Persona (or use `createBrandPersona`).\n */\nexport function brandSkill(opts: BrandSkillOpts): Skill {\n const deps = resolveDeps({ db: opts.db, now: opts.now, newId: opts.newId, fetchBytes: opts.fetchBytes });\n const ctx: BrandToolCtx = {\n db: deps.db,\n bookId: opts.bookId,\n self: opts.self,\n fileBaseUrl: opts.fileBaseUrl,\n fetchBytes: deps.fetchBytes,\n visionInToolResults: opts.visionInToolResults !== false,\n now: deps.now,\n newId: deps.newId,\n loadBook: async () => {\n const res = await deps.db.query({ [BRAND_NS.book]: { $: { where: { id: opts.bookId } } } });\n const row = (res[BRAND_NS.book] ?? [])[0] as BrandBook | undefined;\n if (!row) throw new BrandNotFoundError(`brand book ${opts.bookId}`);\n return row;\n },\n guard: (handler) => async (input, toolCtx) => {\n try {\n return await handler(input, toolCtx);\n } catch (error) {\n if (error instanceof BrandInputError || error instanceof BrandNotFoundError) {\n return { content: error.message, isError: true };\n }\n throw error;\n }\n },\n };\n return {\n name: \"brand\",\n instructions: BRAND_INSTRUCTIONS,\n tools: [...readTools(ctx), ...assetTools(ctx), ...paletteTools(ctx), ...bookTools(ctx)],\n };\n}\n","// The brand-director Persona: the brand skill pre-attached, a default system\n// prompt encoding the explore → propose → human approves → compile loop, and\n// the capability probe hosts use to decide whether asset bytes can ride\n// inside tool results or must be attached pre-turn. @odla-ai/ai types only.\nimport type { Persona, Skill } from \"@odla-ai/ai\";\nimport { brandSkill, type BrandSkillOpts } from \"./skill\";\n\n/** The default brand-director system prompt (override via `system`). */\nexport const DEFAULT_BRAND_SYSTEM =\n \"You are a meticulous brand director for one brand book. You study the real material \" +\n \"before forming opinions, you justify every color with math (harmony, ΔEOK, WCAG \" +\n \"contrast) or provenance (an asset's dominant colors), and you present options rather \" +\n \"than dictating. Proposals are yours to make; decisions are the human's — never \" +\n \"resolve a proposal without their explicit confirmation in this conversation. When \" +\n \"tokens compile with warnings, explain each adjustment in plain language.\";\n\n/** Options for {@link createBrandPersona}. */\nexport interface CreateBrandPersonaOpts {\n /** Canonical model id the persona runs on. */\n model: string;\n /** System prompt override (default {@link DEFAULT_BRAND_SYSTEM}). */\n system?: string;\n /** Provider web-search server tool (default true — brand research). */\n webSearch?: boolean;\n /** Max model turns per run (default 10 — the workflow is multi-step). */\n maxSteps?: number;\n /** Extra skills appended after the brand skill (e.g. a chat skill). */\n skills?: Skill[];\n /** Options for the attached {@link brandSkill}. */\n brand: BrandSkillOpts;\n}\n\n/** Build the brand-director Persona: {@link brandSkill} first, extra skills\n * after, defaults per the option JSDoc above. */\nexport function createBrandPersona(opts: CreateBrandPersonaOpts): Persona {\n return {\n name: \"brand-director\",\n model: opts.model,\n system: opts.system ?? DEFAULT_BRAND_SYSTEM,\n webSearch: opts.webSearch ?? true,\n maxSteps: opts.maxSteps ?? 10,\n skills: [brandSkill(opts.brand), ...(opts.skills ?? [])],\n };\n}\n\n/** The capability flags {@link supportsBrandVision} inspects. */\nexport interface BrandVisionCapabilities {\n toolResultBlocks?: boolean;\n imageIn?: boolean;\n documentIn?: boolean;\n}\n\n/** The (structural) slice of an @odla-ai/ai ModelSpec the probe reads. */\nexport interface BrandVisionSpec {\n capabilities?: BrandVisionCapabilities;\n}\n\n/**\n * Whether a model can view assets THROUGH view_asset — i.e. take image and\n * document blocks inside tool results. Pure capabilities-metadata check\n * (`toolResultBlocks && imageIn && documentIn`), never provider names; when\n * false, hosts attach asset bytes as pre-turn input blocks instead and pass\n * `visionInToolResults: false` to the skill.\n */\nexport function supportsBrandVision(spec: BrandVisionSpec | null | undefined): boolean {\n const caps = spec?.capabilities;\n return !!(caps?.toolResultBlocks && caps.imageIn && caps.documentIn);\n}\n","// HTTP plumbing for the brand route factory (crm's http.ts contract): option\n// shapes, JSON helpers, the error → status mapping (BrandInputError → 400,\n// BrandNotFoundError → 404, anything else an OPAQUE 500), body-field\n// extractors, and the shared book loaders.\n//\n// Access parity note: routes run on the host's ADMIN db credential, which\n// bypasses odla-db rules — so the loaders re-enforce what the CEL rules would:\n// a book you are not in `memberIds` of answers 404, the same as one that does\n// not exist (a non-member cannot probe for existence).\nimport { BRAND_NS } from \"../constants\";\nimport { BrandInputError, BrandNotFoundError } from \"../errors\";\nimport type { BrandActor, BrandBook, BrandDb } from \"../types\";\n\n/** Everything {@link import(\"./index\").createBrandRoutes} needs from the host worker. */\nexport interface BrandRouteOpts {\n /** The injected odla client (a real @odla-ai/db AdminDb satisfies it). */\n db: BrandDb;\n /** Host-owned auth: resolve the request to an actor or null (→ 401). The\n * tokens routes skip this only when `publicTokens` is true. */\n authorize: (req: Request) => Promise<BrandActor | null> | BrandActor | null;\n /** Mount point. Default \"/api/brand\". */\n basePath?: string;\n /** Upload size cap in bytes (checked against `File.size`). Default 8 MiB. */\n maxUploadBytes?: number;\n /** Serve `GET /books/:id/tokens.css` and `tokens.json` without authorize —\n * compiled tokens only; every other route always authorizes. Default false. */\n publicTokens?: boolean;\n /** Injectable clock (tests). Default `Date.now`. */\n now?: () => number;\n /** Injectable id factory (tests). Default `crypto.randomUUID`. */\n newId?: () => string;\n}\n\n/** Per-request context handed to the authorized route handlers. */\nexport interface BrandRouteCtx {\n db: BrandDb;\n actor: BrandActor;\n now: () => number;\n newId: () => string;\n maxUploadBytes: number;\n}\n\n/** JSON response helper (`content-type: application/json`). */\nexport const json = (body: unknown, status = 200, headers: Record<string, string> = {}): Response =>\n new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json\", ...headers },\n });\n\n/** Map a thrown error to its response: 400 input, 404 missing, opaque 500. */\nexport const errorResponse = (error: unknown): Response => {\n if (error instanceof BrandInputError)\n return json({ error: error.message, ...(error.fields ? { fields: error.fields } : {}) }, 400);\n if (error instanceof BrandNotFoundError) return json({ error: error.message }, 404);\n return json({ error: \"internal error\" }, 500);\n};\n\n/** The uniform 405 for a known path hit with the wrong method. */\nexport const methodNotAllowed = (): Response => json({ error: \"method not allowed\" }, 405);\n\n/** Parse a JSON object body; {@link BrandInputError} (→ 400) on anything else. */\nexport async function readJson(req: Request): Promise<Record<string, unknown>> {\n let body: unknown;\n try {\n body = await req.json();\n } catch {\n throw new BrandInputError(\"invalid JSON body\");\n }\n if (typeof body !== \"object\" || body === null || Array.isArray(body))\n throw new BrandInputError(\"body must be a JSON object\");\n return body as Record<string, unknown>;\n}\n\n/** Required non-empty string body field. */\nexport function str(body: Record<string, unknown>, key: string): string {\n const value = body[key];\n if (typeof value !== \"string\" || value === \"\")\n throw new BrandInputError(`\"${key}\" must be a non-empty string`);\n return value;\n}\n\n/** Optional string body field (absent/null → undefined). */\nexport function optStr(body: Record<string, unknown>, key: string): string | undefined {\n const value = body[key];\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\") throw new BrandInputError(`\"${key}\" must be a string`);\n return value;\n}\n\n/** Optional string-array body field (absent/null → undefined). */\nexport function optStrArray(body: Record<string, unknown>, key: string): string[] | undefined {\n const value = body[key];\n if (value === undefined || value === null) return undefined;\n if (!Array.isArray(value) || value.some((v) => typeof v !== \"string\"))\n throw new BrandInputError(`\"${key}\" must be an array of strings`);\n return value as string[];\n}\n\n/** Whether `actorId` is on the book's auth roster. */\nexport function isMember(book: BrandBook, actorId: string): boolean {\n return Array.isArray(book.memberIds) && book.memberIds.includes(actorId);\n}\n\n/** Load a book by id; {@link BrandNotFoundError} (→ 404) when missing. */\nexport async function loadBook(db: BrandDb, bookId: string): Promise<BrandBook> {\n const res = await db.query({ [BRAND_NS.book]: { $: { where: { id: bookId } } } });\n const row = (res[BRAND_NS.book] ?? [])[0] as BrandBook | undefined;\n if (!row) throw new BrandNotFoundError(`brand book ${bookId}`);\n return row;\n}\n\n/** {@link loadBook}, plus the rules-parity membership gate: a non-member gets\n * the same 404 a missing book gets (see the header note). */\nexport async function loadMemberBook(db: BrandDb, bookId: string, actorId: string): Promise<BrandBook> {\n const book = await loadBook(db, bookId);\n if (!isMember(book, actorId)) throw new BrandNotFoundError(`brand book ${bookId}`);\n return book;\n}\n","// /books/:id/assets handlers — the worker-mediated side of the closed\n// `brand_asset` namespace: multipart upload → storage first, then the\n// mirroring row; list (tombstones excluded); delete = storage delete + a\n// `deletedAt` tombstone, never a row delete.\n//\n// Ordering note: EVERY input check (content type → 415, size → 413, kind /\n// title / file name → 400) runs BEFORE `storage.upload`, so a 4xx can never\n// strand an orphaned object in the file store.\nimport { ASSET_KINDS, BRAND_NS, type AssetKind } from \"../constants\";\nimport { BrandInputError, BrandNotFoundError } from \"../errors\";\nimport { createAssetOps, tombstoneAssetOps } from \"../ops/assets\";\nimport type { BrandAsset } from \"../types\";\nimport { assertAssetContentType, capString, safeFileName } from \"../validate\";\nimport { json, loadMemberBook, methodNotAllowed, type BrandRouteCtx } from \"./http\";\n\n/** Read the multipart form; 400 (as {@link BrandInputError}) on any other body. */\nasync function readForm(req: Request): Promise<FormData> {\n try {\n return await req.formData();\n } catch {\n throw new BrandInputError('expected a multipart/form-data body with a \"file\" field');\n }\n}\n\nasync function uploadAsset(ctx: BrandRouteCtx, req: Request, bookId: string): Promise<Response> {\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n const form = await readForm(req);\n const file = form.get(\"file\");\n if (!(file instanceof File)) throw new BrandInputError('\"file\" must be an uploaded file field');\n\n // 415 (unsupported type) and 413 (too large) get their own statuses; the\n // remaining input checks are plain 400s.\n let contentType: string;\n try {\n contentType = assertAssetContentType(file.type);\n } catch (error) {\n if (error instanceof BrandInputError) return json({ error: error.message }, 415);\n throw error;\n }\n if (file.size > ctx.maxUploadBytes)\n return json(\n { error: `file is ${file.size} bytes; the upload limit is ${ctx.maxUploadBytes}` },\n 413,\n );\n const kindRaw = form.get(\"kind\");\n const kind = typeof kindRaw === \"string\" && kindRaw !== \"\" ? kindRaw : \"other\";\n if (!(ASSET_KINDS as readonly string[]).includes(kind))\n throw new BrandInputError(`kind must be one of: ${ASSET_KINDS.join(\", \")}`);\n const titleRaw = form.get(\"title\");\n const title =\n typeof titleRaw === \"string\" && titleRaw !== \"\" ? capString(titleRaw, \"title\", 160) : undefined;\n\n const id = ctx.newId();\n const path = `brand/${book.id}/assets/${id}/${safeFileName(file.name)}`;\n const record = await ctx.db.storage.upload(path, file, contentType);\n await ctx.db.transact(\n createAssetOps({\n id,\n bookId: book.id,\n kind: kind as AssetKind,\n path: record.path,\n url: record.url,\n contentType,\n size: record.size,\n uploadedBy: ctx.actor.id,\n audience: book.memberIds,\n title,\n now: ctx.now(),\n }),\n { mutationId: id },\n );\n const res = await ctx.db.query({ [BRAND_NS.asset]: { $: { where: { id } } } });\n return json((res[BRAND_NS.asset] ?? [])[0], 201);\n}\n\n/**\n * `GET /books/:id/assets` — the book's live assets (tombstoned rows\n * excluded), oldest first, as `{ assets }`. `POST /books/:id/assets` —\n * multipart upload (`file`, optional `kind` default \"other\", optional\n * `title`): 415 off-allowlist type, 413 over `maxUploadBytes`, else upload to\n * `brand/{bookId}/assets/{id}/{safeFileName}` and answer 201 with the asset\n * row. Members only; other methods 405.\n */\nexport async function handleAssetsRoot(ctx: BrandRouteCtx, req: Request, bookId: string): Promise<Response> {\n if (req.method === \"GET\") {\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n const res = await ctx.db.query({\n [BRAND_NS.asset]: {\n // `deletedAt: null` matches ONLY rows without the attr — odla-db's\n // \"absence is a missing triple\" semantics — i.e. not tombstoned.\n $: { where: { bookId: book.id, deletedAt: null }, order: { createdAt: \"asc\" } },\n },\n });\n return json({ assets: res[BRAND_NS.asset] ?? [] });\n }\n if (req.method === \"POST\") return uploadAsset(ctx, req, bookId);\n return methodNotAllowed();\n}\n\n/**\n * `DELETE /books/:id/assets/:assetId` — delete the storage object, then\n * tombstone the row (`deletedAt`); answers `{ id, deletedAt }`. 404 when the\n * asset is unknown, belongs to another book, or is already tombstoned (the\n * storage object is gone — never double-delete). Other methods: 405.\n */\nexport async function handleAssetItem(\n ctx: BrandRouteCtx,\n req: Request,\n bookId: string,\n assetId: string,\n): Promise<Response> {\n if (req.method !== \"DELETE\") return methodNotAllowed();\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n const res = await ctx.db.query({\n [BRAND_NS.asset]: { $: { where: { id: assetId, bookId: book.id } } },\n });\n const asset = (res[BRAND_NS.asset] ?? [])[0] as unknown as BrandAsset | undefined;\n if (!asset || asset.deletedAt != null) throw new BrandNotFoundError(`asset ${assetId}`);\n await ctx.db.storage.delete(asset.path);\n const deletedAt = ctx.now();\n await ctx.db.transact(tombstoneAssetOps(asset.id, deletedAt));\n return json({ id: asset.id, deletedAt });\n}\n","// /books handlers: create, member-filtered list, and detail.\n//\n// List filtering note: odla-db's query where-clauses have no \"roster array\n// CONTAINS value\" operator (`$in` tests a scalar column against a candidate\n// list, the inverse), so membership on the json `memberIds` roster is not\n// expressible as a where. The handler fetches the namespace and filters in\n// code — exactly the visibility the `brand_book.view` CEL rule\n// (`auth.id in data.memberIds`) enforces for rules-scoped credentials; the\n// admin-key route path just re-applies it server-side.\nimport { BRAND_NS } from \"../constants\";\nimport { createBookOps } from \"../ops/books\";\nimport type { BrandBook } from \"../types\";\nimport {\n isMember,\n json,\n loadBook,\n loadMemberBook,\n methodNotAllowed,\n optStr,\n optStrArray,\n readJson,\n str,\n type BrandRouteCtx,\n} from \"./http\";\n\n/**\n * `GET /books` — every book whose `memberIds` roster contains the actor,\n * oldest first, as `{ books }`. `POST /books` — create a draft book owned by\n * the actor (`slug`, `name`, optional `memberIds` roster and `channelId`);\n * answers 201 with the created row. Other methods: 405.\n */\nexport async function handleBooksRoot(ctx: BrandRouteCtx, req: Request): Promise<Response> {\n if (req.method === \"GET\") {\n const res = await ctx.db.query({ [BRAND_NS.book]: { $: { order: { createdAt: \"asc\" } } } });\n const books = ((res[BRAND_NS.book] ?? []) as unknown as BrandBook[]).filter((b) =>\n isMember(b, ctx.actor.id),\n );\n return json({ books });\n }\n if (req.method === \"POST\") {\n const body = await readJson(req);\n const id = ctx.newId();\n const ops = createBookOps({\n id,\n slug: str(body, \"slug\"),\n name: str(body, \"name\"),\n ownerId: ctx.actor.id,\n memberIds: optStrArray(body, \"memberIds\") ?? [],\n channelId: optStr(body, \"channelId\"),\n now: ctx.now(),\n });\n await ctx.db.transact(ops, { mutationId: id });\n return json(await loadBook(ctx.db, id), 201);\n }\n return methodNotAllowed();\n}\n\n/** `GET /books/:id` — the book row, members only (404 otherwise, matching the\n * view rule — see http.ts). Other methods: 405. */\nexport async function handleBookItem(ctx: BrandRouteCtx, req: Request, bookId: string): Promise<Response> {\n if (req.method !== \"GET\") return methodNotAllowed();\n return json(await loadMemberBook(ctx.db, bookId, ctx.actor.id));\n}\n","// /books/:id/tokens.css + tokens.json — the consumption side of the token\n// compiler. Serves the book's cached `tokens` snapshot when present;\n// otherwise compiles on the fly from the active palette (+ the typography\n// section's content) and serves WITHOUT writing — a GET never mutates, so a\n// cache miss under crawler traffic can't fan out writes. `compile_tokens`\n// (the skill tool) is what persists the cache.\n//\n// Conditional requests: the ETag is derived from `book.updatedAt` — every\n// palette acceptance and token compile stamps it — so If-None-Match answers\n// 304 until the brand actually changes.\nimport { BRAND_NS } from \"../constants\";\nimport { BrandNotFoundError } from \"../errors\";\nimport { compileBrandTokens } from \"../tokens/compile\";\nimport { renderTokensCss } from \"../tokens/css\";\nimport type { BrandTokens } from \"../tokens/types\";\nimport type { BrandActor, BrandBook, BrandDb, BrandPalette, TypographySection } from \"../types\";\nimport { json, loadBook, loadMemberBook, methodNotAllowed } from \"./http\";\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/** The book's token maps: the cached snapshot when usable, else a fresh\n * side-effect-free compile from the active palette + typography section.\n * 404 (as {@link BrandNotFoundError}) when there is neither. */\nasync function resolveTokenMaps(\n db: BrandDb,\n book: BrandBook,\n): Promise<{ light: BrandTokens; dark: BrandTokens }> {\n const cache = book.tokens;\n if (cache && isRecord(cache.light) && isRecord(cache.dark))\n return { light: cache.light as BrandTokens, dark: cache.dark as BrandTokens };\n if (!book.activePaletteId) throw new BrandNotFoundError(`compiled tokens for brand book ${book.id}`);\n const pres = await db.query({\n [BRAND_NS.palette]: { $: { where: { id: book.activePaletteId } } },\n });\n const palette = (pres[BRAND_NS.palette] ?? [])[0] as unknown as BrandPalette | undefined;\n if (!palette) throw new BrandNotFoundError(`compiled tokens for brand book ${book.id}`);\n const sres = await db.query({\n [BRAND_NS.section]: { $: { where: { key: `${book.id}:typography` } } },\n });\n const typography = ((sres[BRAND_NS.section] ?? [])[0] as { content?: unknown } | undefined)\n ?.content as TypographySection | undefined;\n const compiled = compileBrandTokens({ swatches: palette.swatches, typography });\n return { light: compiled.light, dark: compiled.dark };\n}\n\n/**\n * Serve `GET /books/:id/tokens.css` (theme CSS via `renderTokensCss`, strong\n * `updatedAt`-derived ETag, If-None-Match → 304) or `tokens.json`\n * (`{ light, dark }`). `actor` null means the publicTokens path — no\n * membership gate; when an actor is present the member-or-404 rule applies\n * like every other route. Other methods: 405.\n */\nexport async function handleTokens(\n db: BrandDb,\n req: Request,\n bookId: string,\n which: \"tokens.css\" | \"tokens.json\",\n actor: BrandActor | null,\n): Promise<Response> {\n if (req.method !== \"GET\") return methodNotAllowed();\n const book = actor === null ? await loadBook(db, bookId) : await loadMemberBook(db, bookId, actor.id);\n const maps = await resolveTokenMaps(db, book);\n if (which === \"tokens.json\") return json({ light: maps.light, dark: maps.dark });\n const etag = `\"brand-tokens-${book.updatedAt}\"`;\n const inm = req.headers.get(\"if-none-match\");\n if (inm && inm.split(\",\").map((v) => v.trim()).includes(etag))\n return new Response(null, { status: 304, headers: { etag } });\n return new Response(renderTokensCss(maps.light, { dark: maps.dark }), {\n status: 200,\n headers: { \"content-type\": \"text/css; charset=utf-8\", etag },\n });\n}\n","// The mountable route factory (crm's createCrmRoutes contract): the host\n// worker composes it —\n// const brandRoutes = createBrandRoutes({ db, authorize, … });\n// return (await brandRoutes(request)) ?? next(request);\n// — keeping full ownership of auth (`authorize`) and the admin db key.\nimport { handleAssetItem, handleAssetsRoot } from \"./assets\";\nimport { handleBookItem, handleBooksRoot } from \"./books\";\nimport { errorResponse, json, type BrandRouteCtx, type BrandRouteOpts } from \"./http\";\nimport { handleTokens } from \"./tokens\";\n\nexport type { BrandRouteCtx, BrandRouteOpts } from \"./http\";\n\ntype TokensFile = \"tokens.css\" | \"tokens.json\";\n\n/** `/books/:id/tokens.css|json` recognizer — the only publicTokens-eligible paths. */\nconst tokensFile = (seg: string[]): TokensFile | null =>\n seg.length === 3 && seg[0] === \"books\" && (seg[2] === \"tokens.css\" || seg[2] === \"tokens.json\")\n ? (seg[2] as TokensFile)\n : null;\n\nasync function route(ctx: BrandRouteCtx, req: Request, seg: string[]): Promise<Response | null> {\n const [head, id, sub, subId] = seg;\n if (head !== \"books\") return null;\n if (seg.length === 1) return handleBooksRoot(ctx, req);\n if (seg.length === 2) return handleBookItem(ctx, req, id!);\n if (sub === \"assets\") {\n if (seg.length === 3) return handleAssetsRoot(ctx, req, id!);\n if (seg.length === 4) return handleAssetItem(ctx, req, id!, subId!);\n return null;\n }\n const file = tokensFile(seg);\n if (file) return handleTokens(ctx.db, req, id!, file, ctx.actor);\n return null;\n}\n\n/**\n * Build the brand fetch handler. Returns `null` for requests outside\n * `basePath` (default `/api/brand`) so the host worker falls through to its\n * own routes; inside it, every route requires `authorize` to resolve an\n * actor (401 otherwise) EXCEPT the two tokens routes when `publicTokens` is\n * true — compiled tokens are the one intentionally publishable surface.\n * Domain errors map to 400/404 JSON; anything unexpected is an opaque 500.\n */\nexport function createBrandRoutes(options: BrandRouteOpts): (req: Request) => Promise<Response | null> {\n const basePath = options.basePath ?? \"/api/brand\";\n const publicTokens = options.publicTokens === true;\n const base = {\n db: options.db,\n now: options.now ?? Date.now,\n newId: options.newId ?? (() => crypto.randomUUID()),\n maxUploadBytes: options.maxUploadBytes ?? 8 * 1024 * 1024,\n };\n return async (req: Request): Promise<Response | null> => {\n const url = new URL(req.url);\n if (url.pathname !== basePath && !url.pathname.startsWith(`${basePath}/`)) return null;\n const seg = url.pathname.slice(basePath.length).split(\"/\").filter(Boolean);\n try {\n const file = tokensFile(seg);\n if (publicTokens && file) return await handleTokens(base.db, req, seg[1]!, file, null);\n const actor = await options.authorize(req);\n if (!actor) return json({ error: \"unauthorized\" }, 401);\n return (await route({ ...base, actor }, req, seg)) ?? json({ error: \"not found\" }, 404);\n } catch (error) {\n return errorResponse(error);\n }\n };\n}\n","// Commit-trigger config brand installs into odla-db (POST to\n// `/app/:id/admin/triggers`), mirroring @odla-ai/chat's botTrigger: the\n// @odla/server commit hook fires on matching human-authored chat-message\n// writes and dispatches to the host's agent worker with `skill: \"brand\"`.\n// Two deployment modes, both this one builder:\n// - global mention-gated: one bot, `mention: \"@brand\"`, no `channels`;\n// - per-book channel-scoped: `channels: [book.channelId]`, no mention.\n\n/** The odla-db namespace chat messages live in.\n * PROVENANCE: @odla-ai/chat `CHAT_NS.message` (packages/chat/src/constants.ts)\n * — duplicated as a local const because this package is zero-dep and the wire\n * value is a stable contract, not an implementation detail. */\nexport const CHAT_MESSAGE_NS = \"chat_message\";\n\n/** Matches @odla/server's `Trigger` (the exact JSON POSTed to\n * `/app/:id/admin/triggers`) — the same wire shape as chat's `ChatTrigger`. */\nexport interface BrandTrigger {\n id: string;\n watch: { ns: string; on: \"create\" | \"update\" };\n when?: string;\n runAs: { agentId: string; persona: string };\n skill: string;\n maxDepth?: number;\n channels?: string[];\n validate?: string;\n}\n\n/** Options for {@link brandBotTrigger}. */\nexport interface BrandBotTriggerOpts {\n /** Trigger id (unique per app). */\n id: string;\n /** The bot's agent id — must be in each target book's `memberIds` roster. */\n agentId: string;\n /** Persona name the dispatching worker runs. */\n persona: string;\n /** Fire only on messages mentioning this handle, e.g. \"@brand\". */\n mention?: string;\n /** Extra CEL over the new message row, ANDed with the built-in guards. */\n when?: string;\n /** Restrict to specific channel ids (the per-book mode). */\n channels?: string[];\n /** Watched write kind (default \"create\"). */\n on?: \"create\" | \"update\";\n}\n\n/** Escape a value for embedding inside a CEL double-quoted string literal —\n * copied verbatim from @odla-ai/chat (packages/chat/src/triggers.ts):\n * `mention` is matched as literal text, so a stray quote or backslash must\n * not break out of the literal into CEL syntax. */\nconst celString = (value: string): string => value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n\n/**\n * Build a trigger that runs the brand agent on human chat messages\n * (optionally @-mentions, optionally channel-scoped): chat's `botTrigger`\n * shape with `skill: \"brand\"` and `maxDepth: 1` so a bot reply can never\n * re-trigger a bot.\n */\nexport function brandBotTrigger(opts: BrandBotTriggerOpts): BrandTrigger {\n const clauses = ['data.authorKind == \"human\"'];\n if (opts.mention) clauses.push(`data.body.contains(\"${celString(opts.mention)}\")`);\n // `when` is documented as caller-authored CEL, so it is intentionally not escaped.\n if (opts.when) clauses.push(`(${opts.when})`);\n return {\n id: opts.id,\n watch: { ns: CHAT_MESSAGE_NS, on: opts.on ?? \"create\" },\n when: clauses.join(\" && \"),\n runAs: { agentId: opts.agentId, persona: opts.persona },\n skill: \"brand\",\n maxDepth: 1,\n ...(opts.channels ? { channels: opts.channels } : {}),\n };\n}\n","// Dispatch: what a host agent worker does when a brandBotTrigger fires.\n// The envelope mirrors chat-agent's DispatchBody STRUCTURALLY (see\n// packages/chat-agent/src/dispatch.ts) without importing it — this package is\n// zero-dep and the wire shape is the odla-db commit hook's contract, not\n// chat-agent's. The pure helpers (parse / book lookup / input assembly) are\n// I/O-light and unit-testable; dispatchBrandTurn wires them into one turn of\n// the injected runAgent.\nimport type { AgentRunInput, ImageBlock, Inference, OracleContentBlock, Persona, Skill } from \"@odla-ai/ai\";\nimport { BRAND_NS } from \"./constants\";\nimport { BrandNotFoundError } from \"./errors\";\nimport { createBrandPersona, supportsBrandVision, type BrandVisionSpec } from \"./skill/persona\";\nimport type { BrandSkillSelf } from \"./skill/skill\";\nimport { CHAT_MESSAGE_NS } from \"./triggers\";\nimport type { BrandAsset, BrandBook, BrandDb } from \"./types\";\n\n/** The dispatch envelope odla-db's commit hook POSTs when a trigger fires —\n * the same wire shape chat-agent consumes (see the header provenance note). */\nexport interface BrandDispatchBody {\n v: number;\n appId: string;\n trigger: { id: string; skill: string; runAs: { agentId: string; persona: string }; maxDepth?: number };\n event: { ns: string; id: string; row: Record<string, unknown> };\n}\n\n/**\n * Validate an untrusted dispatch body; null if malformed. SHAPE-only,\n * mirroring chat-agent's parseDispatch: it does NOT gate on `trigger.skill` —\n * routing on skill is the HOST's job (a worker serving several skills checks\n * `body.trigger.skill === \"brand\"` before calling {@link dispatchBrandTurn}),\n * so an absent skill parses as `\"\"`, never silently defaulted to \"brand\".\n */\nexport function parseBrandDispatch(raw: unknown): BrandDispatchBody | null {\n if (!raw || typeof raw !== \"object\") return null;\n const b = raw as Record<string, unknown>;\n const t = b.trigger as { runAs?: { agentId?: unknown; persona?: unknown }; id?: unknown; skill?: unknown; maxDepth?: unknown } | undefined;\n const e = b.event as { ns?: unknown; id?: unknown; row?: unknown } | undefined;\n if (typeof b.appId !== \"string\" || !b.appId) return null;\n if (!t || typeof t.runAs?.agentId !== \"string\" || typeof t.runAs?.persona !== \"string\") return null;\n if (!e || typeof e.id !== \"string\" || !e.row || typeof e.row !== \"object\") return null;\n return {\n v: typeof b.v === \"number\" ? b.v : 1,\n appId: b.appId,\n trigger: {\n id: typeof t.id === \"string\" ? t.id : \"\",\n skill: typeof t.skill === \"string\" ? t.skill : \"\",\n runAs: { agentId: t.runAs.agentId, persona: t.runAs.persona },\n ...(typeof t.maxDepth === \"number\" ? { maxDepth: t.maxDepth } : {}),\n },\n event: { ns: typeof e.ns === \"string\" ? e.ns : CHAT_MESSAGE_NS, id: e.id, row: e.row as Record<string, unknown> },\n };\n}\n\n/** The brand book bound to a chat channel (`brand_book.channelId`), or null\n * when the channel id is empty or no book claims it. */\nexport async function bookForChannel(db: BrandDb, channelId: string): Promise<BrandBook | null> {\n if (!channelId) return null;\n const res = await db.query({ [BRAND_NS.book]: { $: { where: { channelId } } } });\n return ((res[BRAND_NS.book] ?? [])[0] as BrandBook | undefined) ?? null;\n}\n\n/**\n * The agent-turn input for a dispatched message: a brand-flavored prompt\n * (mirrors chat-agent's `inputFor` tone, steering into the brand workflow),\n * and — when pre-turn `attachments` are supplied (the no-vision-in-tool-\n * results path) — an explicit block array with the images BEFORE the text.\n */\nexport function brandInputFor(\n body: BrandDispatchBody,\n attachments?: ImageBlock[],\n): string | OracleContentBlock[] {\n const row = body.event.row;\n const prompt =\n `A new message arrived in this brand book's channel from ${String(row.authorId ?? \"someone\")}: ` +\n `\"${String(row.body ?? \"\")}\". Ground yourself first (read_brand_book, list_assets), then move ` +\n \"the brand work forward: study the material, justify colors with the math tools, and park \" +\n \"palette ideas as proposals — a human must explicitly approve before you resolve or compile. \" +\n \"If you reply in chat, keep it concise.\";\n return attachments?.length ? [...attachments, { type: \"text\", text: prompt }] : prompt;\n}\n\n/** Image content types eligible for pre-turn attachment (ImageBlock media). */\nconst PRETURN_IMAGE_TYPES: ReadonlySet<string> = new Set([\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n]);\n\n/** Resolve the row's `assetIds` to URL-source ImageBlocks: live image assets\n * only (tombstoned, unknown, and non-image assets — pdf, svg — are skipped),\n * relative asset urls absolutized against `fileBaseUrl` (asset-tools' join). */\nasync function assetBlocksFor(db: BrandDb, fileBaseUrl: string, raw: unknown): Promise<ImageBlock[]> {\n if (!Array.isArray(raw)) return [];\n const ids = raw.filter((v): v is string => typeof v === \"string\");\n if (ids.length === 0) return [];\n const res = await db.query({ [BRAND_NS.asset]: { $: { where: { id: { $in: ids } } } } });\n const byId = new Map(((res[BRAND_NS.asset] ?? []) as unknown as BrandAsset[]).map((a) => [a.id, a]));\n const blocks: ImageBlock[] = [];\n for (const id of ids) {\n const asset = byId.get(id);\n if (!asset || asset.deletedAt != null || !PRETURN_IMAGE_TYPES.has(asset.contentType)) continue;\n const url = asset.url.startsWith(\"http\") ? asset.url : fileBaseUrl + asset.url;\n blocks.push({ type: \"image\", source: { type: \"url\", url } });\n }\n return blocks;\n}\n\n/** Everything {@link dispatchBrandTurn} needs from the host worker. The\n * @odla-ai/ai pieces (`inference`, `runAgent`) are injected so this module\n * keeps the package's types-only relationship with the peer. */\nexport interface BrandDispatchDeps {\n /** The injected odla client (a real @odla-ai/db AdminDb satisfies it). */\n db: BrandDb;\n /** The @odla-ai/ai inference facade the turn runs on. */\n inference: Inference;\n /** Canonical model id for the persona. */\n model: string;\n /** The agent loop — pass @odla-ai/ai's `runAgent`. */\n runAgent: (inference: Inference, persona: Persona, input: AgentRunInput) => Promise<{ finalText: string }>;\n /** Origin prefixed onto relative asset urls (skill + pre-turn attachments). */\n fileBaseUrl: string;\n /** Optional stable id factory for durable whole-turn retries. */\n newId?: () => string;\n /** Optional chat-skill factory (e.g. wrapping @odla-ai/chat's chatSkill) so\n * the bot can reply in the triggering channel. */\n chatSkillFor?: (channelId: string, self: BrandSkillSelf) => Skill;\n /** Model catalog slice (model id → capability spec) for the vision probe;\n * an absent catalog or unknown model fails safe to the pre-turn path. */\n catalog?: Record<string, BrandVisionSpec>;\n}\n\n/**\n * Run one brand-agent turn for a dispatched chat message: resolve the book\n * via the row's `channelId` (throws {@link BrandNotFoundError} when no book\n * claims the channel), probe `supportsBrandVision(catalog[model])`, build the\n * persona (brand skill + optional chat skill, bot identity from\n * `trigger.runAs`), and run the loop. When the model can NOT take blocks in\n * tool results, assets are attached PRE-TURN as URL image blocks — v1 keeps\n * detection simple: only when the message row carries an `assetIds` array\n * (no body-text scraping), and only live image assets.\n */\nexport async function dispatchBrandTurn(\n deps: BrandDispatchDeps,\n body: BrandDispatchBody,\n): Promise<{ finalText: string }> {\n const channelId = String(body.event.row.channelId ?? \"\");\n const book = await bookForChannel(deps.db, channelId);\n if (!book) throw new BrandNotFoundError(`brand book for channel ${channelId || \"(missing channelId)\"}`);\n const visionInToolResults = supportsBrandVision(deps.catalog?.[deps.model]);\n const self: BrandSkillSelf = {\n selfId: body.trigger.runAs.agentId,\n kind: \"bot\",\n displayName: body.trigger.runAs.persona,\n };\n const persona = createBrandPersona({\n model: deps.model,\n brand: {\n db: deps.db,\n bookId: book.id,\n self,\n fileBaseUrl: deps.fileBaseUrl,\n visionInToolResults,\n ...(deps.newId ? { newId: deps.newId } : {}),\n },\n skills: deps.chatSkillFor ? [deps.chatSkillFor(channelId, self)] : [],\n });\n const attachments = visionInToolResults\n ? []\n : await assetBlocksFor(deps.db, deps.fileBaseUrl, body.event.row.assetIds);\n const run = await deps.runAgent(deps.inference, persona, { input: brandInputFor(body, attachments) });\n return { finalText: run.finalText };\n}\n","// The integration descriptor: documentation-as-data for the brand capability,\n// following the crm/chat pattern — what installing @odla-ai/brand into an app\n// means (schema, deny-all rules, per-bot triggers, worker mount), described\n// but not performed. The base shapes are inlined so the zero-dependency\n// package does not depend on the CLI; the CLI consumes descriptors\n// structurally from odla.config.mjs.\nimport { BRAND_SCHEMA, type SerializedSchema } from \"./schema\";\nimport { brandRules, type BrandRules } from \"./rules\";\nimport type { BrandTrigger } from \"./triggers\";\n\n/** One owner-facing setting the integration exposes (crm's shape). */\nexport interface IntegrationSetting {\n key: string;\n description: string;\n public: boolean;\n pattern?: string;\n perEnv: boolean;\n source: string;\n}\n\n/** One vault secret the integration needs (brand core needs none). */\nexport interface IntegrationSecret {\n key: string;\n description: string;\n pattern?: string;\n vault: boolean;\n}\n\n/** Human / CLI / doctor provisioning steps, documentation-as-data. */\nexport interface IntegrationProvision {\n human: string[];\n cli: string[];\n doctor: string[];\n}\n\n/** Unauthenticated route check run by `odla-ai smoke`. */\nexport interface BrandIntegrationProbe {\n path: string;\n expectedStatus: number;\n}\n\n/** The brand descriptor shape: the shared base plus the schema + rules\n * provisioning installs and the (app-supplied) bot triggers. */\nexport interface BrandIntegrationDescriptor {\n id: string;\n title: string;\n npm: string;\n settings: IntegrationSetting[];\n secrets: IntegrationSecret[];\n /** The schema to POST at /app/:id/schema. */\n schema: SerializedSchema;\n /** The default-deny rules to install at /app/:id/admin/rules (merged with existing). */\n rules: BrandRules;\n /** Commit triggers to register at /app/:id/admin/triggers (per-bot; app-supplied). */\n triggers: BrandTrigger[];\n probes?: BrandIntegrationProbe[];\n provision: IntegrationProvision;\n}\n\n/**\n * The static documentation descriptor for @odla-ai/brand. Data only: it\n * describes what installing the brand capability means — push\n * {@link BRAND_SCHEMA}, install the default-deny `brandRules()`, register\n * `brandBotTrigger`s (app-supplied, in either the global mention-gated or the\n * per-book channel-scoped mode), mount `createBrandRoutes` in the app worker\n * — and performs none of it. Use {@link createBrandIntegration} in\n * `odla.config.mjs` to add the live route probe the CLI can execute.\n */\nexport const brandIntegration: BrandIntegrationDescriptor = {\n id: \"brand\",\n title: \"Brand books (assets, palettes, proposals, design tokens)\",\n npm: \"@odla-ai/brand\",\n settings: [\n {\n key: \"basePath\",\n description: 'Route mount point the app worker serves brand under. Default \"/api/brand\".',\n public: true,\n perEnv: false,\n source: \"createBrandRoutes({ basePath }) in the app worker\",\n },\n {\n key: \"publicTokens\",\n description:\n \"Serve GET /books/:id/tokens.css and tokens.json without authorization (compiled tokens \" +\n \"only — books and assets always authorize). Default false.\",\n public: true,\n perEnv: false,\n source: \"createBrandRoutes({ publicTokens }) in the app worker\",\n },\n ],\n secrets: [],\n schema: BRAND_SCHEMA,\n rules: brandRules(),\n triggers: [],\n provision: {\n human: [\n \"Choose the trigger mode: one global mention-gated bot (brandBotTrigger({ mention: \\\"@brand\\\" }), no channels) or per-book channel-scoped bots (channels: [book.channelId], no mention).\",\n \"Pick the bot's model; when supportsBrandVision(catalog[model]) is false, dispatch attaches assets pre-turn instead of inside tool results.\",\n \"Decide whether compiled tokens are public (publicTokens serves tokens.css/tokens.json unauthenticated).\",\n ],\n cli: [\n \"POST BRAND_SCHEMA to /app/:id/schema.\",\n \"Install brandRules() at /app/:id/admin/rules (merged with the app's existing rules).\",\n \"Register a brandBotTrigger(...) per bot at /app/:id/admin/triggers — global mention-gated, or channel-scoped per book.\",\n \"Seed the bot's agent id into each brand_book.memberIds roster (audienceFanoutOps covers existing child rows).\",\n \"Provision the bot's AI provider secret (via @odla-ai/ai) and the worker's admin odla-db credential.\",\n ],\n doctor: [\n \"All five brand_* namespaces have rules installed (brand_asset fully closed — worker-mediated only).\",\n \"brand_book.id/slug, brand_section.key, and the other mirrored id attrs are unique.\",\n \"Each registered trigger's agent id is present in its target books' memberIds rosters.\",\n \"Books with channelId set point at real chat channels when @odla-ai/chat is installed.\",\n ],\n },\n};\n\n/** Options for {@link createBrandIntegration}. */\nexport interface CreateBrandIntegrationOptions {\n /** Worker mount path; defaults to `/api/brand`. */\n basePath?: string;\n /** Document (and probe-plan for) unauthenticated tokens routes. */\n publicTokens?: boolean;\n /** The global bot's mention handle — folded into the CLI trigger step. */\n mention?: string;\n}\n\n/**\n * Build the project-specific, CLI-consumable brand integration descriptor:\n * {@link brandIntegration} plus a live smoke probe (an anonymous GET of\n * `<basePath>/books` must answer 401 — routes mounted, authorize enforced,\n * exactly crm's probe idiom) and, when `mention`/`publicTokens` are given,\n * concrete CLI steps carrying the app's actual values. Mounting\n * `createBrandRoutes` remains app-owned source work.\n */\nexport function createBrandIntegration(\n options: CreateBrandIntegrationOptions = {},\n): BrandIntegrationDescriptor {\n const basePath = options.basePath ?? \"/api/brand\";\n if (!/^\\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/.test(basePath) || basePath.endsWith(\"/\")) {\n throw new Error(\"createBrandIntegration: basePath must be an absolute path without a trailing slash\");\n }\n const cli = [...brandIntegration.provision.cli];\n if (options.mention !== undefined)\n cli.push(`Gate the global bot on mentions: brandBotTrigger({ mention: ${JSON.stringify(options.mention)}, ... }).`);\n if (options.publicTokens === true)\n cli.push(`Mount createBrandRoutes({ publicTokens: true }) so ${basePath}/books/:id/tokens.css serves unauthenticated.`);\n return {\n ...brandIntegration,\n provision: { ...brandIntegration.provision, cli },\n probes: [{ path: `${basePath}/books`, expectedStatus: 401 }],\n };\n}\n"],"mappings":"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","names":["a","isRecord","a"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/agent-profile.ts","../src/errors.ts","../src/deps.ts","../src/schema.ts","../src/rules.ts","../src/validate.ts","../src/review-json.ts","../src/review.ts","../src/discussion-reference.ts","../src/ops/books.ts","../src/ops/sections.ts","../src/ops/palettes.ts","../src/ops/assets.ts","../src/skill/asset-tools.ts","../src/skill/source-asset.ts","../src/skill/book-tools.ts","../src/skill/palette-tools.ts","../src/skill/read-tools.ts","../src/skill/skill.ts","../src/skill/persona.ts","../src/routes/asset-query.ts","../src/routes/http.ts","../src/routes/asset-upload.ts","../src/routes/assets.ts","../src/routes/books.ts","../src/routes/proposal-input.ts","../src/routes/proposal-effects.ts","../src/routes/proposal-resolution-receipts.ts","../src/routes/proposal-dependencies.ts","../src/routes/proposal-state.ts","../src/routes/proposals.ts","../src/routes/tokens.ts","../src/routes/discussion-references.ts","../src/routes/index.ts","../src/dispatch-assets.ts","../src/triggers.ts","../src/dispatch.ts","../src/descriptor.ts"],"sourcesContent":["// Namespaces + closed vocabularies for @odla-ai/brand. One brand book is a\n// row-tree across six namespaces: the book (auth roster + compiled tokens),\n// its sections (one per kind, natural-keyed `${bookId}:${kind}`), palettes\n// (the atomic proposal/approval unit), proposals (human-gated agent output),\n// assets (worker-mediated uploads mirroring real R2 objects), and immutable\n// approval receipts recording the exact human-reviewed action.\n\n/** The odla-db namespaces @odla-ai/brand installs and writes. */\nexport const BRAND_NS = {\n book: \"brand_book\",\n section: \"brand_section\",\n palette: \"brand_palette\",\n proposal: \"brand_proposal\",\n approvalReceipt: \"brand_approval_receipt\",\n asset: \"brand_asset\",\n} as const;\n\n/** Brand-book lifecycle: authored → adopted → retired (delete is owner-only). */\nexport const BOOK_STATUSES = [\"draft\", \"active\", \"archived\"] as const;\n/** Where a brand book stands in its lifecycle. */\nexport type BookStatus = (typeof BOOK_STATUSES)[number];\n\n/** The section kinds a book carries — one row per kind, upserted by natural key. */\nexport const SECTION_KINDS = [\"palette\", \"typography\", \"voice\", \"logo\", \"imagery\"] as const;\n/** Which facet of the brand a section documents. */\nexport type SectionKind = (typeof SECTION_KINDS)[number];\n\n/** Section review state: agent drafts, a human approves. */\nexport const SECTION_STATUSES = [\"draft\", \"approved\"] as const;\n/** Whether a section's content has human sign-off. */\nexport type SectionStatus = (typeof SECTION_STATUSES)[number];\n\n/** Palette lifecycle — palettes are never row-deleted, only archived. */\nexport const PALETTE_STATUSES = [\"active\", \"archived\"] as const;\n/** Whether a palette is the live one or a retired predecessor. */\nexport type PaletteStatus = (typeof PALETTE_STATUSES)[number];\n\n/** How a palette came to be: pulled from an asset, derived from a seed color,\n * or entered by hand. */\nexport const PALETTE_SOURCES = [\"extracted\", \"derived\", \"manual\"] as const;\n/** Provenance of a palette's swatches. */\nexport type PaletteSource = (typeof PALETTE_SOURCES)[number];\n\n/** Every mutable brand facet uses the same proposal/approval contract. */\nexport const PROPOSAL_KINDS = SECTION_KINDS;\n/** Which brand facet a proposal targets. */\nexport type ProposalKind = (typeof PROPOSAL_KINDS)[number];\n\n/** Proposal lifecycle: open until a HUMAN accepts/rejects it (or a newer\n * proposal supersedes it) — agents never resolve their own proposals. */\nexport const PROPOSAL_STATUSES = [\"open\", \"accepted\", \"rejected\", \"superseded\"] as const;\n/** Where a proposal stands in the human-gated review flow. */\nexport type ProposalStatus = (typeof PROPOSAL_STATUSES)[number];\n\n/** What kind of upload an asset row records. */\nexport const ASSET_KINDS = [\"logo\", \"wordmark\", \"inspiration\", \"document\", \"other\"] as const;\n/** The declared purpose of an uploaded asset. */\nexport type AssetKind = (typeof ASSET_KINDS)[number];\n\n/** Every swatch role a palette may assign. `chart` may repeat (a series);\n * `custom` is the escape hatch for roles the token compiler doesn't map. */\nexport const SWATCH_ROLES = [\n \"primary\",\n \"secondary\",\n \"highlight\",\n \"bg\",\n \"surface\",\n \"text\",\n \"neutral\",\n \"good\",\n \"warn\",\n \"danger\",\n \"chart\",\n \"custom\",\n] as const;\n","/** Canonical least-privilege runtime profile for a Brand collaborator agent. */\nexport interface BrandAgentProfile {\n version: 1;\n projectCapabilities: readonly [\"brand.read\", \"brand.edit\"];\n semanticOperations: readonly [\n \"brand.proposal.create\",\n \"brand.asset.analysis.record\",\n \"brand.asset.content.read\",\n ];\n rawBrandWrites: false;\n rawFileOperations: false;\n approval: {\n principalKind: \"human\";\n projectCapability: \"brand.approve\";\n capability: \"brand.proposal.resolve\";\n exactAction: true;\n };\n}\n\n/** Install-time contract: agents use semantic Brand operations; only a direct\n * human may consume exact approval authority for a reviewed proposal. */\nexport const BRAND_AGENT_PROFILE: BrandAgentProfile = {\n version: 1,\n projectCapabilities: [\"brand.read\", \"brand.edit\"],\n semanticOperations: [\n \"brand.proposal.create\",\n \"brand.asset.analysis.record\",\n \"brand.asset.content.read\",\n ],\n rawBrandWrites: false,\n rawFileOperations: false,\n approval: {\n principalKind: \"human\",\n projectCapability: \"brand.approve\",\n capability: \"brand.proposal.resolve\",\n exactAction: true,\n },\n};\n","/** Caller-fault error (bad hex, oversized payload, blocked transition…) — the\n * route layer maps it to a 400. `fields` carries per-field messages when the\n * failure came from input validation. */\nexport class BrandInputError extends Error {\n readonly fields?: Record<string, string>;\n constructor(message: string, fields?: Record<string, string>) {\n super(message);\n this.name = \"BrandInputError\";\n this.fields = fields;\n }\n}\n\n/** Missing entity — the route layer maps it to a 404. */\nexport class BrandNotFoundError extends Error {\n constructor(what: string) {\n super(`${what} not found`);\n this.name = \"BrandNotFoundError\";\n }\n}\n\n/** A once-valid central authority/resource is permanently unavailable. */\nexport class BrandGoneError extends Error {\n constructor(message = \"brand authority or resource is no longer available\") {\n super(message);\n this.name = \"BrandGoneError\";\n }\n}\n\n/** Authenticated principal lacks the required principal kind/capability. */\nexport class BrandForbiddenError extends Error {\n constructor(message = \"forbidden\") {\n super(message);\n this.name = \"BrandForbiddenError\";\n }\n}\n\n/** Reviewed state or an idempotent action no longer matches current state. */\nexport class BrandConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BrandConflictError\";\n }\n}\n\n/**\n * A proposal authority use was consumed, but the local guarded Brand write\n * lost its compare-and-swap race. Clients must preserve the reviewed draft but\n * rotate their idempotency key before a fresh human decision attempt.\n */\nexport class BrandReviewStateChangedError extends BrandConflictError {\n readonly code = \"brand_review_state_changed\";\n\n constructor(\n message = \"proposal or live brand dependencies changed; review and approve again\",\n ) {\n super(message);\n this.name = \"BrandReviewStateChangedError\";\n }\n}\n","// The dependency bundle brand operations take. `now`/`newId` are injectable\n// so tests can pin time and ids and assert exact written attrs; `fetchBytes`\n// is the one network seam (asset bytes for vision), injectable so tests and\n// service-binding hosts never touch the public internet.\nimport type { BrandDb } from \"./types\";\n\n/** What `fetchBytes` resolves to: raw bytes plus the served content type. */\nexport interface BrandFetchedBytes {\n bytes: Uint8Array;\n contentType: string;\n}\n\n/** What every brand operation needs: the injected db, plus test overrides. */\nexport interface BrandDeps {\n db: BrandDb;\n /** Clock override (default `Date.now`). */\n now?: () => number;\n /** Id factory override (default `crypto.randomUUID`). */\n newId?: () => string;\n /** Asset-byte fetcher override (default: global `fetch`). */\n fetchBytes?: (url: string) => Promise<BrandFetchedBytes>;\n}\n\n/** {@link BrandDeps} with the injectable defaults filled in. */\nexport interface ResolvedBrandDeps {\n db: BrandDb;\n now: () => number;\n newId: () => string;\n fetchBytes: (url: string) => Promise<BrandFetchedBytes>;\n}\n\nasync function defaultFetchBytes(url: string): Promise<BrandFetchedBytes> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`asset fetch failed: ${res.status} for ${url}`);\n return {\n bytes: new Uint8Array(await res.arrayBuffer()),\n contentType: res.headers.get(\"content-type\") ?? \"application/octet-stream\",\n };\n}\n\n/** Fill the injectable defaults. */\nexport function resolveDeps(deps: BrandDeps): ResolvedBrandDeps {\n return {\n db: deps.db,\n now: deps.now ?? Date.now,\n newId: deps.newId ?? (() => crypto.randomUUID()),\n fetchBytes: deps.fetchBytes ?? defaultFetchBytes,\n };\n}\n","// The odla-db schema @odla-ai/brand installs (POST to `/app/:id/schema` as\n// `{ schema: BRAND_SCHEMA }`). Ships pre-serialized (the wire shape) so\n// provisioning needs no schema-builder dependency, mirroring @odla-ai/chat\n// and @odla-ai/crm. The serialized types are inlined so the package has zero\n// deps.\n//\n// Design notes (grounded in the odla-db engine):\n// - Swatches are json ON `brand_palette`, NOT their own namespace: the\n// palette is the atomic proposal/approval unit — a human accepts or rejects\n// a palette whole, and swatches are never queried across palettes.\n// - Every child has a schema link to its book. CEL reads membership from the\n// CURRENT `book.memberIds` via ref(), so roster changes never require an\n// eventually-consistent audience fan-out. Proposal audience remains frozen\n// review provenance, not authorization state.\n// - Entity ids are not attributes in odla-db (`where: { id }` matches\n// nothing), so id-addressed rows mirror their id as a unique attr — the\n// crm pattern.\nimport { BRAND_NS } from \"./constants\";\n\n/** Wire-shape attribute value kinds odla-db stores. */\nexport type AttrType = \"string\" | \"number\" | \"boolean\" | \"date\" | \"json\";\n/** One serialized attribute: its type and index/uniqueness flags. */\nexport interface SerializedAttr {\n type: AttrType;\n unique: boolean;\n indexed: boolean;\n optional: boolean;\n}\n/** One serialized namespace: its attribute map. */\nexport interface SerializedEntity {\n attrs: Record<string, SerializedAttr>;\n}\n/** One end of a serialized schema link. */\nexport interface SerializedLinkEnd {\n on: string;\n has: \"one\" | \"many\";\n label: string;\n}\n/** A serialized schema link used for current-book authorization. */\nexport interface SerializedLink {\n forward: SerializedLinkEnd;\n reverse: SerializedLinkEnd;\n}\n/** The wire-shape schema POSTed to `/app/:id/schema`. */\nexport interface SerializedSchema {\n entities: Record<string, SerializedEntity>;\n links: Record<string, SerializedLink>;\n}\n\ntype Opt = Partial<Omit<SerializedAttr, \"type\">>;\nconst a = (type: AttrType, o: Opt = {}): SerializedAttr => ({\n type,\n unique: false,\n indexed: false,\n optional: false,\n ...o,\n});\nconst uniq = (type: AttrType): SerializedAttr => a(type, { unique: true, indexed: true });\nconst idx = (type: AttrType, optional = false): SerializedAttr => a(type, { indexed: true, optional });\nconst opt = (type: AttrType): SerializedAttr => a(type, { optional: true });\n\n/**\n * The pre-serialized (wire-shape) odla-db schema for the six brand\n * namespaces; POST it to `/app/:id/schema` as `{ schema: BRAND_SCHEMA }`.\n * Natural keys (`book.slug`, `section.key`) make provisioning and section\n * upserts idempotent; mirrored `id` attrs make rows addressable by\n * `where: { id }`.\n */\nexport const BRAND_SCHEMA: SerializedSchema = {\n entities: {\n [BRAND_NS.book]: {\n attrs: {\n id: uniq(\"string\"),\n version: a(\"number\"),\n slug: uniq(\"string\"),\n name: idx(\"string\"),\n status: idx(\"string\"), // draft | active | archived\n ownerId: idx(\"string\"),\n createdAuthorityRef: idx(\"string\"),\n rosterAuthorityRef: opt(\"string\"),\n memberIds: a(\"json\"), // the auth roster, incl. the bot agent id\n channelId: a(\"string\", { unique: true, indexed: true, optional: true }),\n activePaletteId: opt(\"string\"),\n activationRevision: a(\"number\"),\n tokens: opt(\"json\"), // maps + complete palette/typography receipt provenance\n summary: opt(\"string\"),\n createdAt: idx(\"date\"),\n updatedAt: idx(\"date\"),\n },\n },\n [BRAND_NS.section]: {\n attrs: {\n key: uniq(\"string\"), // `${bookId}:${kind}` — one section per kind\n bookId: idx(\"string\"),\n kind: idx(\"string\"), // palette | typography | voice | logo | imagery\n status: idx(\"string\"), // draft | approved\n content: a(\"json\"),\n audience: a(\"json\"),\n updatedBy: a(\"string\"),\n updatedAt: idx(\"date\"),\n approvalReceiptId: opt(\"string\"),\n approvalActionDigest: opt(\"string\"),\n },\n },\n [BRAND_NS.palette]: {\n attrs: {\n id: uniq(\"string\"),\n bookId: idx(\"string\"),\n name: a(\"string\"),\n status: idx(\"string\"), // active | archived\n swatches: a(\"json\"), // Swatch[] — see the header design note\n seedHex: opt(\"string\"),\n source: a(\"string\"), // extracted | derived | manual\n rationale: opt(\"string\"),\n proposalId: idx(\"string\"),\n approvalReceiptId: a(\"string\"),\n approvalActionDigest: a(\"string\"),\n audience: a(\"json\"),\n createdAt: idx(\"date\"),\n updatedAt: idx(\"date\"),\n },\n },\n [BRAND_NS.proposal]: {\n attrs: {\n id: uniq(\"string\"),\n bookId: idx(\"string\"),\n kind: idx(\"string\"), // palette | typography | voice | logo\n status: idx(\"string\"), // open | accepted | rejected | superseded\n payload: a(\"json\"),\n rationale: a(\"string\"),\n provenance: a(\"json\"), // exact source asset/message/turn ids (nullable asset)\n reviewDigest: idx(\"string\"),\n audience: a(\"json\"),\n createdBy: a(\"string\"),\n createdAuthorityRef: a(\"string\"),\n createdAt: idx(\"date\"),\n resolvedBy: opt(\"string\"),\n resolvedAt: opt(\"date\"),\n resolutionNote: opt(\"string\"),\n approvedBy: opt(\"string\"),\n appliedBy: opt(\"string\"),\n resolutionReceiptId: opt(\"string\"),\n resolutionActionDigest: opt(\"string\"),\n },\n },\n [BRAND_NS.approvalReceipt]: {\n attrs: {\n id: uniq(\"string\"),\n version: a(\"number\"),\n mutationKey: uniq(\"string\"),\n bookId: idx(\"string\"),\n proposalId: idx(\"string\"),\n resolution: idx(\"string\"), // accepted | rejected\n paletteId: opt(\"string\"),\n resolutionNote: opt(\"string\"),\n reviewedProposal: a(\"json\"),\n actionDigest: idx(\"string\"),\n decisionBinding: a(\"json\"),\n approvedBy: idx(\"string\"),\n approvedByKind: a(\"string\"),\n appliedBy: idx(\"string\"),\n appliedByKind: a(\"string\"),\n authorityRef: idx(\"string\"),\n authorityCapability: a(\"string\"),\n authorityConsumption: a(\"json\"),\n createdAt: idx(\"date\"),\n receiptDigest: idx(\"string\"),\n },\n },\n [BRAND_NS.asset]: {\n attrs: {\n id: uniq(\"string\"),\n bookId: idx(\"string\"),\n kind: idx(\"string\"), // logo | wordmark | inspiration | document | other\n path: idx(\"string\"),\n storageObjectId: idx(\"string\"),\n contentDigest: idx(\"string\"),\n contentType: a(\"string\"),\n size: a(\"number\"),\n status: idx(\"string\"), // live | deleting | deleted\n title: opt(\"string\"),\n analysis: opt(\"json\"), // { description, dominantColors: hex[], tags }\n analyzedAt: opt(\"date\"),\n analysisRevision: a(\"number\"),\n analysisDigest: opt(\"string\"),\n analyzedBy: opt(\"string\"),\n analyzedAuthorityRef: opt(\"string\"),\n audience: a(\"json\"),\n uploadedBy: a(\"string\"),\n uploadedAuthorityRef: a(\"string\"),\n createdAt: idx(\"date\"),\n deletedAt: opt(\"date\"), // tombstone — asset rows are never row-deleted\n deletedBy: opt(\"string\"),\n deletedAuthorityRef: opt(\"string\"),\n },\n },\n },\n links: {\n brandSectionBook: {\n forward: { on: BRAND_NS.section, has: \"one\", label: \"book\" },\n reverse: { on: BRAND_NS.book, has: \"many\", label: \"sections\" },\n },\n brandPaletteBook: {\n forward: { on: BRAND_NS.palette, has: \"one\", label: \"book\" },\n reverse: { on: BRAND_NS.book, has: \"many\", label: \"palettes\" },\n },\n brandProposalBook: {\n forward: { on: BRAND_NS.proposal, has: \"one\", label: \"book\" },\n reverse: { on: BRAND_NS.book, has: \"many\", label: \"proposals\" },\n },\n brandApprovalReceiptBook: {\n forward: { on: BRAND_NS.approvalReceipt, has: \"one\", label: \"book\" },\n reverse: { on: BRAND_NS.book, has: \"many\", label: \"approvalReceipts\" },\n },\n brandAssetBook: {\n forward: { on: BRAND_NS.asset, has: \"one\", label: \"book\" },\n reverse: { on: BRAND_NS.book, has: \"many\", label: \"assets\" },\n },\n },\n};\n","// Default-deny CEL rules for the brand namespaces (POST to\n// `/app/:id/admin/rules`). Access is denormalized (see schema.ts): books gate\n// on `data.memberIds`; child rows follow their required book link and read the\n// current roster with `ref()`. Child writes are closed: proposals and\n// approval receipts all pass through worker routes/tools with explicit actor\n// attribution instead of letting an audience member mutate approval state.\n//\n// Asset writes are closed: rows mirror private object storage and only the\n// worker performs upload/mirror and delete/tombstone pairs.\nimport { BRAND_NS } from \"./constants\";\n\n/** Per-namespace CEL rule strings (missing action = deny). */\nexport interface BrandRule {\n view?: string;\n create?: string;\n update?: string;\n delete?: string;\n}\n/** Namespace → rule set, as installed at `/app/:id/admin/rules`. */\nexport type BrandRules = Record<string, BrandRule>;\n\n// Membership in the audience snapshot — implies a signed identity, since an\n// anonymous auth.id is never written into an audience.\n// A has-one link's ref() result is still a list; the json memberIds value is\n// therefore nested one level (`[[id,…]]`) and must be checked with exists.\nconst CURRENT_BOOK_MEMBER =\n \"ref('book.memberIds').exists(members, auth.id in members)\";\n\n/**\n * Default-deny CEL rules for the six brand namespaces; install at\n * `/app/:id/admin/rules`. Books gate on the `memberIds` roster (owner-only\n * writes); child rows gate reads on current linked-book membership and all\n * writes are worker-mediated. Use\n * {@link brandRules} for a per-install copy.\n */\nexport const BRAND_RULES: BrandRules = {\n [BRAND_NS.book]: {\n view: \"auth.id in data.memberIds\",\n // Every mutation is worker-routed: CEL cannot distinguish an update from\n // a retract, so effect-bearing fields must never be browser-writable.\n create: \"false\",\n update: \"false\",\n delete: \"false\",\n },\n [BRAND_NS.section]: {\n view: CURRENT_BOOK_MEMBER,\n create: \"false\",\n update: \"false\",\n delete: \"false\",\n },\n [BRAND_NS.palette]: {\n view: CURRENT_BOOK_MEMBER,\n create: \"false\",\n update: \"false\",\n delete: \"false\",\n },\n [BRAND_NS.proposal]: {\n view: CURRENT_BOOK_MEMBER,\n create: \"false\",\n update: \"false\",\n delete: \"false\",\n },\n [BRAND_NS.approvalReceipt]: {\n view: CURRENT_BOOK_MEMBER,\n create: \"false\",\n update: \"false\",\n delete: \"false\",\n },\n [BRAND_NS.asset]: {\n view: CURRENT_BOOK_MEMBER,\n create: \"false\",\n update: \"false\",\n delete: \"false\",\n },\n};\n\n/**\n * Rules factory, mirroring `chatRules()`/`crmRules()`. Today it returns a\n * fresh copy of {@link BRAND_RULES}; it exists so a future option (e.g.\n * locking views to an org email domain) can widen or tighten namespaces\n * without apps changing their provisioning call shape.\n */\nexport function brandRules(): BrandRules {\n return Object.fromEntries(Object.entries(BRAND_RULES).map(([ns, r]) => [ns, { ...r }]));\n}\n","// Input validation for brand writes — THE enforcement layer. Taint marking on\n// tool output is advisory; nothing an agent (or a route caller) produces\n// reaches odla-db without passing these checks. Every failure throws\n// {@link BrandInputError} with an actionable message.\nimport { SECTION_KINDS, SWATCH_ROLES } from \"./constants\";\nimport { BrandInputError } from \"./errors\";\nimport type {\n AssetAnalysis,\n ImagerySection,\n LogoSection,\n PaletteSection,\n Swatch,\n SwatchRole,\n TypographySection,\n VoiceSection,\n} from \"./types\";\n\n/** Most swatches a single palette may carry. */\nexport const MAX_SWATCHES = 24;\n\n/** Upload content types the asset pipeline accepts. */\nexport const ASSET_CONTENT_TYPES: ReadonlySet<string> = new Set([\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"application/pdf\",\n]);\n\nconst HEX_RGB = /^#[0-9a-f]{3}$/;\nconst HEX_RRGGBB = /^#[0-9a-f]{6}$/;\nconst HEX_ALPHA = /^#[0-9a-f]{4}$|^#[0-9a-f]{8}$/;\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/**\n * Assert `value` is a `#rgb`/`#rrggbb` hex color and normalize it to\n * lowercase `#rrggbb`. Alpha channels (`#rgba`/`#rrggbbaa`) and every other\n * color syntax are rejected — tokens and contrast math are defined on opaque\n * sRGB hex.\n */\nexport function assertHex(value: unknown, label = \"color\"): string {\n if (typeof value !== \"string\")\n throw new BrandInputError(`${label} must be a hex string like #1a2b3c`);\n const hex = value.trim().toLowerCase();\n if (HEX_ALPHA.test(hex))\n throw new BrandInputError(`${label} must not carry alpha (got ${value}); use #rrggbb`);\n if (HEX_RGB.test(hex)) return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;\n if (!HEX_RRGGBB.test(hex))\n throw new BrandInputError(`${label} must be #rgb or #rrggbb hex (got ${value})`);\n return hex;\n}\n\n/** Assert a trimmed non-empty string of at most `max` characters. */\nexport function capString(value: unknown, label: string, max: number): string {\n if (typeof value !== \"string\") throw new BrandInputError(`${label} must be a string`);\n const s = value.trim();\n if (s === \"\") throw new BrandInputError(`${label} must not be empty`);\n if (s.length > max)\n throw new BrandInputError(`${label} must be at most ${max} characters (got ${s.length})`);\n return s;\n}\n\n/** Assert an array of capped strings (each trimmed and non-empty). */\nexport function capStringArray(\n value: unknown,\n label: string,\n opts: { maxItems: number; maxLen: number; minItems?: number },\n): string[] {\n if (!Array.isArray(value)) throw new BrandInputError(`${label} must be an array of strings`);\n const min = opts.minItems ?? 0;\n if (value.length < min)\n throw new BrandInputError(`${label} must have at least ${min} item${min === 1 ? \"\" : \"s\"}`);\n if (value.length > opts.maxItems)\n throw new BrandInputError(`${label} must have at most ${opts.maxItems} items`);\n return value.map((v, i) => capString(v, `${label}[${i}]`, opts.maxLen));\n}\n\n/**\n * Assert a swatch list: 1–{@link MAX_SWATCHES} entries, each with a known\n * role, a valid hex (normalized), and capped optional name/rationale.\n * Returns the normalized copy — write THAT, never the raw input.\n */\nexport function assertSwatches(value: unknown): Swatch[] {\n if (!Array.isArray(value) || value.length === 0)\n throw new BrandInputError(\"swatches must be a non-empty array\");\n if (value.length > MAX_SWATCHES)\n throw new BrandInputError(`swatches must have at most ${MAX_SWATCHES} entries`);\n return value.map((raw, i) => {\n if (!isRecord(raw)) throw new BrandInputError(`swatches[${i}] must be an object`);\n const role = raw.role;\n if (typeof role !== \"string\" || !(SWATCH_ROLES as readonly string[]).includes(role))\n throw new BrandInputError(\n `swatches[${i}].role must be one of: ${SWATCH_ROLES.join(\", \")}`,\n );\n const out: Swatch = { role: role as SwatchRole, hex: assertHex(raw.hex, `swatches[${i}].hex`) };\n if (raw.name !== undefined) out.name = capString(raw.name, `swatches[${i}].name`, 80);\n if (raw.rationale !== undefined)\n out.rationale = capString(raw.rationale, `swatches[${i}].rationale`, 500);\n return out;\n });\n}\n\nfunction assertPaletteSection(c: Record<string, unknown>): PaletteSection {\n return {\n paletteId: capString(c.paletteId, \"content.paletteId\", 128),\n name: capString(c.name, \"content.name\", 120),\n swatches: assertSwatches(c.swatches),\n };\n}\n\nfunction assertTypographySection(c: Record<string, unknown>): TypographySection {\n const out: TypographySection = {};\n if (c.fontDisplay !== undefined) out.fontDisplay = capString(c.fontDisplay, \"content.fontDisplay\", 120);\n if (c.fontBody !== undefined) out.fontBody = capString(c.fontBody, \"content.fontBody\", 120);\n if (c.fontMono !== undefined) out.fontMono = capString(c.fontMono, \"content.fontMono\", 120);\n if (c.scale !== undefined) {\n if (typeof c.scale !== \"number\" || !Number.isFinite(c.scale) || c.scale <= 1 || c.scale > 2)\n throw new BrandInputError(\"content.scale must be a modular type-scale ratio in (1, 2]\");\n out.scale = c.scale;\n }\n if (c.notes !== undefined) out.notes = capString(c.notes, \"content.notes\", 2000);\n return out;\n}\n\nfunction assertVoiceSection(c: Record<string, unknown>): VoiceSection {\n const out: VoiceSection = {\n tone: capString(c.tone, \"content.tone\", 200),\n principles: capStringArray(c.principles, \"content.principles\", { maxItems: 12, maxLen: 200, minItems: 1 }),\n };\n if (c.examples !== undefined)\n out.examples = capStringArray(c.examples, \"content.examples\", { maxItems: 12, maxLen: 500 });\n return out;\n}\n\nfunction assertLogoSection(c: Record<string, unknown>): LogoSection {\n const out: LogoSection = {\n usage: capStringArray(c.usage, \"content.usage\", { maxItems: 16, maxLen: 300, minItems: 1 }),\n donts: capStringArray(c.donts, \"content.donts\", { maxItems: 16, maxLen: 300 }),\n };\n if (c.clearspace !== undefined) out.clearspace = capString(c.clearspace, \"content.clearspace\", 120);\n if (c.minSize !== undefined) out.minSize = capString(c.minSize, \"content.minSize\", 120);\n return out;\n}\n\nfunction assertImagerySection(c: Record<string, unknown>): ImagerySection {\n return {\n style: capString(c.style, \"content.style\", 200),\n guidance: capStringArray(c.guidance, \"content.guidance\", { maxItems: 16, maxLen: 300, minItems: 1 }),\n };\n}\n\n/**\n * Validate + normalize a section's `content` payload for its kind. Returns\n * the normalized content to write; throws {@link BrandInputError} on an\n * unknown kind or an invalid payload.\n */\nexport function assertSectionContent(kind: string, content: unknown): Record<string, unknown> {\n if (!isRecord(content)) throw new BrandInputError(\"content must be an object\");\n switch (kind) {\n case \"palette\":\n return { ...assertPaletteSection(content) };\n case \"typography\":\n return { ...assertTypographySection(content) };\n case \"voice\":\n return { ...assertVoiceSection(content) };\n case \"logo\":\n return { ...assertLogoSection(content) };\n case \"imagery\":\n return { ...assertImagerySection(content) };\n default:\n throw new BrandInputError(`unknown section kind ${kind}; expected one of: ${SECTION_KINDS.join(\", \")}`);\n }\n}\n\n/**\n * Validate an upload file name for an R2 key. Path/URL delimiters and control\n * characters are rejected; leading dots are stripped and length is capped.\n */\nexport function safeFileName(name: unknown): string {\n if (typeof name !== \"string\") throw new BrandInputError(\"file name must be a string\");\n // eslint-disable-next-line no-control-regex\n if (/[/\\\\?#%\\u0000-\\u001f\\u007f]/.test(name))\n throw new BrandInputError(\"file name must not contain path or URL delimiter characters\");\n const cleaned = name\n .trim()\n .replace(/^\\.+/, \"\");\n if (cleaned === \"\" || cleaned === \".\" || cleaned === \"..\")\n throw new BrandInputError(\"file name is empty or a dot segment after sanitizing\");\n return cleaned.slice(0, 120);\n}\n\n/**\n * Assert an upload content type is on the {@link ASSET_CONTENT_TYPES}\n * allowlist. Normalizes case and strips parameters (`; charset=…`) before\n * checking; returns the normalized bare type.\n */\nexport function assertAssetContentType(value: unknown): string {\n if (typeof value !== \"string\") throw new BrandInputError(\"contentType must be a string\");\n const ct = value.split(\";\")[0]!.trim().toLowerCase();\n if (!ASSET_CONTENT_TYPES.has(ct))\n throw new BrandInputError(\n `unsupported content type ${ct || \"(empty)\"}; allowed: ${[...ASSET_CONTENT_TYPES].join(\", \")}`,\n );\n return ct;\n}\n\n/**\n * Validate + normalize an agent's asset analysis: description ≤ 2000 chars,\n * ≤ 12 dominant colors (each normalized hex), ≤ 24 tags of ≤ 60 chars.\n */\nexport function assertAnalysis(value: unknown): AssetAnalysis {\n if (!isRecord(value)) throw new BrandInputError(\"analysis must be an object\");\n const colors = value.dominantColors;\n if (!Array.isArray(colors)) throw new BrandInputError(\"analysis.dominantColors must be an array\");\n if (colors.length > 12)\n throw new BrandInputError(\"analysis.dominantColors must have at most 12 entries\");\n return {\n description: capString(value.description, \"analysis.description\", 2000),\n dominantColors: colors.map((c, i) => assertHex(c, `analysis.dominantColors[${i}]`)),\n tags: capStringArray(value.tags, \"analysis.tags\", { maxItems: 24, maxLen: 60 }),\n };\n}\n","const record = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n (Object.getPrototypeOf(value) === Object.prototype ||\n Object.getPrototypeOf(value) === null);\n\n/** Stay materially below the server's whole-guards parser budget. */\nexport function isBoundedBrandJson(\n root: unknown,\n limits: { maxDepth?: number; maxNodes?: number; maxBytes?: number } = {},\n): boolean {\n const maxDepth = limits.maxDepth ?? 12;\n const maxNodes = limits.maxNodes ?? 2_048;\n const maxBytes = limits.maxBytes ?? 32 * 1024;\n const stack: Array<{ value: unknown; depth: number }> = [{\n value: root,\n depth: 0,\n }];\n const seen = new Set<object>();\n let nodes = 0;\n while (stack.length) {\n const { value, depth } = stack.pop()!;\n if (++nodes > maxNodes || depth > maxDepth) return false;\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"boolean\"\n ) continue;\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) return false;\n continue;\n }\n if (typeof value !== \"object\" || seen.has(value)) return false;\n seen.add(value);\n if (Array.isArray(value)) {\n for (const child of value)\n stack.push({ value: child, depth: depth + 1 });\n } else if (record(value)) {\n for (const child of Object.values(value))\n stack.push({ value: child, depth: depth + 1 });\n } else {\n return false;\n }\n }\n try {\n return new TextEncoder().encode(JSON.stringify(root)).byteLength <= maxBytes;\n } catch {\n return false;\n }\n}\n\nfunction canonical(value: unknown): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n const row = value as Record<string, unknown>;\n return `{${Object.keys(row).sort().map((key) =>\n `${JSON.stringify(key)}:${canonical(row[key])}`).join(\",\")}}`;\n}\n\n/** Deterministic JSON with recursively sorted object keys. */\nexport function canonicalBrandJson(value: unknown): string {\n if (!isBoundedBrandJson(value, {\n maxDepth: 20,\n maxNodes: 8_192,\n maxBytes: 128 * 1024,\n })) throw new TypeError(\"brand digest input must be bounded finite JSON\");\n return canonical(value);\n}\n\n/** `sha256:<hex>` over {@link canonicalBrandJson}. */\nexport async function brandJsonDigest(value: unknown): Promise<string> {\n const bytes = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(canonicalBrandJson(value)),\n );\n return `sha256:${[...new Uint8Array(bytes)]\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n","// Bounded canonical JSON and self-consistency checks for Brand review and\n// approval records. A local digest is not an authenticity proof: authenticity\n// comes from the credential-bound central authority consumption embedded in\n// the receipt.\nimport { PROPOSAL_KINDS } from \"./constants\";\nimport type {\n BrandApprovalReceipt,\n BrandHumanAuthorityConsumption,\n BrandProposalReviewSnapshot,\n} from \"./types\";\nimport {\n brandJsonDigest,\n isBoundedBrandJson,\n} from \"./review-json\";\n\nexport {\n brandJsonDigest,\n canonicalBrandJson,\n isBoundedBrandJson,\n} from \"./review-json\";\n\nconst DIGEST = /^sha256:[0-9a-f]{64}$/;\nconst record = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\nconst exactKeys = (value: Record<string, unknown>, required: readonly string[], optional: readonly string[] = []) => {\n const allowed = new Set([...required, ...optional]);\n return required.every((key) => Object.hasOwn(value, key)) &&\n Object.keys(value).every((key) => allowed.has(key));\n};\nconst boundedString = (value: unknown, max = 200): value is string =>\n typeof value === \"string\" && value.length > 0 && value.length <= max;\nconst safeTime = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) >= 0;\n\n/** Stable local reference to one immutable central grant revision. */\nexport function brandAuthorityRef(\n consumption: Pick<BrandHumanAuthorityConsumption, \"grantId\" | \"grantVersion\">,\n): string {\n return `authority:${consumption.grantId}:v${consumption.grantVersion}`;\n}\n\nconst SNAPSHOT_REQUIRED = [\n \"id\", \"bookId\", \"kind\", \"status\", \"payload\", \"rationale\", \"provenance\",\n \"reviewDigest\", \"audience\", \"createdBy\", \"createdAuthorityRef\", \"createdAt\",\n] as const;\n\nfunction validSnapshotShape(value: unknown): value is BrandProposalReviewSnapshot {\n if (!record(value) || !exactKeys(value, SNAPSHOT_REQUIRED)) return false;\n const provenance = value.provenance;\n return boundedString(value.id) &&\n boundedString(value.bookId) &&\n typeof value.kind === \"string\" &&\n (PROPOSAL_KINDS as readonly string[]).includes(value.kind) &&\n value.status === \"open\" &&\n record(value.payload) &&\n boundedString(value.rationale, 2_000) &&\n record(provenance) &&\n exactKeys(provenance, [\n \"sourceAssetId\", \"sourceAsset\", \"messageId\", \"turnId\", \"taintLabels\",\n ]) &&\n (provenance.sourceAssetId === null ||\n boundedString(provenance.sourceAssetId)) &&\n (provenance.sourceAsset === null ||\n (record(provenance.sourceAsset) &&\n exactKeys(provenance.sourceAsset, [\n \"assetId\", \"contentDigest\", \"objectEtag\", \"objectSize\", \"pathDigest\",\n \"contentType\", \"analysisRevision\", \"analysisDigest\",\n ]) &&\n boundedString(provenance.sourceAsset.assetId) &&\n typeof provenance.sourceAsset.contentDigest === \"string\" &&\n DIGEST.test(provenance.sourceAsset.contentDigest) &&\n boundedString(provenance.sourceAsset.objectEtag) &&\n Number.isSafeInteger(provenance.sourceAsset.objectSize) &&\n (provenance.sourceAsset.objectSize as number) > 0 &&\n typeof provenance.sourceAsset.pathDigest === \"string\" &&\n DIGEST.test(provenance.sourceAsset.pathDigest) &&\n (provenance.sourceAsset.contentType === null ||\n boundedString(provenance.sourceAsset.contentType, 160)) &&\n (provenance.sourceAsset.analysisRevision === null ||\n (Number.isSafeInteger(provenance.sourceAsset.analysisRevision) &&\n (provenance.sourceAsset.analysisRevision as number) >= 0)) &&\n (provenance.sourceAsset.analysisDigest === null ||\n (typeof provenance.sourceAsset.analysisDigest === \"string\" &&\n DIGEST.test(provenance.sourceAsset.analysisDigest))))) &&\n ((provenance.sourceAssetId === null && provenance.sourceAsset === null) ||\n (provenance.sourceAssetId !== null &&\n provenance.sourceAsset !== null &&\n provenance.sourceAsset.assetId === provenance.sourceAssetId)) &&\n (provenance.messageId === null || boundedString(provenance.messageId)) &&\n (provenance.turnId === null || boundedString(provenance.turnId)) &&\n Array.isArray(provenance.taintLabels) &&\n provenance.taintLabels.length <= 16 &&\n provenance.taintLabels.every((label) => boundedString(label, 120)) &&\n new Set(provenance.taintLabels).size === provenance.taintLabels.length &&\n typeof value.reviewDigest === \"string\" && DIGEST.test(value.reviewDigest) &&\n Array.isArray(value.audience) &&\n value.audience.length > 0 && value.audience.length <= 100 &&\n value.audience.every((id) => boundedString(id)) &&\n new Set(value.audience).size === value.audience.length &&\n boundedString(value.createdBy) &&\n boundedString(value.createdAuthorityRef) &&\n safeTime(value.createdAt);\n}\n\nconst CONSUMPTION_REQUIRED = [\n \"id\", \"grantId\", \"grantVersion\", \"useNumber\", \"actorPrincipalId\",\n \"actorKind\", \"credentialId\", \"credentialKind\", \"appId\", \"appIncarnation\",\n \"capability\",\n \"projectCapability\", \"effect\", \"actionDigest\", \"resourceDigest\",\n \"constraintEvidence\",\n \"consumptionIdempotencyKey\", \"requestDigest\", \"consumedAt\",\n] as const;\n\n/** Validate the exact direct-human central authority receipt shape. */\nexport function isBrandHumanAuthorityConsumption(\n value: unknown,\n): value is BrandHumanAuthorityConsumption {\n if (!record(value) || !exactKeys(value, CONSUMPTION_REQUIRED)) return false;\n return boundedString(value.id) &&\n boundedString(value.grantId) &&\n Number.isSafeInteger(value.grantVersion) && (value.grantVersion as number) > 0 &&\n Number.isSafeInteger(value.useNumber) && (value.useNumber as number) > 0 &&\n boundedString(value.actorPrincipalId) &&\n value.actorKind === \"human\" &&\n boundedString(value.credentialId) &&\n value.credentialKind === \"clerk\" &&\n boundedString(value.appId) &&\n typeof value.appIncarnation === \"string\" &&\n /^[a-f0-9]{32}$/.test(value.appIncarnation) &&\n value.capability === \"brand.proposal.resolve\" &&\n value.projectCapability === \"brand.approve\" &&\n value.effect === \"internal\" &&\n typeof value.actionDigest === \"string\" && DIGEST.test(value.actionDigest) &&\n typeof value.resourceDigest === \"string\" && DIGEST.test(value.resourceDigest) &&\n record(value.constraintEvidence) &&\n boundedString(value.consumptionIdempotencyKey) &&\n typeof value.requestDigest === \"string\" && DIGEST.test(value.requestDigest) &&\n safeTime(value.consumedAt);\n}\n\nconst RECEIPT_REQUIRED = [\n \"version\", \"id\", \"mutationKey\", \"bookId\", \"proposalId\", \"resolution\",\n \"reviewedProposal\", \"actionDigest\", \"decisionBinding\", \"approvedBy\", \"approvedByKind\",\n \"appliedBy\", \"appliedByKind\", \"authorityRef\", \"authorityCapability\",\n \"authorityConsumption\", \"createdAt\", \"receiptDigest\",\n] as const;\n\n/** Verify exact shape, cross-field bindings, and every local digest. This\n * proves receipt self-consistency only; the host must authenticate the\n * central consumption behind `authorityConsumption.id`. */\nexport async function verifyBrandApprovalReceipt(receipt: unknown): Promise<boolean> {\n try {\n if (!isBoundedBrandJson(receipt, { maxDepth: 14, maxNodes: 2_500, maxBytes: 48 * 1024 }))\n return false;\n if (!record(receipt) || !exactKeys(receipt, RECEIPT_REQUIRED, [\"paletteId\", \"resolutionNote\"]))\n return false;\n const binding = receipt.decisionBinding;\n if (\n receipt.version !== 1 ||\n !boundedString(receipt.id) ||\n !boundedString(receipt.mutationKey) ||\n !boundedString(receipt.bookId) ||\n !boundedString(receipt.proposalId) ||\n (receipt.resolution !== \"accepted\" && receipt.resolution !== \"rejected\") ||\n !validSnapshotShape(receipt.reviewedProposal) ||\n typeof receipt.actionDigest !== \"string\" || !DIGEST.test(receipt.actionDigest) ||\n !record(binding) ||\n !exactKeys(binding, [\n \"version\", \"bookVersion\", \"activationRevision\", \"activePaletteId\",\n \"memberIdsDigest\", \"activePaletteDigest\", \"typographyDigest\",\n \"sourceAssetDigest\", \"effectDigest\",\n ]) ||\n binding.version !== 1 ||\n !Number.isSafeInteger(binding.bookVersion) || (binding.bookVersion as number) < 1 ||\n !Number.isSafeInteger(binding.activationRevision) ||\n (binding.activationRevision as number) < 0 ||\n (binding.activePaletteId !== null && !boundedString(binding.activePaletteId)) ||\n typeof binding.memberIdsDigest !== \"string\" || !DIGEST.test(binding.memberIdsDigest) ||\n (binding.activePaletteDigest !== null &&\n (typeof binding.activePaletteDigest !== \"string\" ||\n !DIGEST.test(binding.activePaletteDigest))) ||\n (binding.typographyDigest !== null &&\n (typeof binding.typographyDigest !== \"string\" ||\n !DIGEST.test(binding.typographyDigest))) ||\n (binding.sourceAssetDigest !== null &&\n (typeof binding.sourceAssetDigest !== \"string\" ||\n !DIGEST.test(binding.sourceAssetDigest))) ||\n typeof binding.effectDigest !== \"string\" || !DIGEST.test(binding.effectDigest) ||\n !boundedString(receipt.approvedBy) ||\n receipt.approvedByKind !== \"human\" ||\n !boundedString(receipt.appliedBy) ||\n receipt.appliedByKind !== \"human\" ||\n !boundedString(receipt.authorityRef) ||\n receipt.authorityCapability !== \"brand.approve\" ||\n !isBrandHumanAuthorityConsumption(receipt.authorityConsumption) ||\n !safeTime(receipt.createdAt) ||\n typeof receipt.receiptDigest !== \"string\" || !DIGEST.test(receipt.receiptDigest) ||\n (receipt.paletteId !== undefined && !boundedString(receipt.paletteId)) ||\n (receipt.resolutionNote !== undefined && !boundedString(receipt.resolutionNote, 1_000))\n ) return false;\n\n const reviewed = receipt.reviewedProposal;\n const authority = receipt.authorityConsumption;\n if (\n reviewed.id !== receipt.proposalId ||\n reviewed.bookId !== receipt.bookId ||\n receipt.approvedBy !== receipt.appliedBy ||\n authority.actorPrincipalId !== receipt.approvedBy ||\n authority.actionDigest !== receipt.actionDigest ||\n authority.consumptionIdempotencyKey !== receipt.mutationKey ||\n receipt.authorityRef !== brandAuthorityRef(authority) ||\n authority.consumedAt > receipt.createdAt ||\n (receipt.resolution === \"rejected\" && receipt.paletteId !== undefined) ||\n (receipt.resolution === \"accepted\" && reviewed.kind === \"palette\" && !receipt.paletteId) ||\n (reviewed.kind !== \"palette\" && receipt.paletteId !== undefined)\n ) return false;\n\n const { reviewDigest, ...unsignedReview } = reviewed;\n if ((await brandJsonDigest(unsignedReview)) !== reviewDigest) return false;\n const expectedAction = await brandJsonDigest({\n version: 1,\n reviewedProposal: reviewed,\n resolution: receipt.resolution,\n resolutionNote: receipt.resolutionNote ?? null,\n paletteId: receipt.paletteId ?? null,\n decisionBinding: binding,\n });\n if (expectedAction !== receipt.actionDigest) return false;\n if ((await brandJsonDigest({ bookId: receipt.bookId, proposalId: receipt.proposalId })) !==\n authority.resourceDigest) return false;\n\n const { receiptDigest, ...immutable } = receipt;\n return (await brandJsonDigest(immutable)) === receiptDigest;\n } catch {\n return false;\n }\n}\n","/** Brand resources that can be shared into a Discussion message. */\nexport const BRAND_DISCUSSION_REFERENCE_KINDS = [\n \"brand:book\",\n \"brand:asset\",\n \"brand:palette\",\n \"brand:proposal\",\n \"brand:receipt\",\n] as const;\n\n/** One Brand resource kind understood by the native Brand destination. */\nexport type BrandDiscussionReferenceKind =\n (typeof BRAND_DISCUSSION_REFERENCE_KINDS)[number];\n\n/** Canonical Brand destination target parsed from an `odla-ref` deep link. */\nexport interface BrandDiscussionReferenceTarget {\n kind: BrandDiscussionReferenceKind;\n bookId: string;\n resourceId?: string;\n}\n\n/** Product-owned projection returned to Discussion typeahead and exact lookup. */\nexport interface BrandDiscussionReference {\n /** Canonical Brand kind used in stored Discussion ref markup. */\n kind: BrandDiscussionReferenceKind;\n /** Opaque durable product id; never infer membership from its segments. */\n id: string;\n /** Product-authored primary display name. */\n label: string;\n /** Short product-authored secondary context for the picker. */\n hint: string;\n /** Bounded product-authored context safe to show an LLM or person. */\n summary: string;\n /** Current product status at inspection time. */\n status: string;\n /** Human-readable native surface the link opens. */\n destination: string;\n /** Same-origin native link; navigation is not mutation authority. */\n href: string;\n}\n\nconst SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._~-]{0,199}$/;\n\n/** Durable ref id: a book id, or `bookId/resourceId` for a child resource. */\nexport function brandDiscussionReferenceId(\n target: BrandDiscussionReferenceTarget,\n): string {\n return target.resourceId\n ? `${target.bookId}/${target.resourceId}`\n : target.bookId;\n}\n\n/** Canonical value stored in the stable `odla-ref` query parameter. */\nexport function formatBrandDiscussionReference(\n target: BrandDiscussionReferenceTarget,\n): string {\n return `${target.kind}/${brandDiscussionReferenceId(target)}`;\n}\n\n/** Parse and validate a Brand `odla-ref`; malformed and cross-product refs fail closed. */\nexport function parseBrandDiscussionReference(\n input: URL | string,\n): BrandDiscussionReferenceTarget | null {\n let raw: string | null;\n try {\n raw = input instanceof URL\n ? input.searchParams.get(\"odla-ref\")\n : new URL(input, \"https://brand.invalid\").searchParams.get(\"odla-ref\");\n } catch {\n return null;\n }\n if (!raw) return null;\n const [kind, bookId, resourceId, extra] = raw.split(\"/\");\n if (\n extra !== undefined ||\n !BRAND_DISCUSSION_REFERENCE_KINDS.includes(\n kind as BrandDiscussionReferenceKind,\n ) ||\n !bookId ||\n !SEGMENT.test(bookId)\n ) return null;\n const typedKind = kind as BrandDiscussionReferenceKind;\n if (typedKind === \"brand:book\") {\n return resourceId === undefined ? { kind: typedKind, bookId } : null;\n }\n return resourceId && SEGMENT.test(resourceId)\n ? { kind: typedKind, bookId, resourceId }\n : null;\n}\n\n/** Build the native Brand deep link while preserving the deployed origin. */\nexport function brandDiscussionReferenceHref(\n current: URL,\n target: BrandDiscussionReferenceTarget,\n basePath = \"/\",\n): string {\n const next = new URL(current.origin);\n next.pathname = basePath.startsWith(\"/\") ? basePath : `/${basePath}`;\n next.searchParams.set(\"odla-ref\", formatBrandDiscussionReference(target));\n return next.toString();\n}\n","// Pure op-builders for brand_book rows: (input) -> BrandOp[]. No I/O — this\n// is the unit-test seam (assert the emitted ops); routes and the skill share\n// these so every write path commits identical shapes.\nimport { BOOK_STATUSES, BRAND_NS, type BookStatus } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport type { BrandAttrs, BrandBook, BrandEntityRef, BrandOp } from \"../types\";\nimport { capString } from \"../validate\";\n\nconst SLUG_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;\n\n/** Input to {@link createBookOps}. `memberIds` is the full auth roster —\n * include the bot agent's id so it can pass the audience rules. */\nexport interface CreateBookInput {\n id: string;\n slug: string;\n name: string;\n ownerId: string;\n createdAuthorityRef: string;\n memberIds: string[];\n channelId?: string;\n now: number;\n}\n\n/**\n * Ops to create a brand book: one `brand_book` row in `draft` status with the\n * id mirrored as an attr (odla-db ids aren't attrs), the owner always folded\n * into the deduplicated `memberIds` roster (the create rule requires it), and\n * both timestamps set to `now`.\n */\nexport function createBookOps(input: CreateBookInput): BrandOp[] {\n const slug = capString(input.slug, \"slug\", 80);\n if (!SLUG_RE.test(slug))\n throw new BrandInputError(\"slug must be lowercase letters, digits, and inner hyphens\");\n const name = capString(input.name, \"name\", 120);\n const ownerId = capString(input.ownerId, \"ownerId\", 160);\n const createdAuthorityRef = capString(input.createdAuthorityRef, \"createdAuthorityRef\", 200);\n const memberIds = Array.from(new Set([ownerId, ...input.memberIds.map((id, index) =>\n capString(id, `memberIds[${index}]`, 160))]));\n if (memberIds.length > 100)\n throw new BrandInputError(\"a brand book supports at most 100 members\");\n return [\n {\n t: \"update\",\n ns: BRAND_NS.book,\n id: input.id,\n attrs: {\n id: input.id,\n version: 1,\n slug,\n name,\n status: \"draft\",\n ownerId,\n createdAuthorityRef,\n memberIds,\n activationRevision: 0,\n createdAt: input.now,\n updatedAt: input.now,\n ...(input.channelId ? { channelId: input.channelId } : {}),\n },\n },\n ];\n}\n\n// Patchable book columns, and which of them may be cleared with `null`\n// (required attrs can't be retracted — the final-state schema check fails).\nconst PATCHABLE = new Set([\"name\", \"status\", \"channelId\", \"summary\"]);\nconst CLEARABLE = new Set([\"channelId\", \"summary\"]);\n\nfunction validateBookField(key: string, value: unknown): unknown {\n switch (key) {\n case \"name\":\n return capString(value, \"name\", 120);\n case \"status\":\n if (typeof value !== \"string\" || !(BOOK_STATUSES as readonly string[]).includes(value))\n throw new BrandInputError(`status must be one of: ${BOOK_STATUSES.join(\", \")}`);\n return value as BookStatus;\n case \"channelId\":\n return capString(value, \"channelId\", 128);\n case \"summary\":\n return capString(value, \"summary\", 2000);\n default:\n return value;\n }\n}\n\n/**\n * Ops to patch a brand book. `null` means CLEAR (a `retract` op — odla-db has\n * no storable scalar null) and is only allowed on optional columns;\n * `undefined` keys are dropped. Any write stamps `updatedAt`; an empty\n * effective patch emits no ops at all.\n */\nexport function updateBookOps(\n bookId: BrandEntityRef,\n patch: Record<string, unknown>,\n now: number,\n): BrandOp[] {\n const attrs: BrandAttrs = {};\n const retract: string[] = [];\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) continue;\n if (!PATCHABLE.has(key)) throw new BrandInputError(`unknown book field: ${key}`);\n if (value === null) {\n if (!CLEARABLE.has(key)) throw new BrandInputError(`${key} is required and cannot be cleared`);\n retract.push(key);\n continue;\n }\n attrs[key] = validateBookField(key, value);\n }\n if (Object.keys(attrs).length === 0 && retract.length === 0) return [];\n const ops: BrandOp[] = [\n { t: \"update\", ns: BRAND_NS.book, id: bookId, attrs: { ...attrs, updatedAt: now } },\n ];\n if (retract.length > 0) ops.push({ t: \"retract\", ns: BRAND_NS.book, id: bookId, attrs: retract });\n return ops;\n}\n\n/** The child rows whose `audience` snapshots a roster change must rewrite.\n * Pass the rows you queried — the builder stays pure. */\nexport interface AudienceChildren {\n sections?: Array<{ id: string }>;\n palettes?: Array<{ id: string }>;\n proposals?: Array<{ id: string }>;\n assets?: Array<{ id: string }>;\n}\n\n/**\n * Ops to change a book's roster: rewrite `memberIds` (owner always kept) and\n * fan the new list out to every child row's denormalized `audience` snapshot.\n * Query the children first and pass them in — this builder does no I/O, so\n * tests can assert the exact fan-out.\n */\nexport function audienceFanoutOps(\n book: Pick<BrandBook, \"id\" | \"ownerId\">,\n newMemberIds: string[],\n children: AudienceChildren,\n now: number,\n): BrandOp[] {\n const memberIds = Array.from(new Set([book.ownerId, ...newMemberIds]));\n const ops: BrandOp[] = [\n { t: \"update\", ns: BRAND_NS.book, id: book.id, attrs: { memberIds, updatedAt: now } },\n ];\n const fan = (ns: string, rows?: Array<{ id: string }>) => {\n for (const row of rows ?? []) ops.push({ t: \"update\", ns, id: row.id, attrs: { audience: memberIds } });\n };\n fan(BRAND_NS.section, children.sections);\n fan(BRAND_NS.palette, children.palettes);\n fan(BRAND_NS.proposal, children.proposals);\n fan(BRAND_NS.asset, children.assets);\n return ops;\n}\n","// Pure op-builder for brand_section rows. One section per (book, kind),\n// upserted through a natural-key Lookup ref so re-writing the same section\n// binds to the same row (no read-modify-write race, idempotent installs).\nimport { BRAND_NS, SECTION_STATUSES, type SectionKind, type SectionStatus } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport { brandJsonDigest } from \"../review\";\nimport type { BrandOp, BrandProposal } from \"../types\";\nimport { assertSectionContent, capString } from \"../validate\";\n\n/** The natural key a section row is upserted by: `${bookId}:${kind}`. */\nexport function sectionKey(bookId: string, kind: SectionKind): string {\n return `${bookId}:${kind}`;\n}\n\n/** Input to {@link upsertSectionOps}. `audience` is the book's roster\n * snapshot; `status` defaults to `draft` (a human approves later). */\nexport interface UpsertSectionInput {\n bookId: string;\n kind: SectionKind;\n content: Record<string, unknown>;\n status?: SectionStatus;\n audience: string[];\n updatedBy: string;\n now: number;\n approvalReceiptId?: string;\n approvalActionDigest?: string;\n}\n\n/**\n * Ops to create-or-replace a book's section of one kind: a single `update`\n * addressed by the `{ ns, attr: \"key\", value }` Lookup ref, carrying the\n * validated + normalized content (see `assertSectionContent`), the audience\n * snapshot, and the author/timestamp.\n */\nexport function upsertSectionOps(input: UpsertSectionInput): BrandOp[] {\n const status = input.status ?? \"draft\";\n if (!(SECTION_STATUSES as readonly string[]).includes(status))\n throw new BrandInputError(`status must be one of: ${SECTION_STATUSES.join(\", \")}`);\n const content = assertSectionContent(input.kind, input.content);\n if (\n status === \"approved\" &&\n (!input.approvalReceiptId || !input.approvalActionDigest)\n ) throw new BrandInputError(\"approved sections require approval receipt provenance\");\n const key = sectionKey(input.bookId, input.kind);\n return [\n {\n t: \"update\",\n ns: BRAND_NS.section,\n id: { ns: BRAND_NS.section, attr: \"key\", value: key },\n attrs: {\n key,\n bookId: input.bookId,\n kind: input.kind,\n status,\n content,\n audience: input.audience,\n updatedBy: input.updatedBy,\n updatedAt: input.now,\n ...(input.approvalReceiptId\n ? { approvalReceiptId: capString(input.approvalReceiptId, \"approvalReceiptId\", 200) }\n : {}),\n ...(input.approvalActionDigest\n ? { approvalActionDigest: capString(input.approvalActionDigest, \"approvalActionDigest\", 80) }\n : {}),\n },\n },\n {\n t: \"link\",\n ns: BRAND_NS.section,\n id: { ns: BRAND_NS.section, attr: \"key\", value: key },\n label: \"book\",\n target: input.bookId,\n },\n ];\n}\n\n/** Input for an agent-authored non-palette facet proposal. */\nexport interface ProposeSectionInput {\n id: string;\n bookId: string;\n kind: Exclude<SectionKind, \"palette\">;\n content: Record<string, unknown>;\n rationale: string;\n audience: string[];\n createdBy: string;\n createdAuthorityRef: string;\n sourceAsset?: BrandProposal[\"provenance\"][\"sourceAsset\"];\n messageId: string;\n turnId: string;\n taintLabels: string[];\n now: number;\n}\n\n/** Validate a facet draft and park it as an immutable OPEN proposal. */\nexport async function proposeSectionOps(input: ProposeSectionInput): Promise<BrandOp[]> {\n if (input.taintLabels.length > 16)\n throw new BrandInputError(\"taintLabels must have at most 16 entries\");\n const proposal = {\n id: input.id,\n bookId: input.bookId,\n kind: input.kind,\n status: \"open\" as const,\n payload: { content: assertSectionContent(input.kind, input.content) },\n rationale: capString(input.rationale, \"rationale\", 2000),\n provenance: {\n sourceAssetId: input.sourceAsset?.assetId ?? null,\n sourceAsset: input.sourceAsset ?? null,\n messageId: capString(input.messageId, \"messageId\", 200),\n turnId: capString(input.turnId, \"turnId\", 200),\n taintLabels: [...new Set(input.taintLabels.map((label, index) =>\n capString(label, `taintLabels[${index}]`, 120)))].sort(),\n },\n audience: input.audience,\n createdBy: input.createdBy,\n createdAuthorityRef: input.createdAuthorityRef,\n createdAt: input.now,\n };\n return [\n {\n t: \"update\",\n ns: BRAND_NS.proposal,\n id: input.id,\n attrs: { ...proposal, reviewDigest: await brandJsonDigest(proposal) },\n },\n { t: \"link\", ns: BRAND_NS.proposal, id: input.id, label: \"book\", target: input.bookId },\n ];\n}\n","// Pure op-builders for the palette proposal flow: the agent proposes, a\n// HUMAN accepts or rejects. Acceptance is one atomic transact — palette row,\n// approved palette section, the book's `activePaletteId`, and the proposal's\n// resolution — so a book can never point at a palette that wasn't written.\n//\n// Note on op kinds: the design doc says \"book merge {activePaletteId}\", but\n// odla-db's `merge` op deep-merges JSON attributes only (the engine rejects\n// it on scalars) — a scalar write on an existing row is an attr-merge\n// `update`, which is what these builders emit.\nimport { BRAND_NS } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport { brandJsonDigest } from \"../review\";\nimport type { BrandOp, BrandProposal } from \"../types\";\nimport { assertHex, assertSwatches, capString } from \"../validate\";\nimport { upsertSectionOps } from \"./sections\";\n\n/** Input to {@link proposePaletteOps}. `audience` is the book's roster\n * snapshot; `contrastReport` is stored verbatim in the payload for the\n * human reviewer. */\nexport interface ProposePaletteInput {\n id: string;\n bookId: string;\n name: string;\n rationale: string;\n swatches: unknown;\n seedHex?: string;\n contrastReport?: unknown;\n createdBy: string;\n createdAuthorityRef: string;\n audience: string[];\n sourceAsset?: BrandProposal[\"provenance\"][\"sourceAsset\"];\n messageId: string;\n turnId: string;\n taintLabels: string[];\n now: number;\n}\n\n/**\n * Ops to park a palette proposal for human review: one `brand_proposal` row,\n * `kind: \"palette\"`, `status: \"open\"`, with the validated swatches (and\n * optional seed/contrast report) in `payload`.\n */\nexport async function proposePaletteOps(input: ProposePaletteInput): Promise<BrandOp[]> {\n const name = capString(input.name, \"name\", 120);\n const rationale = capString(input.rationale, \"rationale\", 2000);\n const swatches = assertSwatches(input.swatches);\n const seedHex = input.seedHex === undefined ? undefined : assertHex(input.seedHex, \"seedHex\");\n if (input.taintLabels.length > 16)\n throw new BrandInputError(\"taintLabels must have at most 16 entries\");\n const payload: Record<string, unknown> = {\n name,\n swatches,\n ...(seedHex ? { seedHex } : {}),\n ...(input.contrastReport !== undefined ? { contrastReport: input.contrastReport } : {}),\n };\n const proposal = {\n id: input.id,\n bookId: input.bookId,\n kind: \"palette\" as const,\n status: \"open\" as const,\n payload,\n rationale,\n provenance: {\n sourceAssetId: input.sourceAsset?.assetId ?? null,\n sourceAsset: input.sourceAsset ?? null,\n messageId: capString(input.messageId, \"messageId\", 200),\n turnId: capString(input.turnId, \"turnId\", 200),\n taintLabels: [...new Set(input.taintLabels.map((label, index) =>\n capString(label, `taintLabels[${index}]`, 120)))].sort(),\n },\n audience: input.audience,\n createdBy: input.createdBy,\n createdAuthorityRef: input.createdAuthorityRef,\n createdAt: input.now,\n };\n return [\n {\n t: \"update\",\n ns: BRAND_NS.proposal,\n id: input.id,\n attrs: { ...proposal, reviewDigest: await brandJsonDigest(proposal) },\n },\n { t: \"link\", ns: BRAND_NS.proposal, id: input.id, label: \"book\", target: input.bookId },\n ];\n}\n\n/** Input to {@link acceptProposalOps}: the proposal row as read back, the id\n * to mint the palette under, and who resolved it. */\nexport interface AcceptProposalInput {\n proposal: BrandProposal;\n paletteId: string;\n resolvedBy: string;\n approvalReceiptId: string;\n approvalActionDigest: string;\n now: number;\n resolutionNote?: string;\n}\n\n/**\n * Ops to accept an OPEN palette proposal, all in one transact:\n * 1. the `brand_palette` row (source: `extracted` when the proposal came from\n * an asset, `derived` when seeded, else `manual`),\n * 2. the approved `palette` section upsert,\n * 3. the book's `activePaletteId` pointer,\n * 4. the proposal flipped to `accepted` with resolver + timestamp.\n * Throws on a non-palette or already-resolved proposal, or a payload that no\n * longer validates.\n */\nexport function acceptProposalOps(input: AcceptProposalInput): BrandOp[] {\n const {\n proposal,\n paletteId,\n resolvedBy,\n approvalReceiptId,\n approvalActionDigest,\n now,\n } = input;\n if (proposal.kind !== \"palette\")\n throw new BrandInputError(`proposal ${proposal.id} is a ${proposal.kind} proposal, not a palette`);\n if (proposal.status !== \"open\")\n throw new BrandInputError(`proposal ${proposal.id} is ${proposal.status}, not open`);\n const payload = proposal.payload;\n const name = capString(payload.name, \"payload.name\", 120);\n const swatches = assertSwatches(payload.swatches);\n const seedHex = payload.seedHex === undefined ? undefined : assertHex(payload.seedHex, \"payload.seedHex\");\n const source = proposal.provenance.sourceAsset ? \"extracted\" : seedHex ? \"derived\" : \"manual\";\n return [\n {\n t: \"update\",\n ns: BRAND_NS.palette,\n id: paletteId,\n attrs: {\n id: paletteId,\n bookId: proposal.bookId,\n name,\n status: \"active\",\n swatches,\n source,\n rationale: proposal.rationale,\n proposalId: proposal.id,\n approvalReceiptId: capString(approvalReceiptId, \"approvalReceiptId\", 200),\n approvalActionDigest: capString(\n approvalActionDigest,\n \"approvalActionDigest\",\n 80,\n ),\n audience: proposal.audience,\n createdAt: now,\n updatedAt: now,\n ...(seedHex ? { seedHex } : {}),\n },\n },\n { t: \"link\", ns: BRAND_NS.palette, id: paletteId, label: \"book\", target: proposal.bookId },\n ...upsertSectionOps({\n bookId: proposal.bookId,\n kind: \"palette\",\n content: { paletteId, name, swatches },\n status: \"approved\",\n audience: proposal.audience,\n updatedBy: resolvedBy,\n approvalReceiptId,\n approvalActionDigest,\n now,\n }),\n {\n t: \"update\",\n ns: BRAND_NS.book,\n id: proposal.bookId,\n attrs: { activePaletteId: paletteId, updatedAt: now },\n },\n {\n t: \"update\",\n ns: BRAND_NS.proposal,\n id: proposal.id,\n attrs: {\n status: \"accepted\",\n resolvedBy,\n resolvedAt: now,\n ...(input.resolutionNote ? { resolutionNote: input.resolutionNote } : {}),\n },\n },\n ];\n}\n\n/** Input to {@link rejectProposalOps}. */\nexport interface RejectProposalInput {\n proposal: BrandProposal;\n resolvedBy: string;\n now: number;\n resolutionNote?: string;\n}\n\n/**\n * Ops to reject an OPEN proposal (any kind): flip it to `rejected` with\n * resolver, timestamp, and the optional note. Nothing else is touched — the\n * proposal row itself is the audit trail.\n */\nexport function rejectProposalOps(input: RejectProposalInput): BrandOp[] {\n const { proposal, resolvedBy, now } = input;\n if (proposal.status !== \"open\")\n throw new BrandInputError(`proposal ${proposal.id} is ${proposal.status}, not open`);\n return [\n {\n t: \"update\",\n ns: BRAND_NS.proposal,\n id: proposal.id,\n attrs: {\n status: \"rejected\",\n resolvedBy,\n resolvedAt: now,\n ...(input.resolutionNote ? { resolutionNote: input.resolutionNote } : {}),\n },\n },\n ];\n}\n","// Pure op-builders for brand_asset rows. Asset rows are worker-mediated\n// (rules deny everything): the caller uploads to storage FIRST, then commits\n// the mirroring row — and \"delete\" is a `deletedAt` tombstone (an attr-merge\n// `update`; odla-db's `merge` op is json-only), never a row delete, so\n// analyses and proposals that reference the asset stay coherent.\nimport { ASSET_KINDS, BRAND_NS, type AssetKind } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport { brandJsonDigest } from \"../review\";\nimport type { BrandEntityRef, BrandOp } from \"../types\";\nimport { assertAnalysis, assertAssetContentType, capString } from \"../validate\";\n\n/** Input to {@link createAssetOps} — the storage upload's receipt fields\n * (`path`/`size`) plus the declared kind and the book's audience. */\nexport interface CreateAssetInput {\n id: string;\n bookId: string;\n kind: AssetKind;\n path: string;\n storageObjectId: string;\n contentDigest: string;\n contentType: string;\n size: number;\n uploadedBy: string;\n uploadedAuthorityRef: string;\n audience: string[];\n title?: string;\n now: number;\n}\n\n/**\n * Ops to record one uploaded asset: a single `brand_asset` row mirroring the\n * storage object, with the content type re-checked against the allowlist and\n * the size required to be a positive byte count.\n */\nexport function createAssetOps(input: CreateAssetInput): BrandOp[] {\n if (!(ASSET_KINDS as readonly string[]).includes(input.kind))\n throw new BrandInputError(`kind must be one of: ${ASSET_KINDS.join(\", \")}`);\n const contentType = assertAssetContentType(input.contentType);\n if (typeof input.size !== \"number\" || !Number.isFinite(input.size) || input.size <= 0)\n throw new BrandInputError(\"size must be a positive byte count\");\n if (!/^sha256:[0-9a-f]{64}$/.test(input.contentDigest))\n throw new BrandInputError(\"contentDigest must be a SHA-256 digest\");\n const title = input.title === undefined ? undefined : capString(input.title, \"title\", 160);\n return [\n {\n t: \"update\",\n ns: BRAND_NS.asset,\n id: input.id,\n attrs: {\n id: input.id,\n bookId: input.bookId,\n kind: input.kind,\n path: capString(input.path, \"path\", 512),\n storageObjectId: capString(input.storageObjectId, \"storageObjectId\", 200),\n contentDigest: capString(input.contentDigest, \"contentDigest\", 80),\n contentType,\n size: input.size,\n status: \"live\",\n analysisRevision: 0,\n audience: input.audience,\n uploadedBy: input.uploadedBy,\n uploadedAuthorityRef: capString(\n input.uploadedAuthorityRef,\n \"uploadedAuthorityRef\",\n 200,\n ),\n createdAt: input.now,\n ...(title ? { title } : {}),\n },\n },\n { t: \"link\", ns: BRAND_NS.asset, id: input.id, label: \"book\", target: input.bookId },\n ];\n}\n\n/**\n * Ops to tombstone an asset after its storage object was deleted: stamp\n * `deletedAt` in place. List reads exclude tombstoned rows; the row itself\n * stays for provenance.\n */\nexport function beginAssetDeleteOps(\n assetId: BrandEntityRef,\n now: number,\n deletedBy: string,\n deletedAuthorityRef: string,\n): BrandOp[] {\n return [{\n t: \"update\",\n ns: BRAND_NS.asset,\n id: assetId,\n attrs: {\n status: \"deleting\",\n deletedAt: now,\n deletedBy: capString(deletedBy, \"deletedBy\", 160),\n deletedAuthorityRef: capString(deletedAuthorityRef, \"deletedAuthorityRef\", 200),\n },\n }];\n}\n\n/** Complete a previously authorized deletion after storage is tombstoned. */\nexport function finishAssetDeleteOps(assetId: BrandEntityRef): BrandOp[] {\n return [{\n t: \"update\",\n ns: BRAND_NS.asset,\n id: assetId,\n attrs: { status: \"deleted\" },\n }];\n}\n\n/**\n * Ops to record an agent's analysis of an asset: the validated + capped\n * analysis json plus `analyzedAt`. Replaces any prior analysis whole.\n */\nexport async function recordAnalysisOps(\n assetId: BrandEntityRef,\n analysis: unknown,\n priorRevision: number,\n analyzedBy: string,\n analyzedAuthorityRef: string,\n now: number,\n): Promise<BrandOp[]> {\n if (!Number.isSafeInteger(priorRevision) || priorRevision < 0)\n throw new BrandInputError(\"prior analysis revision must be a non-negative integer\");\n const normalized = assertAnalysis(analysis);\n return [\n {\n t: \"update\",\n ns: BRAND_NS.asset,\n id: assetId,\n attrs: {\n analysis: normalized,\n analysisRevision: priorRevision + 1,\n analysisDigest: await brandJsonDigest(normalized),\n analyzedBy: capString(analyzedBy, \"analyzedBy\", 160),\n analyzedAuthorityRef: capString(\n analyzedAuthorityRef,\n \"analyzedAuthorityRef\",\n 200,\n ),\n analyzedAt: now,\n },\n },\n ];\n}\n","// Asset tools: view_asset feeds real uploaded bytes to the model as an\n// image/document block inside the tool result (the vision path), and\n// record_asset_analysis persists what the model saw through the validated\n// ops layer. view_asset output is model-visible content fetched from\n// storage, so the tool declares `tool_untrusted:view_asset` taint.\n// @odla-ai/ai is imported for types only.\nimport type { DocumentBlock, ImageBlock, ImageMediaType, TextBlock, ToolDef, ToolOutput } from \"@odla-ai/ai\";\nimport { BRAND_NS } from \"../constants\";\nimport { BrandNotFoundError } from \"../errors\";\nimport type { BrandAsset } from \"../types\";\nimport { assertAnalysis } from \"../validate\";\nimport type { BrandToolCtx } from \"./skill\";\n\n/** Byte cap for in-conversation asset viewing (4.5 MiB — providers reject\n * larger inline payloads well before context does). */\nexport const MAX_VIEW_BYTES = 4_718_592;\n\nconst IMAGE_TYPES: ReadonlySet<string> = new Set([\"image/png\", \"image/jpeg\", \"image/gif\", \"image/webp\"]);\n\n/**\n * Base64-encode bytes without assuming a platform: `btoa` over a chunked\n * binary string where available (workerd, browsers, Node ≥ 16), `Buffer`\n * otherwise. Chunking keeps `String.fromCharCode` off the argument-count\n * cliff for multi-megabyte assets.\n */\nexport function base64FromBytes(bytes: Uint8Array): string {\n if (typeof btoa === \"function\") {\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 0x2000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x2000));\n }\n return btoa(binary);\n }\n return Buffer.from(bytes).toString(\"base64\");\n}\n\nconst bareType = (ct: string): string => (ct.split(\";\")[0] ?? \"\").trim().toLowerCase();\n\nfunction viewOutput(asset: BrandAsset, bytes: Uint8Array, contentType: string): ToolOutput {\n const caption: TextBlock = {\n type: \"text\",\n text: `Asset ${asset.id} (${asset.kind}, ${contentType}, ${bytes.byteLength} bytes${asset.title ? `, \"${asset.title}\"` : \"\"}):`,\n };\n if (IMAGE_TYPES.has(contentType)) {\n const image: ImageBlock = {\n type: \"image\",\n source: { type: \"base64\", mediaType: contentType as ImageMediaType, data: base64FromBytes(bytes) },\n };\n return { content: [caption, image] };\n }\n const document: DocumentBlock = {\n type: \"document\",\n source: { type: \"base64\", mediaType: \"application/pdf\", data: base64FromBytes(bytes) },\n };\n return { content: [caption, document] };\n}\n\n/**\n * The asset tools, scoped to the context's book: `view_asset` (fetch the\n * stored bytes and return them as an image/PDF block, with size and type\n * gates) and `record_asset_analysis` (persist the model's description,\n * dominant colors, and tags onto the asset row).\n */\nexport function assetTools(ctx: BrandToolCtx): ToolDef[] {\n const loadAsset = async (assetId: string): Promise<BrandAsset> => {\n const book = await ctx.loadBook();\n const res = await ctx.db.query({\n [BRAND_NS.asset]: {\n $: { where: { id: assetId, bookId: ctx.bookId } },\n book: {},\n },\n });\n const row = (res[BRAND_NS.asset] ?? [])[0] as\n | (BrandAsset & { book?: Array<{ id: string }> })\n | undefined;\n if (\n !row ||\n row.status !== \"live\" ||\n row.deletedAt ||\n !Array.isArray(row.book) ||\n row.book.length !== 1 ||\n row.book[0]?.id !== book.id\n ) throw new BrandNotFoundError(`asset ${assetId}`);\n return row;\n };\n\n const viewAsset: ToolDef = {\n name: \"view_asset\",\n description:\n \"Look at an uploaded asset: fetches its bytes and returns the image (png/jpeg/gif/webp) or PDF for you to view. Other types cannot be viewed in-conversation.\",\n inputSchema: {\n type: \"object\",\n required: [\"assetId\"],\n properties: { assetId: { type: \"string\", description: \"The asset row id from list_assets.\" } },\n },\n outputTaint: [\"tool_untrusted:view_asset\"],\n handler: ctx.guard(async (input) => {\n const asset = await loadAsset(String(input.assetId));\n if (!ctx.visionInToolResults) {\n return {\n content:\n `This model cannot take images inside tool results. Asset ${asset.id} must be attached ` +\n \"as a pre-turn image by the host instead — ask the human to re-send their message \" +\n \"referencing the asset (the dispatcher attaches it up front), or describe it from \" +\n \"what they tell you.\",\n };\n }\n const read = await ctx.authority(\"brand.read\");\n const fetched = await ctx.readAssetContent(asset.id);\n if (fetched.bytes.byteLength > MAX_VIEW_BYTES) {\n return {\n content:\n `Asset ${asset.id} is ${fetched.bytes.byteLength} bytes — over the ${MAX_VIEW_BYTES}-byte ` +\n \"(4.5 MB) in-conversation viewing cap. Ask the human for a smaller export of this file.\",\n };\n }\n const served = bareType(fetched.contentType);\n const effective = IMAGE_TYPES.has(served) || served === \"application/pdf\" ? served : bareType(asset.contentType);\n if (!IMAGE_TYPES.has(effective) && effective !== \"application/pdf\") {\n return {\n content:\n `Asset ${asset.id} is ${effective} — stored but not viewable in-conversation. ` +\n \"Ask the human to describe it, or to upload a PNG/JPEG export you can view.\",\n };\n }\n return viewOutput(asset, fetched.bytes, effective);\n }),\n };\n\n const recordAnalysis: ToolDef = {\n name: \"record_asset_analysis\",\n description:\n \"Record what you observed in an asset you viewed. Uses guarded analysis revisions so concurrent agents cannot overwrite each other silently.\",\n acceptsTaint: [\"tool_untrusted:view_asset\"],\n inputSchema: {\n type: \"object\",\n required: [\"assetId\", \"description\", \"dominantColors\", \"tags\"],\n properties: {\n assetId: { type: \"string\" },\n description: { type: \"string\", description: \"What the asset shows (max 2000 chars).\" },\n dominantColors: { type: \"array\", items: { type: \"string\" }, maxItems: 12, description: \"Dominant colors as hex.\" },\n tags: { type: \"array\", items: { type: \"string\" }, maxItems: 24 },\n },\n },\n handler: ctx.guard(async (input) => {\n const asset = await loadAsset(String(input.assetId));\n await ctx.authority(\"brand.edit\");\n const analysis = assertAnalysis({\n description: input.description,\n dominantColors: input.dominantColors,\n tags: input.tags,\n });\n const updated = await ctx.recordAssetAnalysis({\n mutationId: ctx.newId(),\n assetId: asset.id,\n analysis,\n expectedAnalysisRevision: asset.analysisRevision,\n });\n if (\n updated.id !== asset.id ||\n updated.bookId !== ctx.bookId ||\n updated.status !== \"live\" ||\n updated.analysisRevision !== asset.analysisRevision + 1 ||\n updated.analyzedBy !== ctx.self.selfId\n ) throw new BrandNotFoundError(\"asset analysis bridge returned invalid state\");\n return {\n content: `Recorded analysis for asset ${asset.id}: ${analysis.dominantColors.length} dominant color(s), ${analysis.tags.length} tag(s).`,\n };\n }),\n };\n\n return [viewAsset, recordAnalysis];\n}\n","import { BRAND_NS } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport type { BrandBook } from \"../types\";\nimport { capString } from \"../validate\";\nimport type { BrandToolCtx } from \"./skill\";\n\n/** Validate an optional proposal source against the exact live linked book. */\nexport async function proposalSourceAssetId(\n ctx: BrandToolCtx,\n book: BrandBook,\n value: unknown,\n): Promise<string | undefined> {\n if (value === undefined) return undefined;\n const sourceAssetId = capString(value, \"sourceAssetId\", 200);\n const result = await ctx.db.query({\n [BRAND_NS.asset]: {\n $: {\n where: { id: sourceAssetId, bookId: book.id, status: \"live\" },\n limit: 2,\n },\n book: { $: { limit: 2 } },\n },\n });\n const rows = result[BRAND_NS.asset] ?? [];\n const asset = rows.length === 1\n ? rows[0] as {\n id?: string;\n bookId?: string;\n status?: string;\n deletedAt?: number;\n book?: Array<{ id: string }>;\n }\n : undefined;\n if (\n !asset ||\n asset.id !== sourceAssetId ||\n asset.bookId !== book.id ||\n asset.status !== \"live\" ||\n asset.deletedAt !== undefined ||\n !Array.isArray(asset.book) ||\n asset.book.length !== 1 ||\n asset.book[0]?.id !== book.id\n ) throw new BrandInputError(\n \"sourceAssetId must be a live asset in this brand book\",\n );\n return sourceAssetId;\n}\n","// Non-palette brand-facet proposal tool. Agent-authored changes never touch\n// the live natural-key section; a human decision route applies accepted\n// content as an approved section with a durable receipt.\nimport type { ToolDef } from \"@odla-ai/ai\";\nimport {\n SECTION_KINDS,\n type SectionKind,\n} from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport { assertSectionContent, capString } from \"../validate\";\nimport type { BrandToolCtx } from \"./skill\";\nimport { proposalSourceAssetId } from \"./source-asset\";\n\nconst PROPOSABLE = SECTION_KINDS.filter((kind) => kind !== \"palette\");\n\n/** `update_section` validates a draft and parks it as an OPEN proposal. */\nexport function bookTools(ctx: BrandToolCtx): ToolDef[] {\n return [{\n name: \"update_section\",\n description:\n \"Propose a typography, voice, logo, or imagery section revision for human approval. This never overwrites the live approved section.\",\n acceptsTaint: [\"tool_untrusted:view_asset\"],\n inputSchema: {\n type: \"object\",\n required: [\"kind\", \"content\", \"rationale\"],\n properties: {\n kind: { type: \"string\", enum: PROPOSABLE },\n content: { type: \"object\", description: \"The complete proposed section payload.\" },\n rationale: { type: \"string\", description: \"Why this revision should replace the live section.\" },\n sourceAssetId: {\n type: \"string\",\n description: \"Optional exact live Brand asset that grounds this revision.\",\n },\n },\n },\n handler: ctx.guard(async (input) => {\n const allowed = new Set([\"kind\", \"content\", \"rationale\", \"sourceAssetId\"]);\n if (Object.keys(input).some((key) => !allowed.has(key)))\n throw new BrandInputError(\"section proposal has unknown fields\");\n const book = await ctx.loadBook();\n await ctx.authority(\"brand.edit\");\n const kind = input.kind as SectionKind;\n if (kind === \"palette\" || !PROPOSABLE.includes(kind))\n throw new BrandInputError(`kind must be one of: ${PROPOSABLE.join(\", \")}`);\n const rationale = capString(input.rationale, \"rationale\", 2_000);\n const sourceAssetId = await proposalSourceAssetId(\n ctx,\n book,\n input.sourceAssetId,\n );\n const proposal = await ctx.createProposal({\n mutationId: ctx.newId(),\n kind,\n payload: {\n content: assertSectionContent(kind, input.content),\n },\n rationale,\n ...(sourceAssetId ? { sourceAssetId } : {}),\n });\n if (\n proposal.bookId !== book.id ||\n proposal.createdBy !== ctx.self.selfId ||\n proposal.kind !== kind ||\n proposal.status !== \"open\"\n ) throw new BrandInputError(\"brand proposal bridge returned an invalid proposal\");\n return {\n content:\n `Parked ${kind} section proposal ${proposal.id}. The live section is unchanged; ` +\n \"a human must approve this exact revision.\",\n };\n }),\n }];\n}\n","// Color-exploration + proposal tools. analyze_color / evaluate_contrast are\n// pure math over the color engine (the agent's grounding for every hex it\n// suggests); propose_palette PARKS a proposal for human review — it never\n// activates anything. Proposal resolution is intentionally absent from the\n// agent skill; a human uses createBrandRoutes' guarded approval endpoint.\nimport type { ToolDef } from \"@odla-ai/ai\";\nimport {\n analogous,\n complementary,\n contrastRatio,\n derivePalette,\n hexToOklch,\n meetsAA,\n meetsAAA,\n monochrome,\n nearestNamedColor,\n pickTextOn,\n relativeLuminance,\n splitComplementary,\n tetradic,\n tintShadeRamp,\n triadic,\n} from \"../color/index\";\nimport { BrandInputError } from \"../errors\";\nimport type { Swatch, SwatchRole } from \"../types\";\nimport { assertHex, assertSwatches, capString } from \"../validate\";\nimport type { BrandToolCtx } from \"./skill\";\nimport { proposalSourceAssetId } from \"./source-asset\";\n\nconst r2 = (n: number): string => n.toFixed(2);\nconst pf = (ok: boolean): string => (ok ? \"pass\" : \"FAIL\");\n\nconst verdict = (ratio: number): string =>\n `${r2(ratio)}:1 — AA text ${pf(meetsAA(ratio))}, AA large/ui ${pf(meetsAA(ratio, \"large-text\"))}, AAA text ${pf(meetsAAA(ratio))}`;\n\n/** Harmony strategies propose_palette accepts, mapped to the seed companions\n * that replace the derived secondary/highlight (in that order). */\nconst HARMONY_COMPANIONS: Record<string, (seed: string) => string[]> = {\n complementary: (s) => [complementary(s)],\n analogous: (s) => [...analogous(s)],\n triadic: (s) => [...triadic(s)],\n split: (s) => [...splitComplementary(s)],\n tetradic: (s) => tetradic(s).slice(0, 2),\n monochrome: (s) => monochrome(s, 4).slice(1, 3),\n};\n\nfunction applyHarmony(swatches: Swatch[], seedHex: string, harmony: unknown): Swatch[] {\n if (typeof harmony !== \"string\" || !(harmony in HARMONY_COMPANIONS)) {\n throw new BrandInputError(`harmony must be one of: ${Object.keys(HARMONY_COMPANIONS).join(\", \")}`);\n }\n const [secondary, highlight] = HARMONY_COMPANIONS[harmony]!(seedHex);\n return swatches.map((s) => {\n const hex = s.role === \"secondary\" ? secondary : s.role === \"highlight\" ? highlight : undefined;\n if (!hex) return s;\n return { ...s, hex, name: nearestNamedColor(hex).name, rationale: `${harmony} companion of the seed` };\n });\n}\n\n/** WCAG ratios (2 dp) for the palette's key role pairs — stored verbatim in\n * the proposal payload so the human reviews numbers, not vibes. */\nfunction contrastReport(swatches: Swatch[]): Record<string, number> {\n const byRole = (role: SwatchRole): string | undefined => swatches.find((s) => s.role === role)?.hex;\n const bg = byRole(\"bg\") ?? \"#ffffff\";\n const report: Record<string, number> = {};\n const put = (label: string, fg?: string): void => {\n if (fg) report[label] = Math.round(contrastRatio(fg, bg) * 100) / 100;\n };\n put(\"text-on-bg\", byRole(\"text\"));\n put(\"primary-on-bg\", byRole(\"primary\"));\n put(\"good-on-bg\", byRole(\"good\"));\n put(\"warn-on-bg\", byRole(\"warn\"));\n put(\"danger-on-bg\", byRole(\"danger\"));\n const primary = byRole(\"primary\");\n if (primary) report[\"text-on-primary\"] = Math.round(contrastRatio(pickTextOn(primary), primary) * 100) / 100;\n return report;\n}\n\nconst INCLUDE_SECTIONS = [\"harmony\", \"ramp\"] as const;\n\nfunction analyzeLines(hex: string, include: string[]): string[] {\n const lch = hexToOklch(hex);\n const named = nearestNamedColor(hex);\n const lines = [\n `${hex} — nearest CSS name: ${named.name} (ΔEOK ${named.deltaEOK.toFixed(3)})`,\n `OKLCH: L ${lch.L.toFixed(3)}, C ${lch.C.toFixed(3)}, h ${lch.h.toFixed(1)}°`,\n `relative luminance ${relativeLuminance(hex).toFixed(3)}; contrast ${r2(contrastRatio(hex, \"#ffffff\"))}:1 on white, ${r2(contrastRatio(hex, \"#000000\"))}:1 on black`,\n `readable text on it: ${pickTextOn(hex)}`,\n ];\n if (include.includes(\"harmony\")) {\n const [aMinus, aPlus] = analogous(hex);\n const [tMinus, tPlus] = triadic(hex);\n const [sMinus, sPlus] = splitComplementary(hex);\n lines.push(\n `harmony — complementary ${complementary(hex)}; analogous ${aMinus} ${aPlus}; triadic ${tMinus} ${tPlus}; split ${sMinus} ${sPlus}`,\n );\n }\n if (include.includes(\"ramp\")) lines.push(`ramp — ${tintShadeRamp(hex).join(\" \")}`);\n return lines;\n}\n\n/**\n * The palette tools: `analyze_color`, `evaluate_contrast` (pure math),\n * `propose_palette` (writes an OPEN proposal with an automatic contrast\n * report). Resolution is deliberately not an agent tool.\n */\nexport function paletteTools(ctx: BrandToolCtx): ToolDef[] {\n const analyzeColor: ToolDef = {\n name: \"analyze_color\",\n description:\n \"Analyze one color: nearest CSS name, OKLCH coordinates, luminance, contrast on white/black. Optionally include harmony companions and a tint/shade ramp.\",\n inputSchema: {\n type: \"object\",\n required: [\"hex\"],\n properties: {\n hex: { type: \"string\", description: \"#rgb or #rrggbb\" },\n include: { type: \"array\", items: { type: \"string\", enum: [...INCLUDE_SECTIONS] } },\n },\n },\n handler: ctx.guard(async (input) => {\n const hex = assertHex(input.hex, \"hex\");\n const include = input.include === undefined ? [] : input.include;\n if (!Array.isArray(include) || include.some((s) => !(INCLUDE_SECTIONS as readonly unknown[]).includes(s))) {\n throw new BrandInputError(`include entries must be one of: ${INCLUDE_SECTIONS.join(\", \")}`);\n }\n return { content: analyzeLines(hex, include as string[]).join(\"\\n\") };\n }),\n };\n\n const evaluateContrast: ToolDef = {\n name: \"evaluate_contrast\",\n description:\n \"WCAG 2.1 contrast: pass pairs ([{fg,bg}]) for specific combinations, or hexes ([…]) for every pairwise ratio. Reports AA/AAA verdicts.\",\n inputSchema: {\n type: \"object\",\n properties: {\n pairs: {\n type: \"array\",\n maxItems: 20,\n items: { type: \"object\", required: [\"fg\", \"bg\"], properties: { fg: { type: \"string\" }, bg: { type: \"string\" } } },\n },\n hexes: { type: \"array\", minItems: 2, maxItems: 8, items: { type: \"string\" } },\n },\n },\n handler: ctx.guard(async (input) => {\n if (Array.isArray(input.pairs) && input.pairs.length > 0) {\n if (input.pairs.length > 20) throw new BrandInputError(\"pairs must have at most 20 entries\");\n const lines = input.pairs.map((raw, i) => {\n const p = (raw ?? {}) as Record<string, unknown>;\n const fg = assertHex(p.fg, `pairs[${i}].fg`);\n const bg = assertHex(p.bg, `pairs[${i}].bg`);\n return `${fg} on ${bg}: ${verdict(contrastRatio(fg, bg))}`;\n });\n return { content: lines.join(\"\\n\") };\n }\n if (Array.isArray(input.hexes)) {\n if (input.hexes.length < 2 || input.hexes.length > 8) {\n throw new BrandInputError(\"hexes must have 2 to 8 entries\");\n }\n const hexes = input.hexes.map((h, i) => assertHex(h, `hexes[${i}]`));\n const lines: string[] = [];\n for (let i = 0; i < hexes.length; i++) {\n for (let j = i + 1; j < hexes.length; j++) {\n lines.push(`${hexes[i]} vs ${hexes[j]}: ${verdict(contrastRatio(hexes[i]!, hexes[j]!))}`);\n }\n }\n return { content: lines.join(\"\\n\") };\n }\n throw new BrandInputError(\"provide pairs ([{fg,bg}, …]) or hexes ([#rrggbb, …])\");\n }),\n };\n\n const proposePalette: ToolDef = {\n name: \"propose_palette\",\n description:\n \"Park a palette proposal for human review (does NOT change the brand). Pass explicit swatches, or a seedHex (and optional harmony) to derive a full palette. A WCAG contrast report is attached automatically.\",\n acceptsTaint: [\"tool_untrusted:view_asset\"],\n inputSchema: {\n type: \"object\",\n required: [\"name\", \"rationale\"],\n properties: {\n name: { type: \"string\" },\n rationale: { type: \"string\", description: \"Why these colors — cite assets, harmony, contrast.\" },\n seedHex: { type: \"string\" },\n harmony: { type: \"string\", enum: Object.keys(HARMONY_COMPANIONS) },\n sourceAssetId: {\n type: \"string\",\n description: \"Optional exact asset id that grounded this palette.\",\n },\n swatches: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"role\", \"hex\"],\n properties: {\n role: { type: \"string\" },\n hex: { type: \"string\" },\n name: { type: \"string\" },\n rationale: { type: \"string\" },\n },\n },\n },\n },\n },\n handler: ctx.guard(async (input, toolCtx) => {\n const book = await ctx.loadBook();\n await ctx.authority(\"brand.edit\");\n const name = capString(input.name, \"name\", 120);\n const rationale = capString(input.rationale, \"rationale\", 2_000);\n const sourceAssetId = await proposalSourceAssetId(\n ctx,\n book,\n input.sourceAssetId,\n );\n const seedHex = input.seedHex === undefined ? undefined : assertHex(input.seedHex, \"seedHex\");\n let swatches: Swatch[];\n if (input.swatches !== undefined) {\n swatches = assertSwatches(input.swatches);\n } else {\n if (!seedHex) throw new BrandInputError(\"provide swatches, or a seedHex to derive a palette from\");\n swatches = derivePalette(seedHex);\n if (input.harmony !== undefined) swatches = applyHarmony(swatches, seedHex, input.harmony);\n }\n const report = contrastReport(swatches);\n const proposal = await ctx.createProposal({\n mutationId: ctx.newId(),\n kind: \"palette\",\n payload: {\n name,\n swatches,\n ...(seedHex ? { seedHex } : {}),\n contrastReport: report,\n },\n rationale,\n ...(sourceAssetId ? { sourceAssetId } : {}),\n });\n if (\n proposal.bookId !== book.id ||\n proposal.createdBy !== ctx.self.selfId ||\n proposal.kind !== \"palette\" ||\n proposal.status !== \"open\"\n ) throw new BrandInputError(\"brand proposal bridge returned an invalid proposal\");\n const reportText = Object.entries(report).map(([k, v]) => `${k} ${r2(v)}:1`).join(\", \");\n return {\n content:\n `Parked palette proposal ${proposal.id} (\"${name}\", ${swatches.length} swatches` +\n `${seedHex ? `, seeded from ${seedHex}` : \"\"}). Contrast: ${reportText}. ` +\n \"Awaiting a human decision in the brand approval surface.\",\n };\n }),\n };\n\n return [analyzeColor, evaluateContrast, proposePalette];\n}\n","// Read-only brand tools: a compact structured-text snapshot of the book\n// (read_brand_book) and the live asset list (list_assets). Deterministic, no\n// AI calls, no writes — the agent's orientation step before it proposes\n// anything. @odla-ai/ai is imported for types only.\nimport type { ToolDef } from \"@odla-ai/ai\";\nimport { ASSET_KINDS, BRAND_NS } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport type { BrandAsset, BrandBook, BrandPalette, BrandProposal, BrandSection } from \"../types\";\nimport type { BrandToolCtx } from \"./skill\";\nimport type { BrandPrincipalProjection } from \"./skill\";\n\nconst iso = (ms: number): string => new Date(ms).toISOString();\n\nconst shortId = (id: string): string =>\n id.length <= 12 ? id : `${id.slice(0, 6)}…${id.slice(-4)}`;\nconst principalLabel = (\n id: string,\n directory: Map<string, BrandPrincipalProjection>,\n): string => {\n const value = directory.get(id);\n return value\n ? `${value.displayName} [${value.kind} · ${shortId(id)}]`\n : `Unknown principal [${shortId(id)}]`;\n};\n\nfunction bookLines(\n book: BrandBook,\n directory: Map<string, BrandPrincipalProjection>,\n): string[] {\n const lines = [\n `brand book \"${book.name}\" (${book.slug}) — ${book.status}`,\n `members: ${book.memberIds.map((id) => principalLabel(id, directory)).join(\", \")}`,\n `active palette: ${book.activePaletteId ?? \"(none accepted yet)\"}`,\n book.tokens\n ? `tokens: compiled ${iso(book.tokens.compiledAt)} with ${book.tokens.warnings.length} warning(s)`\n : \"tokens: (not compiled)\",\n ];\n if (book.summary) lines.push(`summary: ${book.summary}`);\n return lines;\n}\n\nfunction childLines(\n sections: BrandSection[],\n palettes: BrandPalette[],\n proposals: BrandProposal[],\n directory: Map<string, BrandPrincipalProjection>,\n): string[] {\n return [\n \"sections:\",\n ...(sections.length\n ? sections.map((s) =>\n `- ${s.kind}: ${s.status}, updated ${iso(s.updatedAt)} by ` +\n principalLabel(s.updatedBy, directory))\n : [\"- (none)\"]),\n \"palettes:\",\n ...(palettes.length\n ? palettes.map((p) => `- ${p.id} \"${p.name}\" (${p.status}, ${p.source}, ${p.swatches.length} swatches)`)\n : [\"- (none)\"]),\n \"open proposals:\",\n ...(proposals.length\n ? proposals.map((p) =>\n `- ${p.id} (${p.kind}) by ${principalLabel(p.createdBy, directory)}: ${p.rationale}`)\n : [\"- (none)\"]),\n ];\n}\n\n/**\n * The two read-only tools, scoped to the context's book:\n * `read_brand_book` (book + sections + palettes + open proposals as compact\n * text) and `list_assets` (live, non-tombstoned asset rows, optionally\n * filtered by kind).\n */\nexport function readTools(ctx: BrandToolCtx): ToolDef[] {\n const readBrandBook: ToolDef = {\n name: \"read_brand_book\",\n description:\n \"Read the current brand book: status, members, active palette, compiled tokens, sections, palettes, and open proposals.\",\n inputSchema: { type: \"object\", properties: {} },\n handler: ctx.guard(async () => {\n const authorizedBook = await ctx.loadBook();\n const res = await ctx.db.query({\n [BRAND_NS.section]: {\n $: { where: { bookId: ctx.bookId }, order: { updatedAt: \"asc\" } },\n book: {},\n },\n [BRAND_NS.palette]: {\n $: { where: { bookId: ctx.bookId }, order: { createdAt: \"asc\" } },\n book: {},\n },\n [BRAND_NS.proposal]: {\n $: {\n where: { bookId: ctx.bookId, status: \"open\" },\n order: { createdAt: \"asc\" },\n },\n book: {},\n },\n });\n const linked = <T extends { bookId: string; book?: Array<{ id: string }> }>(\n rows: unknown[],\n ): T[] => (rows as T[]).filter((row) =>\n row.bookId === authorizedBook.id &&\n Array.isArray(row.book) &&\n row.book.length === 1 &&\n row.book[0]?.id === authorizedBook.id);\n const sections = linked<BrandSection & { book?: Array<{ id: string }> }>(\n res[BRAND_NS.section] ?? [],\n );\n const palettes = linked<BrandPalette & { book?: Array<{ id: string }> }>(\n res[BRAND_NS.palette] ?? [],\n );\n const proposals = linked<BrandProposal & { book?: Array<{ id: string }> }>(\n res[BRAND_NS.proposal] ?? [],\n );\n const ids = [\n ...authorizedBook.memberIds,\n ...sections.map((section) => section.updatedBy),\n ...proposals.map((proposal) => proposal.createdBy),\n ];\n const directory = new Map(\n (await ctx.resolvePrincipals(ids)).map((principal) => [principal.id, principal]),\n );\n return {\n content: [\n ...bookLines(authorizedBook, directory),\n ...childLines(sections, palettes, proposals, directory),\n ].join(\"\\n\"),\n };\n }),\n };\n\n const listAssets: ToolDef = {\n name: \"list_assets\",\n description:\n \"List the book's uploaded assets (id, kind, content type, size, title, analysis state). Tombstoned assets are excluded.\",\n inputSchema: {\n type: \"object\",\n properties: {\n kind: { type: \"string\", enum: [...ASSET_KINDS], description: \"Only assets of this kind.\" },\n },\n },\n handler: ctx.guard(async (input) => {\n await ctx.loadBook();\n const where: Record<string, unknown> = { bookId: ctx.bookId, status: \"live\" };\n if (input.kind !== undefined) {\n if (typeof input.kind !== \"string\" || !(ASSET_KINDS as readonly string[]).includes(input.kind)) {\n throw new BrandInputError(`kind must be one of: ${ASSET_KINDS.join(\", \")}`);\n }\n where.kind = input.kind;\n }\n const res = await ctx.db.query({\n [BRAND_NS.asset]: {\n $: { where, order: { createdAt: \"asc\" } },\n book: {},\n },\n });\n const rows = ((res[BRAND_NS.asset] ?? []) as Array<\n BrandAsset & { book?: Array<{ id: string }> }\n >).filter((asset) =>\n asset.bookId === ctx.bookId &&\n Array.isArray(asset.book) &&\n asset.book.length === 1 &&\n asset.book[0]?.id === ctx.bookId);\n if (rows.length === 0) {\n return { content: input.kind ? `(no ${String(input.kind)} assets uploaded yet)` : \"(no assets uploaded yet)\" };\n }\n const lines = rows.map(\n (a) =>\n `${a.id} — ${a.kind}, ${a.contentType}, ${a.size} bytes` +\n `${a.title ? `, \"${a.title}\"` : \"\"}${a.analysis ? \" (analyzed)\" : \" (not analyzed)\"}`,\n );\n return { content: lines.join(\"\\n\") };\n }),\n };\n\n return [readBrandBook, listAssets];\n}\n","// The @odla-ai/ai Skill assembly for a brand book: one shared tool context\n// (injected db + identity + defaults), the workflow instructions, and the\n// tools from the four tool modules. @odla-ai/ai is an optional peer imported\n// for TYPES ONLY (chat's pattern) — the package works without it installed.\n//\n// Error contract with the agent loop: runAgent converts a handler throw into\n// a SANITIZED error tool_result (`Tool \"x\" failed.`) because arbitrary\n// handler messages may carry credentials. Brand's own validation errors are\n// crafted, secret-free, and actionable, so `guard` catches BrandInputError /\n// BrandNotFoundError and returns the message as an error output the model can\n// act on; anything unexpected still propagates into the loop's sanitizer.\nimport type { Skill, ToolHandler } from \"@odla-ai/ai\";\nimport { BRAND_NS } from \"../constants\";\nimport { resolveDeps, type BrandFetchedBytes } from \"../deps\";\nimport { BrandForbiddenError, BrandInputError, BrandNotFoundError } from \"../errors\";\nimport type {\n AssetAnalysis,\n BrandAsset,\n BrandBook,\n BrandDb,\n BrandProposal,\n} from \"../types\";\nimport type { ProposalKind } from \"../constants\";\nimport { assetTools } from \"./asset-tools\";\nimport { bookTools } from \"./book-tools\";\nimport { paletteTools } from \"./palette-tools\";\nimport { readTools } from \"./read-tools\";\nimport type {\n BrandCapability,\n BrandCapabilityAuthority,\n BrandPrincipalProjection,\n} from \"./agent-types\";\n\nexport type {\n BrandCapability,\n BrandCapabilityAuthority,\n BrandPrincipalProjection,\n} from \"./agent-types\";\n\n/** The bot identity the skill writes as (`selfId` = the agent id carried in\n * the book's `memberIds` roster and every audience snapshot). */\nexport interface BrandSkillSelf {\n selfId: string;\n kind: \"bot\";\n displayName?: string;\n}\n\n/** Server-enforced semantic bridge. Raw agent credentials must be denied all\n * Brand namespace writes and raw file operations. */\nexport interface BrandAgentBridge {\n createProposal(input: {\n jobId: string;\n bookId: string;\n mutationId: string;\n kind: ProposalKind;\n payload: Record<string, unknown>;\n rationale: string;\n sourceAssetId?: string;\n }): Promise<BrandProposal>;\n recordAssetAnalysis(input: {\n jobId: string;\n mutationId: string;\n bookId: string;\n assetId: string;\n analysis: AssetAnalysis;\n expectedAnalysisRevision: number;\n }): Promise<BrandAsset>;\n readAssetContent(input: {\n jobId: string;\n bookId: string;\n assetId: string;\n }): Promise<BrandFetchedBytes>;\n}\n\n/** Options for {@link brandSkill}. */\nexport interface BrandSkillOpts {\n /** The injected odla client (a real @odla-ai/db AdminDb satisfies it). */\n db: BrandDb;\n /** The one brand book this skill instance is scoped to. */\n bookId: string;\n /** The bot identity acting through these tools. */\n self: BrandSkillSelf;\n /** Host attestation for the rules-scoped credential behind `db`. */\n agentDbBinding: { principalId: string; credentialRef: string };\n /** Active verified agent job; the bridge derives message/turn provenance. */\n agentJobId: string;\n agentBridge: BrandAgentBridge;\n /** Host verification against the live principal grant. Missing/denied hooks\n * fail closed; roster membership is visibility, not authority. */\n authorizeCapability: (input: {\n agentId: string;\n bookId: string;\n capability: BrandCapability;\n }) => Promise<BrandCapabilityAuthority | null> | BrandCapabilityAuthority | null;\n /** Bounded host directory projection for conversational display only. */\n resolvePrincipals: (input: {\n requesterAgentId: string;\n bookId: string;\n principalIds: string[];\n }) => Promise<BrandPrincipalProjection[]>;\n /** False when the model cannot take image/document blocks inside a\n * tool_result — view_asset then steers to the pre-turn attachment path. */\n visionInToolResults?: boolean;\n /** Clock override (tests). */\n now?: () => number;\n /** Id factory override (tests). */\n newId?: () => string;\n}\n\n/** The resolved context every brand tool module builds its tools from. */\nexport interface BrandToolCtx {\n db: BrandDb;\n bookId: string;\n self: BrandSkillSelf;\n /** Whether image/document blocks may be returned inside tool results. */\n visionInToolResults: boolean;\n now: () => number;\n newId: () => string;\n agentJobId: string;\n createProposal(input: {\n mutationId: string;\n kind: ProposalKind;\n payload: Record<string, unknown>;\n rationale: string;\n sourceAssetId?: string;\n }): Promise<BrandProposal>;\n recordAssetAnalysis(input: {\n mutationId: string;\n assetId: string;\n analysis: AssetAnalysis;\n expectedAnalysisRevision: number;\n }): Promise<BrandAsset>;\n readAssetContent(assetId: string): Promise<BrandFetchedBytes>;\n resolvePrincipals(ids: string[]): Promise<BrandPrincipalProjection[]>;\n authority(capability: BrandCapability): Promise<BrandCapabilityAuthority>;\n /** Load the scoped book row; throws BrandNotFoundError when missing. */\n loadBook(): Promise<BrandBook>;\n /** Wrap a handler so Brand validation errors come back as actionable\n * error text instead of the loop's sanitized generic failure. */\n guard(handler: ToolHandler): ToolHandler;\n}\n\n/** Workflow guidance appended to the persona's system prompt as the skill's\n * instruction section. */\nexport const BRAND_INSTRUCTIONS =\n \"You help build and maintain ONE brand book. Workflow, in order:\\n\" +\n \"1. Understand the brand first: read_brand_book and list_assets before proposing anything.\\n\" +\n \"2. Look at the real material: view_asset on logos and inspiration, then record what you \" +\n \"saw with record_asset_analysis (description, dominant colors as hex, tags).\\n\" +\n \"3. Explore with the math tools: analyze_color and evaluate_contrast. Never invent a hex \" +\n \"without a rationale — ground every color in an asset's dominant color, a harmony \" +\n \"companion, or a contrast fix, and say which.\\n\" +\n \"4. propose_palette parks a proposal for review. It does NOT change the brand.\\n\" +\n \"5. You cannot approve or resolve a proposal. Direct the human to the brand approval \" +\n \"surface, which records a guarded receipt for their decision.\\n\" +\n \"6. update_section parks a proposal; it never overwrites an approved facet. Bind \" +\n \"sourceAssetId when a real Brand asset grounds typography, voice, logo, or imagery. Human \" +\n \"acceptance applies the exact reviewed change and automatically recompiles dependent tokens.\\n\" +\n \"7. Re-read the book after a decision and explain any compiler warnings conversationally.\";\n\n/**\n * Build the brand Skill: read/asset/palette/book tools scoped to one book,\n * acting as one bot identity, plus {@link BRAND_INSTRUCTIONS}. Attach it to\n * a Persona (or use `createBrandPersona`).\n */\nexport function brandSkill(opts: BrandSkillOpts): Skill {\n if (\n opts.agentDbBinding.principalId !== opts.self.selfId ||\n !opts.agentDbBinding.credentialRef\n ) throw new BrandForbiddenError(\"brand db is not bound to the acting agent\");\n const deps = resolveDeps({ db: opts.db, now: opts.now, newId: opts.newId });\n const authority = (capability: BrandCapability): Promise<BrandCapabilityAuthority> =>\n Promise.resolve(opts.authorizeCapability({\n agentId: opts.self.selfId,\n bookId: opts.bookId,\n capability,\n }) ?? null).then((result) => {\n if (!result || result.capability !== capability || !result.authorityRef)\n throw new BrandForbiddenError(`agent lacks ${capability} for brand book ${opts.bookId}`);\n return result;\n });\n const ctx: BrandToolCtx = {\n db: deps.db,\n bookId: opts.bookId,\n self: opts.self,\n visionInToolResults: opts.visionInToolResults !== false,\n now: deps.now,\n newId: deps.newId,\n agentJobId: opts.agentJobId,\n createProposal: (input) => opts.agentBridge.createProposal({\n jobId: opts.agentJobId,\n bookId: opts.bookId,\n ...input,\n }),\n recordAssetAnalysis: (input) => opts.agentBridge.recordAssetAnalysis({\n jobId: opts.agentJobId,\n bookId: opts.bookId,\n ...input,\n }),\n readAssetContent: (assetId) => opts.agentBridge.readAssetContent({\n jobId: opts.agentJobId,\n bookId: opts.bookId,\n assetId,\n }),\n resolvePrincipals: (principalIds) => {\n const ids = [...new Set(principalIds)].slice(0, 100);\n return opts.resolvePrincipals({\n requesterAgentId: opts.self.selfId,\n bookId: opts.bookId,\n principalIds: ids,\n });\n },\n authority,\n loadBook: async () => {\n await authority(\"brand.read\");\n const res = await deps.db.query({ [BRAND_NS.book]: { $: { where: { id: opts.bookId } } } });\n const row = (res[BRAND_NS.book] ?? [])[0] as BrandBook | undefined;\n if (!row || !row.memberIds.includes(opts.self.selfId))\n throw new BrandNotFoundError(`brand book ${opts.bookId}`);\n return row;\n },\n guard: (handler) => async (input, toolCtx) => {\n try {\n return await handler(input, toolCtx);\n } catch (error) {\n if (\n error instanceof BrandInputError ||\n error instanceof BrandNotFoundError ||\n error instanceof BrandForbiddenError\n ) {\n return { content: error.message, isError: true };\n }\n throw error;\n }\n },\n };\n return {\n name: \"brand\",\n instructions: BRAND_INSTRUCTIONS,\n tools: [...readTools(ctx), ...assetTools(ctx), ...paletteTools(ctx), ...bookTools(ctx)],\n };\n}\n","// The brand-director Persona: the brand skill pre-attached, a default system\n// prompt encoding the explore → propose → human approves → compile loop, and\n// the capability probe hosts use to decide whether asset bytes can ride\n// inside tool results or must be attached pre-turn. @odla-ai/ai types only.\nimport type { Persona, Skill } from \"@odla-ai/ai\";\nimport { brandSkill, type BrandSkillOpts } from \"./skill\";\n\n/** The default brand-director system prompt (override via `system`). */\nexport const DEFAULT_BRAND_SYSTEM =\n \"You are a meticulous brand director for one brand book. You study the real material \" +\n \"before forming opinions, you justify every color with math (harmony, ΔEOK, WCAG \" +\n \"contrast) or provenance (an asset's dominant colors), and you present options rather \" +\n \"than dictating. Proposals and drafts are yours to make; decisions are the human's — \" +\n \"you have no proposal-resolution or section-approval tool. When \" +\n \"tokens compile with warnings, explain each adjustment in plain language.\";\n\n/** Options for {@link createBrandPersona}. */\nexport interface CreateBrandPersonaOpts {\n /** Canonical model id the persona runs on. */\n model: string;\n /** System prompt override (default {@link DEFAULT_BRAND_SYSTEM}). */\n system?: string;\n /** Provider web-search server tool (default true — brand research). */\n webSearch?: boolean;\n /** Max model turns per run (default 10 — the workflow is multi-step). */\n maxSteps?: number;\n /** Extra skills appended after the brand skill (e.g. a chat skill). */\n skills?: Skill[];\n /** Options for the attached {@link brandSkill}. */\n brand: BrandSkillOpts;\n}\n\n/** Build the brand-director Persona: {@link brandSkill} first, extra skills\n * after, defaults per the option JSDoc above. */\nexport function createBrandPersona(opts: CreateBrandPersonaOpts): Persona {\n return {\n name: \"brand-director\",\n model: opts.model,\n system: opts.system ?? DEFAULT_BRAND_SYSTEM,\n webSearch: opts.webSearch ?? true,\n maxSteps: opts.maxSteps ?? 10,\n skills: [brandSkill(opts.brand), ...(opts.skills ?? [])],\n };\n}\n\n/** The capability flags {@link supportsBrandVision} inspects. */\nexport interface BrandVisionCapabilities {\n toolResultBlocks?: boolean;\n imageIn?: boolean;\n documentIn?: boolean;\n}\n\n/** The (structural) slice of an @odla-ai/ai ModelSpec the probe reads. */\nexport interface BrandVisionSpec {\n capabilities?: BrandVisionCapabilities;\n}\n\n/**\n * Whether a model can view assets THROUGH view_asset — i.e. take image and\n * document blocks inside tool results. Pure capabilities-metadata check\n * (`toolResultBlocks && imageIn && documentIn`), never provider names; when\n * false, hosts attach asset bytes as pre-turn input blocks instead and pass\n * `visionInToolResults: false` to the skill.\n */\nexport function supportsBrandVision(spec: BrandVisionSpec | null | undefined): boolean {\n const caps = spec?.capabilities;\n return !!(caps?.toolResultBlocks && caps.imageIn && caps.documentIn);\n}\n","import { BRAND_NS } from \"../constants\";\nimport { BrandNotFoundError } from \"../errors\";\nimport type { BrandAsset, BrandBook } from \"../types\";\nimport type { BrandRouteCtx } from \"./http\";\n\nexport async function linkedAsset(\n ctx: BrandRouteCtx,\n book: BrandBook,\n assetId: string,\n allowDeleting = false,\n): Promise<BrandAsset> {\n const result = await ctx.db.query({\n [BRAND_NS.asset]: {\n $: { where: { id: assetId, bookId: book.id } },\n book: {},\n },\n });\n const row = (result[BRAND_NS.asset] ?? [])[0] as\n | (BrandAsset & { book?: BrandBook[] })\n | undefined;\n const links = row?.book;\n if (\n !row ||\n row.bookId !== book.id ||\n !Array.isArray(links) ||\n links.length !== 1 ||\n links[0]?.id !== book.id ||\n (row.status !== \"live\" && !(allowDeleting && row.status === \"deleting\"))\n ) throw new BrandNotFoundError(`asset ${assetId}`);\n return row;\n}\n","// HTTP plumbing for the brand route factory (crm's http.ts contract): option\n// shapes, JSON helpers, the error → status mapping (BrandInputError → 400,\n// BrandNotFoundError → 404, anything else an OPAQUE 500), body-field\n// extractors, and the shared book loaders.\n//\n// Access parity note: routes run on the host's ADMIN db credential, which\n// bypasses odla-db rules — so the loaders re-enforce what the CEL rules would:\n// a book you are not in `memberIds` of answers 404, the same as one that does\n// not exist (a non-member cannot probe for existence).\nimport { BRAND_NS } from \"../constants\";\nimport {\n BrandConflictError,\n BrandForbiddenError,\n BrandGoneError,\n BrandInputError,\n BrandNotFoundError,\n BrandReviewStateChangedError,\n} from \"../errors\";\nimport type {\n BrandActor,\n BrandBook,\n BrandDb,\n BrandHumanAuthorityConsumption,\n BrandSourceAssetSnapshot,\n} from \"../types\";\n\nexport type BrandRouteCapability = \"brand.edit\" | \"app.manage\";\nexport type BrandRouteEffect = \"internal\" | \"destructive\";\nexport interface BrandRouteAuthority {\n authorityRef: string;\n actorPrincipalId: string;\n capability: BrandRouteCapability;\n effect: BrandRouteEffect;\n}\n\n/** Everything {@link import(\"./index\").createBrandRoutes} needs from the host worker. */\nexport interface BrandRouteOpts {\n /** The injected odla client (a real @odla-ai/db AdminDb satisfies it). */\n db: BrandDb;\n /** Registry app that owns the book rows and central authority records. */\n appId: string;\n /** Host-owned auth: resolve the request to an actor or null (→ 401). The\n * tokens routes skip this only when `publicTokens` is true. */\n authorize: (req: Request) => Promise<BrandActor | null> | BrandActor | null;\n /** Optional host-owned authority seam for read-only Discussion reference\n * lookup. Verify exact Brand product, brand.read capability, canonical\n * audience, principal, current app lifetime/environment, and agent grant\n * provenance here; when omitted, the ordinary request authorizer is used. */\n authorizeDiscussionReferences?: (\n req: Request,\n ) => Promise<BrandActor | null> | BrandActor | null;\n /** Live host verification for worker-mediated effects. The callback must\n * verify the direct human credential, current app owner/co-owner status,\n * exact capability/effect/resource, and return null on any uncertainty. */\n authorizeCapability: (input: {\n req: Request;\n actor: BrandActor;\n appId: string;\n bookId?: string;\n capability: BrandRouteCapability;\n effect: BrandRouteEffect;\n }) => Promise<BrandRouteAuthority | null> | BrandRouteAuthority | null;\n /** Consume or idempotently replay one registry `human_exact` authority use,\n * then reload and authenticate its immutable central receipt. Missing,\n * synthetic, cached, or unverifiable authority must return null. */\n consumeHumanExact: (input: {\n req: Request;\n actor: BrandActor;\n appId: string;\n capability: \"brand.proposal.resolve\";\n projectCapability: \"brand.approve\";\n effect: \"internal\";\n resource: { bookId: string; proposalId: string };\n actionDigest: string;\n consumptionIdempotencyKey: string;\n }) => Promise<BrandHumanAuthorityConsumption | null> | BrandHumanAuthorityConsumption | null;\n /** Re-read the private object and authenticate the exact snapshot captured\n * by the agent bridge. This must verify path, ETag, size, and SHA-256 bytes;\n * returning false prevents authority consumption and the local effect. */\n verifySourceAssetSnapshot: (input: {\n req: Request;\n appId: string;\n bookId: string;\n assetId: string;\n path: string;\n snapshot: BrandSourceAssetSnapshot;\n }) => Promise<boolean> | boolean;\n /** Mount point. Default \"/api/brand\". */\n basePath?: string;\n /** Native UI mount used by returned Discussion deep links. Default \"/\". */\n discussionBasePath?: string;\n /** Upload size cap in bytes (checked against `File.size`). Default 8 MiB. */\n maxUploadBytes?: number;\n /** Serve `GET /books/:id/tokens.css` and `tokens.json` without authorize —\n * compiled tokens only; every other route always authorizes. Default false. */\n publicTokens?: boolean;\n /** Injectable clock (tests). Default `Date.now`. */\n now?: () => number;\n /** Injectable id factory (tests). Default `crypto.randomUUID`. */\n newId?: () => string;\n}\n\n/** Per-request context handed to the authorized route handlers. */\nexport interface BrandRouteCtx {\n db: BrandDb;\n appId: string;\n actor: BrandActor;\n authorizeCapability: BrandRouteOpts[\"authorizeCapability\"];\n consumeHumanExact: BrandRouteOpts[\"consumeHumanExact\"];\n verifySourceAssetSnapshot: BrandRouteOpts[\"verifySourceAssetSnapshot\"];\n now: () => number;\n newId: () => string;\n maxUploadBytes: number;\n discussionBasePath: string;\n}\n\n/** Revalidate one direct-human route effect immediately before its write. */\nexport async function requireRouteAuthority(\n ctx: BrandRouteCtx,\n req: Request,\n capability: BrandRouteCapability,\n effect: BrandRouteEffect,\n bookId?: string,\n): Promise<BrandRouteAuthority> {\n if (ctx.actor.kind !== \"human\")\n throw new BrandForbiddenError(\"this brand effect requires a directly authenticated human\");\n const result = await ctx.authorizeCapability({\n req,\n actor: ctx.actor,\n appId: ctx.appId,\n ...(bookId ? { bookId } : {}),\n capability,\n effect,\n });\n if (\n !result ||\n result.actorPrincipalId !== ctx.actor.id ||\n result.capability !== capability ||\n result.effect !== effect ||\n typeof result.authorityRef !== \"string\" ||\n result.authorityRef.length < 1 ||\n result.authorityRef.length > 200\n ) throw new BrandForbiddenError(`human lacks ${capability} ${effect} authority`);\n return result;\n}\n\n/** JSON response helper (`content-type: application/json`). */\nexport const json = (body: unknown, status = 200, headers: Record<string, string> = {}): Response =>\n new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json\", ...headers },\n });\n\n/** Map a thrown error to its response: 400 input, 403 principal kind, 404\n * missing/membership parity, 409 stale review, otherwise opaque 500. */\nexport const errorResponse = (error: unknown): Response => {\n if (error instanceof BrandInputError)\n return json({ error: error.message, ...(error.fields ? { fields: error.fields } : {}) }, 400);\n if (error instanceof BrandForbiddenError) return json({ error: error.message }, 403);\n if (error instanceof BrandNotFoundError) return json({ error: error.message }, 404);\n if (error instanceof BrandGoneError) return json({ error: error.message }, 410);\n if (error instanceof BrandReviewStateChangedError)\n return json({ error: error.message, code: error.code }, 409);\n if (error instanceof BrandConflictError) return json({ error: error.message }, 409);\n return json({ error: \"internal error\" }, 500);\n};\n\n/** The uniform 405 for a known path hit with the wrong method. */\nexport const methodNotAllowed = (): Response => json({ error: \"method not allowed\" }, 405);\n\n/** Parse a JSON object body; {@link BrandInputError} (→ 400) on anything else. */\nexport async function readJson(req: Request): Promise<Record<string, unknown>> {\n let body: unknown;\n try {\n body = await req.json();\n } catch {\n throw new BrandInputError(\"invalid JSON body\");\n }\n if (typeof body !== \"object\" || body === null || Array.isArray(body))\n throw new BrandInputError(\"body must be a JSON object\");\n return body as Record<string, unknown>;\n}\n\n/** Required non-empty string body field. */\nexport function str(body: Record<string, unknown>, key: string): string {\n const value = body[key];\n if (typeof value !== \"string\" || value === \"\")\n throw new BrandInputError(`\"${key}\" must be a non-empty string`);\n return value;\n}\n\n/** Optional string body field (absent/null → undefined). */\nexport function optStr(body: Record<string, unknown>, key: string): string | undefined {\n const value = body[key];\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\") throw new BrandInputError(`\"${key}\" must be a string`);\n return value;\n}\n\n/** Optional string-array body field (absent/null → undefined). */\nexport function optStrArray(body: Record<string, unknown>, key: string): string[] | undefined {\n const value = body[key];\n if (value === undefined || value === null) return undefined;\n if (!Array.isArray(value) || value.some((v) => typeof v !== \"string\"))\n throw new BrandInputError(`\"${key}\" must be an array of strings`);\n return value as string[];\n}\n\n/** Whether `actorId` is on the book's auth roster. */\nexport function isMember(book: BrandBook, actorId: string): boolean {\n return Array.isArray(book.memberIds) && book.memberIds.includes(actorId);\n}\n\n/** Load a book by id; {@link BrandNotFoundError} (→ 404) when missing. */\nexport async function loadBook(db: BrandDb, bookId: string): Promise<BrandBook> {\n const res = await db.query({ [BRAND_NS.book]: { $: { where: { id: bookId } } } });\n const row = (res[BRAND_NS.book] ?? [])[0] as BrandBook | undefined;\n if (!row) throw new BrandNotFoundError(`brand book ${bookId}`);\n return row;\n}\n\n/** {@link loadBook}, plus the rules-parity membership gate: a non-member gets\n * the same 404 a missing book gets (see the header note). */\nexport async function loadMemberBook(db: BrandDb, bookId: string, actorId: string): Promise<BrandBook> {\n const book = await loadBook(db, bookId);\n if (!isMember(book, actorId)) throw new BrandNotFoundError(`brand book ${bookId}`);\n return book;\n}\n","import { ASSET_KINDS, BRAND_NS, type AssetKind } from \"../constants\";\nimport { BrandConflictError, BrandInputError } from \"../errors\";\nimport { createAssetOps } from \"../ops/assets\";\nimport { assertAssetContentType, capString, safeFileName } from \"../validate\";\nimport { linkedAsset } from \"./asset-query\";\nimport {\n json,\n loadMemberBook,\n requireRouteAuthority,\n type BrandRouteCtx,\n} from \"./http\";\n\nasync function readForm(req: Request): Promise<FormData> {\n try {\n return await req.formData();\n } catch {\n throw new BrandInputError(\n 'expected multipart/form-data with a \"file\" field',\n );\n }\n}\n\nasync function contentDigest(file: File): Promise<string> {\n const hash = await crypto.subtle.digest(\"SHA-256\", await file.arrayBuffer());\n return `sha256:${[...new Uint8Array(hash)]\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\nexport async function uploadAsset(\n ctx: BrandRouteCtx,\n req: Request,\n bookId: string,\n): Promise<Response> {\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n const form = await readForm(req);\n const file = form.get(\"file\");\n if (!(file instanceof File))\n throw new BrandInputError('\"file\" must be an uploaded file field');\n let contentType: string;\n try {\n contentType = assertAssetContentType(file.type);\n } catch (error) {\n if (error instanceof BrandInputError)\n return json({ error: error.message }, 415);\n throw error;\n }\n if (file.size > ctx.maxUploadBytes)\n return json({ error: `file exceeds ${ctx.maxUploadBytes} bytes` }, 413);\n const kindRaw = form.get(\"kind\");\n const kind = typeof kindRaw === \"string\" && kindRaw ? kindRaw : \"other\";\n if (!(ASSET_KINDS as readonly string[]).includes(kind))\n throw new BrandInputError(`kind must be one of: ${ASSET_KINDS.join(\", \")}`);\n const titleRaw = form.get(\"title\");\n const title = typeof titleRaw === \"string\" && titleRaw\n ? capString(titleRaw, \"title\", 160)\n : undefined;\n const fileName = safeFileName(file.name);\n const id = ctx.newId();\n const path = `brand/${book.id}/assets/${id}/${fileName}`;\n const authority = await requireRouteAuthority(\n ctx, req, \"brand.edit\", \"internal\", book.id,\n );\n const record = await ctx.db.storage.upload(\n path,\n file,\n contentType,\n { private: true },\n );\n if (record.path !== path) {\n await ctx.db.storage.delete(record.path);\n throw new BrandConflictError(\n \"private storage returned an unexpected asset path\",\n );\n }\n try {\n const current = await requireRouteAuthority(\n ctx, req, \"brand.edit\", \"internal\", book.id,\n );\n if (current.authorityRef !== authority.authorityRef)\n throw new BrandConflictError(\"brand edit authority changed during upload\");\n await ctx.db.transact(createAssetOps({\n id,\n bookId: book.id,\n kind: kind as AssetKind,\n path: record.path,\n storageObjectId: record.id,\n contentDigest: await contentDigest(file),\n contentType,\n size: record.size,\n uploadedBy: ctx.actor.id,\n uploadedAuthorityRef: authority.authorityRef,\n audience: book.memberIds,\n title,\n now: ctx.now(),\n }), {\n mutationId: `brand:asset-upload:v1:${id}`,\n guards: [\n { ns: BRAND_NS.asset, id, exists: false },\n {\n ns: BRAND_NS.book,\n id: book.id,\n exists: true,\n equals: {\n version: book.version,\n activationRevision: book.activationRevision,\n memberIds: book.memberIds,\n },\n },\n ],\n asUser: ctx.actor.id,\n ...(ctx.actor.email ? { asEmail: ctx.actor.email } : {}),\n asPrincipalKind: \"human\",\n });\n } catch (error) {\n await ctx.db.storage.delete(record.path);\n throw error;\n }\n return json(await linkedAsset(ctx, book, id), 201);\n}\n","// Private Brand asset upload, listing, short-lived download signing, and\n// deletion saga. Rows are linked to books and privileged reads validate both\n// the scalar bookId and the actual schema link.\nimport { BRAND_NS } from \"../constants\";\nimport { BrandConflictError } from \"../errors\";\nimport {\n beginAssetDeleteOps,\n finishAssetDeleteOps,\n} from \"../ops/assets\";\nimport type { BrandAsset, BrandBook } from \"../types\";\nimport { linkedAsset } from \"./asset-query\";\nimport { uploadAsset } from \"./asset-upload\";\nimport {\n json,\n loadMemberBook,\n methodNotAllowed,\n requireRouteAuthority,\n type BrandRouteCtx,\n} from \"./http\";\n\n/** List or upload assets. Only live rows are returned; every upload is\n * private and its expiring signed URL is never persisted. */\nexport async function handleAssetsRoot(\n ctx: BrandRouteCtx,\n req: Request,\n bookId: string,\n): Promise<Response> {\n if (req.method === \"POST\") return uploadAsset(ctx, req, bookId);\n if (req.method !== \"GET\") return methodNotAllowed();\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n const result = await ctx.db.query({\n [BRAND_NS.asset]: {\n $: { where: { bookId: book.id, status: \"live\" }, order: { createdAt: \"asc\" } },\n book: {},\n },\n });\n const assets = (result[BRAND_NS.asset] ?? []).filter((value) => {\n const row = value as BrandAsset & { book?: BrandBook[] };\n return row.bookId === book.id &&\n Array.isArray(row.book) &&\n row.book.length === 1 &&\n row.book[0]?.id === book.id;\n });\n return json({ assets });\n}\n\n/** Mint a five-minute private URL after current membership + exact link\n * validation. The response itself is non-cacheable. */\nexport async function handleAssetContent(\n ctx: BrandRouteCtx,\n req: Request,\n bookId: string,\n assetId: string,\n): Promise<Response> {\n if (req.method !== \"GET\") return methodNotAllowed();\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n const asset = await linkedAsset(ctx, book, assetId);\n const expiresInSeconds = 300;\n const url = await ctx.db.storage.sign(asset.path, expiresInSeconds);\n return json(\n { assetId, url, expiresInSeconds },\n 200,\n { \"cache-control\": \"private, no-store\", \"x-content-type-options\": \"nosniff\" },\n );\n}\n\n/** Guarded deleting → storage tombstone → deleted saga. A retry resumes a\n * deleting row; list/sign paths reject it from the first committed step. */\nexport async function handleAssetItem(\n ctx: BrandRouteCtx,\n req: Request,\n bookId: string,\n assetId: string,\n): Promise<Response> {\n if (req.method !== \"DELETE\") return methodNotAllowed();\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n let asset = await linkedAsset(ctx, book, assetId, true);\n const authority = await requireRouteAuthority(\n ctx, req, \"brand.edit\", \"destructive\", book.id,\n );\n const mutationBase = `brand:asset-delete:v1:${book.id}:${asset.id}`;\n if (asset.status === \"live\") {\n const deletedAt = ctx.now();\n try {\n await ctx.db.transact(beginAssetDeleteOps(\n asset.id,\n deletedAt,\n ctx.actor.id,\n authority.authorityRef,\n ), {\n mutationId: `${mutationBase}:begin`,\n guards: [\n {\n ns: BRAND_NS.asset,\n id: asset.id,\n exists: true,\n equals: {\n bookId: book.id,\n path: asset.path,\n storageObjectId: asset.storageObjectId,\n contentDigest: asset.contentDigest,\n status: \"live\",\n },\n },\n {\n ns: BRAND_NS.book,\n id: book.id,\n exists: true,\n equals: { version: book.version, memberIds: book.memberIds },\n },\n ],\n asUser: ctx.actor.id,\n ...(ctx.actor.email ? { asEmail: ctx.actor.email } : {}),\n asPrincipalKind: \"human\",\n });\n } catch (error) {\n if (\n typeof error === \"object\" &&\n error !== null &&\n (error as { code?: unknown }).code === \"transact_guard_failed\"\n ) throw new BrandConflictError(\"asset changed before deletion\");\n throw error;\n }\n asset = { ...asset, status: \"deleting\", deletedAt };\n }\n await ctx.db.storage.delete(asset.path);\n await ctx.db.transact(finishAssetDeleteOps(asset.id), {\n mutationId: `${mutationBase}:finish`,\n guards: [{\n ns: BRAND_NS.asset,\n id: asset.id,\n exists: true,\n equals: {\n bookId: book.id,\n path: asset.path,\n storageObjectId: asset.storageObjectId,\n contentDigest: asset.contentDigest,\n status: \"deleting\",\n deletedBy: asset.deletedBy ?? ctx.actor.id,\n deletedAuthorityRef: asset.deletedAuthorityRef ?? authority.authorityRef,\n },\n }],\n asUser: ctx.actor.id,\n ...(ctx.actor.email ? { asEmail: ctx.actor.email } : {}),\n asPrincipalKind: \"human\",\n });\n return json({ id: asset.id, status: \"deleted\", deletedAt: asset.deletedAt });\n}\n","// /books handlers: create, member-filtered list, and detail.\n//\n// List filtering note: odla-db's query where-clauses have no \"roster array\n// CONTAINS value\" operator (`$in` tests a scalar column against a candidate\n// list, the inverse), so membership on the json `memberIds` roster is not\n// expressible as a where. The handler fetches the namespace and filters in\n// code — exactly the visibility the `brand_book.view` CEL rule\n// (`auth.id in data.memberIds`) enforces for rules-scoped credentials; the\n// admin-key route path just re-applies it server-side.\nimport { BRAND_NS } from \"../constants\";\nimport { BrandConflictError, BrandForbiddenError, BrandInputError } from \"../errors\";\nimport { createBookOps } from \"../ops/books\";\nimport type { BrandBook } from \"../types\";\nimport { capString } from \"../validate\";\nimport {\n isMember,\n json,\n loadBook,\n loadMemberBook,\n methodNotAllowed,\n optStr,\n optStrArray,\n readJson,\n requireRouteAuthority,\n str,\n type BrandRouteCtx,\n} from \"./http\";\n\n/**\n * `GET /books` — every book whose `memberIds` roster contains the actor,\n * oldest first, as `{ books }`. `POST /books` — create a draft book owned by\n * the actor (`slug`, `name`, optional `memberIds` roster and `channelId`);\n * answers 201 with the created row. Other methods: 405.\n */\nexport async function handleBooksRoot(ctx: BrandRouteCtx, req: Request): Promise<Response> {\n if (req.method === \"GET\") {\n const res = await ctx.db.query({ [BRAND_NS.book]: { $: { order: { createdAt: \"asc\" } } } });\n const books = ((res[BRAND_NS.book] ?? []) as unknown as BrandBook[]).filter((b) =>\n isMember(b, ctx.actor.id),\n );\n return json({ books });\n }\n if (req.method === \"POST\") {\n if (ctx.actor.kind !== \"human\")\n throw new BrandForbiddenError(\"only a human can create a brand book\");\n const body = await readJson(req);\n const id = ctx.newId();\n const authority = await requireRouteAuthority(\n ctx,\n req,\n \"brand.edit\",\n \"internal\",\n );\n const ops = createBookOps({\n id,\n slug: str(body, \"slug\"),\n name: str(body, \"name\"),\n ownerId: ctx.actor.id,\n createdAuthorityRef: authority.authorityRef,\n memberIds: optStrArray(body, \"memberIds\") ?? [],\n channelId: optStr(body, \"channelId\"),\n now: ctx.now(),\n });\n await ctx.db.transact(ops, {\n mutationId: id,\n guards: [{ ns: BRAND_NS.book, id, exists: false }],\n asUser: ctx.actor.id,\n ...(ctx.actor.email ? { asEmail: ctx.actor.email } : {}),\n asPrincipalKind: \"human\",\n });\n return json(await loadBook(ctx.db, id), 201);\n }\n return methodNotAllowed();\n}\n\nconst sameStrings = (left: string[], right: string[]): boolean =>\n left.length === right.length && left.every((value, index) => value === right[index]);\nconst guardFailure = (error: unknown): boolean =>\n typeof error === \"object\" && error !== null &&\n (error as { code?: unknown }).code === \"transact_guard_failed\";\n\n/** `PATCH /books/:id/members` — owner-only atomic roster update. Child CEL\n * reads follow schema links to this current roster, so no fan-out is needed. */\nexport async function handleBookMembers(\n ctx: BrandRouteCtx,\n req: Request,\n bookId: string,\n): Promise<Response> {\n if (req.method !== \"PATCH\") return methodNotAllowed();\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n if (ctx.actor.kind !== \"human\")\n throw new BrandForbiddenError(\"only a human app owner can change members\");\n const body = await readJson(req);\n const rawMembers = optStrArray(body, \"memberIds\");\n const rawExpected = optStrArray(body, \"expectedMemberIds\");\n if (!rawMembers || !rawExpected)\n throw new BrandInputError('\"memberIds\" and \"expectedMemberIds\" are required string arrays');\n const memberIds = Array.from(new Set([\n book.ownerId,\n ...rawMembers.map((id, index) => capString(id, `memberIds[${index}]`, 160)),\n ]));\n if (memberIds.length > 100)\n throw new BrandInputError(\"a brand book supports at most 100 members\");\n const expectedMemberIds = rawExpected.map((id, index) =>\n capString(id, `expectedMemberIds[${index}]`, 160));\n if (!sameStrings(book.memberIds, expectedMemberIds) && !sameStrings(book.memberIds, memberIds))\n throw new BrandConflictError(\"brand book membership changed since review\");\n\n const mutationId = capString(str(body, \"mutationId\"), \"mutationId\", 200);\n const mutationKey = `brand:book-members:v1:${bookId}:${mutationId}`;\n const authority = await requireRouteAuthority(\n ctx,\n req,\n \"app.manage\",\n \"internal\",\n bookId,\n );\n try {\n const tx = await ctx.db.transact(\n [{\n t: \"update\",\n ns: BRAND_NS.book,\n id: bookId,\n attrs: {\n memberIds,\n version: book.version + 1,\n updatedAt: ctx.now(),\n rosterAuthorityRef: authority.authorityRef,\n },\n }],\n {\n mutationId: mutationKey,\n guards: [{\n ns: BRAND_NS.book,\n id: bookId,\n exists: true,\n equals: { memberIds: expectedMemberIds, version: book.version },\n }],\n asUser: ctx.actor.id,\n ...(ctx.actor.email ? { asEmail: ctx.actor.email } : {}),\n asPrincipalKind: \"human\",\n },\n );\n return json({ bookId, memberIds, duplicate: tx.duplicate === true });\n } catch (error) {\n if (guardFailure(error))\n throw new BrandConflictError(\"brand book membership changed since review\");\n throw error;\n }\n}\n\n/** `GET /books/:id` — the book row, members only (404 otherwise, matching the\n * view rule — see http.ts). Other methods: 405. */\nexport async function handleBookItem(ctx: BrandRouteCtx, req: Request, bookId: string): Promise<Response> {\n if (req.method !== \"GET\") return methodNotAllowed();\n return json(await loadMemberBook(ctx.db, bookId, ctx.actor.id));\n}\n","import { PROPOSAL_KINDS } from \"../constants\";\nimport { BrandConflictError, BrandInputError } from \"../errors\";\nimport { isBoundedBrandJson } from \"../review\";\nimport type { BrandProposal, BrandProposalReviewSnapshot } from \"../types\";\nimport { capString } from \"../validate\";\nimport { optStr, str } from \"./http\";\n\nconst SNAPSHOT_KEYS = [\n \"audience\",\n \"bookId\",\n \"createdAt\",\n \"createdAuthorityRef\",\n \"createdBy\",\n \"id\",\n \"kind\",\n \"payload\",\n \"provenance\",\n \"rationale\",\n \"reviewDigest\",\n \"status\",\n] as const;\nconst record = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nexport interface ProposalResolutionRequest {\n mutationId: string;\n resolution: \"accepted\" | \"rejected\";\n reviewed: BrandProposalReviewSnapshot;\n resolutionNote?: string;\n}\n\nexport function parseProposalResolutionRequest(\n body: Record<string, unknown>,\n bookId: string,\n proposalId: string,\n): ProposalResolutionRequest {\n const allowed = new Set([\n \"mutationId\",\n \"resolution\",\n \"reviewedProposal\",\n \"note\",\n ]);\n if (Object.keys(body).some((key) => !allowed.has(key)))\n throw new BrandInputError(\"proposal resolution body has unknown fields\");\n const mutationId = capString(str(body, \"mutationId\"), \"mutationId\", 200);\n const rawResolution = str(body, \"resolution\");\n if (rawResolution !== \"accepted\" && rawResolution !== \"rejected\")\n throw new BrandInputError('\"resolution\" must be \"accepted\" or \"rejected\"');\n const rawNote = optStr(body, \"note\");\n const resolutionNote = rawNote?.trim()\n ? capString(rawNote, \"note\", 1_000)\n : undefined;\n return {\n mutationId,\n resolution: rawResolution,\n reviewed: parseReviewedProposal(body.reviewedProposal, bookId, proposalId),\n ...(resolutionNote ? { resolutionNote } : {}),\n };\n}\n\n/** Freeze the exact OPEN proposal fields a reviewer sees. */\nexport function proposalReviewSnapshot(proposal: BrandProposal): BrandProposalReviewSnapshot {\n if (proposal.status !== \"open\")\n throw new BrandConflictError(`proposal ${proposal.id} is ${proposal.status}, not open`);\n return {\n id: proposal.id,\n bookId: proposal.bookId,\n kind: proposal.kind,\n status: \"open\",\n payload: proposal.payload,\n rationale: proposal.rationale,\n provenance: proposal.provenance,\n reviewDigest: proposal.reviewDigest,\n audience: proposal.audience,\n createdBy: proposal.createdBy,\n createdAuthorityRef: proposal.createdAuthorityRef,\n createdAt: proposal.createdAt,\n };\n}\n\n/** Strict, bounded request parser: no extra hydration/resolution fields. */\nexport function parseReviewedProposal(\n value: unknown,\n bookId: string,\n proposalId: string,\n): BrandProposalReviewSnapshot {\n // The server bounds the entire guards array. Reserve ample room for guard\n // wrappers and the independent book/palette/receipt guards.\n if (!isBoundedBrandJson(value, { maxDepth: 12, maxNodes: 1_500, maxBytes: 32 * 1024 }))\n throw new BrandInputError('\"reviewedProposal\" is too deeply nested, complex, or large');\n if (!record(value)) throw new BrandInputError('\"reviewedProposal\" must be an object');\n const keys = Object.keys(value).sort();\n if (\n keys.length !== SNAPSHOT_KEYS.length ||\n !SNAPSHOT_KEYS.every((key, index) => key === keys[index])\n ) throw new BrandInputError('\"reviewedProposal\" has an invalid shape');\n if (value.id !== proposalId || value.bookId !== bookId || value.status !== \"open\")\n throw new BrandInputError('\"reviewedProposal\" must identify this open proposal');\n if (\n typeof value.kind !== \"string\" ||\n !(PROPOSAL_KINDS as readonly string[]).includes(value.kind) ||\n !record(value.payload) ||\n typeof value.rationale !== \"string\" ||\n !Array.isArray(value.audience) ||\n value.audience.length < 1 ||\n value.audience.length > 100 ||\n value.audience.some((id) => typeof id !== \"string\" || id.length < 1 || id.length > 200) ||\n new Set(value.audience).size !== value.audience.length ||\n typeof value.createdBy !== \"string\" || value.createdBy.length < 1 || value.createdBy.length > 200 ||\n typeof value.createdAuthorityRef !== \"string\" ||\n value.createdAuthorityRef.length < 1 || value.createdAuthorityRef.length > 200 ||\n !Number.isSafeInteger(value.createdAt) || (value.createdAt as number) < 0 ||\n typeof value.reviewDigest !== \"string\" ||\n !/^sha256:[0-9a-f]{64}$/.test(value.reviewDigest)\n ) throw new BrandInputError('\"reviewedProposal\" has invalid fields');\n if (\n !record(value.provenance) ||\n Object.keys(value.provenance).sort().join(\",\") !==\n \"messageId,sourceAsset,sourceAssetId,taintLabels,turnId\" ||\n (value.provenance.sourceAssetId !== null &&\n (typeof value.provenance.sourceAssetId !== \"string\" ||\n value.provenance.sourceAssetId.length < 1 ||\n value.provenance.sourceAssetId.length > 200)) ||\n (value.provenance.sourceAsset !== null &&\n (!record(value.provenance.sourceAsset) ||\n Object.keys(value.provenance.sourceAsset).sort().join(\",\") !==\n \"analysisDigest,analysisRevision,assetId,contentDigest,contentType,objectEtag,objectSize,pathDigest\" ||\n typeof value.provenance.sourceAsset.assetId !== \"string\" ||\n value.provenance.sourceAsset.assetId.length < 1 ||\n value.provenance.sourceAsset.assetId.length > 200 ||\n typeof value.provenance.sourceAsset.objectEtag !== \"string\" ||\n value.provenance.sourceAsset.objectEtag.length < 1 ||\n value.provenance.sourceAsset.objectEtag.length > 200 ||\n !Number.isSafeInteger(value.provenance.sourceAsset.objectSize) ||\n (value.provenance.sourceAsset.objectSize as number) < 1 ||\n typeof value.provenance.sourceAsset.pathDigest !== \"string\" ||\n !/^sha256:[0-9a-f]{64}$/.test(value.provenance.sourceAsset.pathDigest) ||\n (value.provenance.sourceAsset.contentType !== null &&\n (typeof value.provenance.sourceAsset.contentType !== \"string\" ||\n value.provenance.sourceAsset.contentType.length < 1 ||\n value.provenance.sourceAsset.contentType.length > 160)) ||\n typeof value.provenance.sourceAsset.contentDigest !== \"string\" ||\n !/^sha256:[0-9a-f]{64}$/.test(value.provenance.sourceAsset.contentDigest) ||\n (value.provenance.sourceAsset.analysisRevision !== null &&\n (!Number.isSafeInteger(value.provenance.sourceAsset.analysisRevision) ||\n (value.provenance.sourceAsset.analysisRevision as number) < 0)) ||\n (value.provenance.sourceAsset.analysisDigest !== null &&\n (typeof value.provenance.sourceAsset.analysisDigest !== \"string\" ||\n !/^sha256:[0-9a-f]{64}$/.test(\n value.provenance.sourceAsset.analysisDigest,\n ))) ||\n value.provenance.sourceAsset.assetId !==\n value.provenance.sourceAssetId)) ||\n ((value.provenance.sourceAssetId === null) !==\n (value.provenance.sourceAsset === null)) ||\n (value.provenance.messageId !== null &&\n (typeof value.provenance.messageId !== \"string\" ||\n value.provenance.messageId.length < 1 ||\n value.provenance.messageId.length > 200)) ||\n (value.provenance.turnId !== null &&\n (typeof value.provenance.turnId !== \"string\" ||\n value.provenance.turnId.length < 1 ||\n value.provenance.turnId.length > 200)) ||\n !Array.isArray(value.provenance.taintLabels) ||\n value.provenance.taintLabels.length > 16 ||\n value.provenance.taintLabels.some((label) =>\n typeof label !== \"string\" || label.length < 1 || label.length > 120) ||\n new Set(value.provenance.taintLabels).size !== value.provenance.taintLabels.length\n ) throw new BrandInputError('\"reviewedProposal.provenance\" is invalid');\n return value as unknown as BrandProposalReviewSnapshot;\n}\n\nexport const proposalGuardEquals = (\n snapshot: BrandProposalReviewSnapshot,\n): Record<string, unknown> => ({ ...snapshot });\n","import { BRAND_NS } from \"../constants\";\nimport { BrandInputError } from \"../errors\";\nimport { acceptProposalOps, rejectProposalOps } from \"../ops/palettes\";\nimport { upsertSectionOps } from \"../ops/sections\";\nimport { brandJsonDigest } from \"../review\";\nimport { compileBrandTokens } from \"../tokens/compile\";\nimport type {\n BrandBook,\n BrandOp,\n BrandPalette,\n BrandProposal,\n BrandSection,\n BrandTokensSnapshot,\n Swatch,\n TypographySection,\n} from \"../types\";\nimport { assertSwatches } from \"../validate\";\n\nexport interface ProposalEffectInput {\n proposal: BrandProposal;\n book: BrandBook;\n resolution: \"accepted\" | \"rejected\";\n receiptId: string;\n actionDigest: string;\n paletteId?: string;\n priorPalette?: BrandPalette;\n approvedTypography?: BrandSection;\n actorId: string;\n now: number;\n resolutionNote?: string;\n}\n\nasync function tokenSnapshot(\n swatches: Swatch[],\n typography: TypographySection | undefined,\n input: ProposalEffectInput,\n paletteId: string,\n paletteReceiptId: string,\n paletteActionDigest: string,\n typographyReceiptId?: string,\n typographyActionDigest?: string,\n): Promise<BrandTokensSnapshot> {\n const compiled = compileBrandTokens({ swatches, ...(typography ? { typography } : {}) });\n const sources = {\n paletteId,\n paletteReceiptId,\n paletteActionDigest,\n typographyReceiptId: typographyReceiptId ?? null,\n typographyActionDigest: typographyActionDigest ?? null,\n };\n return {\n light: compiled.light,\n dark: compiled.dark,\n warnings: compiled.warnings,\n compiledAt: input.now,\n paletteId,\n paletteReceiptId,\n paletteActionDigest,\n ...(typographyReceiptId ? { typographyReceiptId } : {}),\n ...(typographyActionDigest ? { typographyActionDigest } : {}),\n sourceDigest: await brandJsonDigest(sources),\n };\n}\n\nfunction stampProposal(ops: BrandOp[], input: ProposalEffectInput): void {\n const op = ops.find(\n (candidate) =>\n candidate.t === \"update\" &&\n candidate.ns === BRAND_NS.proposal &&\n candidate.id === input.proposal.id,\n );\n if (!op || op.t !== \"update\") throw new Error(\"proposal resolution op missing\");\n Object.assign(op.attrs, {\n approvedBy: input.actorId,\n appliedBy: input.actorId,\n resolutionReceiptId: input.receiptId,\n resolutionActionDigest: input.actionDigest,\n });\n}\n\n/** Build all live effects for one guarded decision. */\nexport async function proposalDecisionOps(input: ProposalEffectInput): Promise<BrandOp[]> {\n const common = {\n proposal: input.proposal,\n resolvedBy: input.actorId,\n now: input.now,\n resolutionNote: input.resolutionNote,\n };\n if (input.resolution === \"rejected\") {\n const ops = rejectProposalOps(common);\n stampProposal(ops, input);\n return ops;\n }\n\n let ops: BrandOp[];\n if (input.proposal.kind === \"palette\") {\n if (!input.paletteId) throw new Error(\"accepted palette id missing\");\n ops = acceptProposalOps({\n ...common,\n paletteId: input.paletteId,\n approvalReceiptId: input.receiptId,\n approvalActionDigest: input.actionDigest,\n });\n const swatches = assertSwatches(input.proposal.payload.swatches);\n const tokens = await tokenSnapshot(\n swatches,\n input.approvedTypography?.content as TypographySection | undefined,\n input,\n input.paletteId,\n input.receiptId,\n input.actionDigest,\n input.approvedTypography?.approvalReceiptId,\n input.approvedTypography?.approvalActionDigest,\n );\n const bookOp = ops.find(\n (op) => op.t === \"update\" && op.ns === BRAND_NS.book && op.id === input.book.id,\n );\n if (!bookOp || bookOp.t !== \"update\") throw new Error(\"book activation op missing\");\n Object.assign(bookOp.attrs, {\n version: input.book.version + 1,\n activationRevision: input.book.activationRevision + 1,\n tokens,\n });\n if (input.priorPalette && input.priorPalette.id !== input.paletteId) {\n ops.unshift({\n t: \"update\",\n ns: BRAND_NS.palette,\n id: input.priorPalette.id,\n attrs: { status: \"archived\", updatedAt: input.now },\n });\n }\n } else {\n const content = input.proposal.payload.content;\n if (typeof content !== \"object\" || content === null || Array.isArray(content))\n throw new BrandInputError(\"proposal payload.content must be an object\");\n ops = [\n ...upsertSectionOps({\n bookId: input.book.id,\n kind: input.proposal.kind,\n content: content as Record<string, unknown>,\n status: \"approved\",\n audience: input.book.memberIds,\n updatedBy: input.actorId,\n approvalReceiptId: input.receiptId,\n approvalActionDigest: input.actionDigest,\n now: input.now,\n }),\n {\n t: \"update\",\n ns: BRAND_NS.book,\n id: input.book.id,\n attrs: {\n activationRevision: input.book.activationRevision + 1,\n version: input.book.version + 1,\n updatedAt: input.now,\n },\n },\n {\n t: \"update\",\n ns: BRAND_NS.proposal,\n id: input.proposal.id,\n attrs: {\n status: \"accepted\",\n resolvedBy: input.actorId,\n resolvedAt: input.now,\n ...(input.resolutionNote ? { resolutionNote: input.resolutionNote } : {}),\n },\n },\n ];\n if (input.proposal.kind === \"typography\" && input.priorPalette) {\n const bookOp = ops.find(\n (op) => op.t === \"update\" && op.ns === BRAND_NS.book && op.id === input.book.id,\n );\n if (bookOp?.t === \"update\") {\n if (!input.priorPalette.approvalReceiptId || !input.priorPalette.approvalActionDigest)\n throw new BrandInputError(\"active palette is missing approval provenance\");\n bookOp.attrs.tokens = await tokenSnapshot(\n input.priorPalette.swatches,\n content as TypographySection,\n input,\n input.priorPalette.id,\n input.priorPalette.approvalReceiptId,\n input.priorPalette.approvalActionDigest,\n input.receiptId,\n input.actionDigest,\n );\n }\n }\n }\n stampProposal(ops, input);\n return ops;\n}\n","import { BRAND_NS } from \"../constants\";\nimport { BrandForbiddenError } from \"../errors\";\nimport {\n brandJsonDigest,\n canonicalBrandJson,\n isBrandHumanAuthorityConsumption,\n} from \"../review\";\nimport type {\n BrandApprovalReceipt,\n BrandHumanAuthorityConsumption,\n BrandProposalReviewSnapshot,\n} from \"../types\";\nimport type { BrandRouteCtx } from \"./http\";\n\n/** Fixed-width local/central idempotency domain. Caller-controlled ids are\n * hashed so every legal request stays below registry and database key limits. */\nexport async function proposalResolutionMutationKey(\n bookId: string,\n proposalId: string,\n mutationId: string,\n): Promise<string> {\n const digest = await brandJsonDigest({\n version: 3,\n bookId,\n proposalId,\n mutationId,\n });\n return `brand:proposal-resolution:v3:${digest.slice(\"sha256:\".length)}`;\n}\n\nexport async function proposalReceiptByMutation(\n ctx: BrandRouteCtx,\n mutationKey: string,\n): Promise<BrandApprovalReceipt | undefined> {\n const result = await ctx.db.query({\n [BRAND_NS.approvalReceipt]: {\n $: { where: { mutationKey } },\n book: {},\n },\n });\n const row = (result[BRAND_NS.approvalReceipt] ?? [])[0] as\n | (BrandApprovalReceipt & { book?: Array<{ id: string }> })\n | undefined;\n if (\n !row ||\n !Array.isArray(row.book) ||\n row.book.length !== 1 ||\n row.book[0]?.id !== row.bookId\n ) return undefined;\n const { book: _book, ...receipt } = row;\n return receipt as BrandApprovalReceipt;\n}\n\nexport async function consumeProposalAuthority(\n ctx: BrandRouteCtx,\n req: Request,\n bookId: string,\n proposalId: string,\n actionDigest: string,\n mutationKey: string,\n): Promise<BrandHumanAuthorityConsumption> {\n const authority = await ctx.consumeHumanExact({\n req,\n actor: ctx.actor,\n appId: ctx.appId,\n capability: \"brand.proposal.resolve\",\n projectCapability: \"brand.approve\",\n effect: \"internal\",\n resource: { bookId, proposalId },\n actionDigest,\n consumptionIdempotencyKey: mutationKey,\n });\n const resourceDigest = await brandJsonDigest({ bookId, proposalId });\n if (\n !isBrandHumanAuthorityConsumption(authority) ||\n authority.actorPrincipalId !== ctx.actor.id ||\n authority.appId !== ctx.appId ||\n authority.actionDigest !== actionDigest ||\n authority.resourceDigest !== resourceDigest ||\n authority.consumptionIdempotencyKey !== mutationKey\n ) throw new BrandForbiddenError(\n \"a verified human-exact brand approval is required\",\n );\n return authority;\n}\n\nexport function sameProposalResolutionRequest(\n receipt: BrandApprovalReceipt,\n reviewed: BrandProposalReviewSnapshot,\n resolution: \"accepted\" | \"rejected\",\n note: string | undefined,\n paletteId: string | undefined,\n): boolean {\n return receipt.resolution === resolution &&\n (receipt.resolutionNote ?? null) === (note ?? null) &&\n (receipt.paletteId ?? null) === (paletteId ?? null) &&\n canonicalBrandJson(receipt.reviewedProposal) ===\n canonicalBrandJson(reviewed);\n}\n","import { BRAND_NS } from \"../constants\";\nimport { BrandConflictError } from \"../errors\";\nimport {\n canonicalBrandJson,\n verifyBrandApprovalReceipt,\n} from \"../review\";\nimport type {\n BrandApprovalReceipt,\n BrandBook,\n BrandPalette,\n BrandProposal,\n BrandSection,\n BrandTransactGuard,\n} from \"../types\";\nimport {\n assertHex,\n assertSectionContent,\n assertSwatches,\n capString,\n} from \"../validate\";\nimport type { BrandRouteCtx } from \"./http\";\n\nasync function receipt(\n ctx: BrandRouteCtx,\n id: string,\n actionDigest: string,\n expected: {\n bookId: string;\n kind: BrandProposal[\"kind\"];\n paletteId?: string;\n proposalId?: string;\n content?: Record<string, unknown>;\n },\n): Promise<BrandApprovalReceipt> {\n const result = await ctx.db.query({\n [BRAND_NS.approvalReceipt]: {\n $: { where: { id } },\n book: {},\n },\n });\n const row = (result[BRAND_NS.approvalReceipt] ?? [])[0] as\n | (BrandApprovalReceipt & { book?: Array<{ id: string }> })\n | undefined;\n if (\n !row ||\n row.actionDigest !== actionDigest ||\n row.resolution !== \"accepted\" ||\n row.bookId !== expected.bookId ||\n row.reviewedProposal.bookId !== expected.bookId ||\n row.reviewedProposal.kind !== expected.kind ||\n !Array.isArray(row.book) ||\n row.book.length !== 1 ||\n row.book[0]?.id !== expected.bookId ||\n (expected.paletteId !== undefined && row.paletteId !== expected.paletteId) ||\n (expected.proposalId !== undefined && row.proposalId !== expected.proposalId) ||\n (expected.content !== undefined &&\n canonicalBrandJson(row.reviewedProposal.payload.content) !==\n canonicalBrandJson(expected.content))\n ) throw new BrandConflictError(`approval receipt ${id} is invalid`);\n const { book: _book, ...unhydrated } = row;\n if (!(await verifyBrandApprovalReceipt(unhydrated)))\n throw new BrandConflictError(`approval receipt ${id} is invalid`);\n return unhydrated as BrandApprovalReceipt;\n}\n\nexport async function activePalette(\n ctx: BrandRouteCtx,\n book: BrandBook,\n): Promise<{ palette?: BrandPalette; receipt?: BrandApprovalReceipt }> {\n if (!book.activePaletteId) return {};\n const result = await ctx.db.query({\n [BRAND_NS.palette]: {\n $: { where: { id: book.activePaletteId } },\n book: {},\n },\n });\n const palette = (result[BRAND_NS.palette] ?? [])[0] as\n | (BrandPalette & { book?: Array<{ id: string }> })\n | undefined;\n if (\n !palette ||\n palette.bookId !== book.id ||\n palette.status !== \"active\" ||\n !palette.proposalId ||\n !palette.approvalReceiptId ||\n !palette.approvalActionDigest ||\n !Array.isArray(palette.book) ||\n palette.book.length !== 1 ||\n palette.book[0]?.id !== book.id\n ) throw new BrandConflictError(\n \"active palette is missing valid approval provenance\",\n );\n const approval = await receipt(\n ctx,\n palette.approvalReceiptId,\n palette.approvalActionDigest,\n {\n bookId: book.id,\n kind: \"palette\",\n paletteId: palette.id,\n proposalId: palette.proposalId,\n },\n );\n let expectedName: string;\n let expectedSwatches: ReturnType<typeof assertSwatches>;\n let expectedSeed: string | undefined;\n try {\n expectedName = capString(\n approval.reviewedProposal.payload.name,\n \"reviewedProposal.payload.name\",\n 120,\n );\n expectedSwatches = assertSwatches(\n approval.reviewedProposal.payload.swatches,\n );\n expectedSeed = approval.reviewedProposal.payload.seedHex === undefined\n ? undefined\n : assertHex(\n approval.reviewedProposal.payload.seedHex,\n \"reviewedProposal.payload.seedHex\",\n );\n } catch {\n throw new BrandConflictError(\"active palette approval payload is invalid\");\n }\n const expectedSource = approval.reviewedProposal.provenance.sourceAsset\n ? \"extracted\"\n : expectedSeed\n ? \"derived\"\n : \"manual\";\n if (\n palette.proposalId !== approval.proposalId ||\n palette.name !== expectedName ||\n canonicalBrandJson(palette.swatches) !== canonicalBrandJson(expectedSwatches) ||\n (palette.seedHex ?? null) !== (expectedSeed ?? null) ||\n palette.source !== expectedSource ||\n palette.rationale !== approval.reviewedProposal.rationale ||\n canonicalBrandJson(palette.audience) !==\n canonicalBrandJson(approval.reviewedProposal.audience) ||\n palette.createdAt !== approval.createdAt ||\n palette.updatedAt !== approval.createdAt\n ) throw new BrandConflictError(\n \"active palette does not match its approved proposal\",\n );\n return { palette, receipt: approval };\n}\n\nexport async function approvedTypography(\n ctx: BrandRouteCtx,\n book: BrandBook,\n): Promise<{ section?: BrandSection; receipt?: BrandApprovalReceipt }> {\n const key = `${book.id}:typography`;\n const result = await ctx.db.query({\n [BRAND_NS.section]: {\n $: { where: { key } },\n book: {},\n },\n });\n const section = (result[BRAND_NS.section] ?? [])[0] as\n | (BrandSection & { book?: Array<{ id: string }> })\n | undefined;\n if (!section || section.status !== \"approved\") return {};\n if (\n section.bookId !== book.id ||\n section.kind !== \"typography\" ||\n !section.approvalReceiptId ||\n !section.approvalActionDigest ||\n !Array.isArray(section.book) ||\n section.book.length !== 1 ||\n section.book[0]?.id !== book.id\n ) throw new BrandConflictError(\n \"approved typography is missing valid approval provenance\",\n );\n assertSectionContent(\"typography\", section.content);\n return {\n section,\n receipt: await receipt(\n ctx,\n section.approvalReceiptId,\n section.approvalActionDigest,\n { bookId: book.id, kind: \"typography\", content: section.content },\n ),\n };\n}\n\nexport const receiptGuard = (\n value: BrandApprovalReceipt,\n): BrandTransactGuard => ({\n ns: BRAND_NS.approvalReceipt,\n id: value.id,\n exists: true,\n equals: {\n actionDigest: value.actionDigest,\n receiptDigest: value.receiptDigest,\n resolution: \"accepted\",\n },\n});\n","import { BRAND_NS } from \"../constants\";\nimport { BrandConflictError, BrandNotFoundError } from \"../errors\";\nimport { brandJsonDigest } from \"../review\";\nimport type {\n BrandAsset,\n BrandBook,\n BrandDecisionBinding,\n BrandPalette,\n BrandProposal,\n BrandSection,\n BrandTransactGuard,\n} from \"../types\";\nimport {\n assertSectionContent,\n assertSwatches,\n capString,\n} from \"../validate\";\nimport type { BrandRouteCtx } from \"./http\";\nimport {\n activePalette,\n approvedTypography,\n receiptGuard,\n} from \"./proposal-dependencies\";\n\nexport interface ProposalDecisionState {\n priorPalette?: BrandPalette;\n approvedTypography?: BrandSection;\n binding: BrandDecisionBinding;\n effectDescriptor: Record<string, unknown>;\n dependencyGuards: BrandTransactGuard[];\n}\n\n/** Resolve, validate, and digest every live dependency before authority is\n * consumed. The caller must include every returned guard in the local CAS. */\nexport async function proposalDecisionState(\n ctx: BrandRouteCtx,\n req: Request,\n book: BrandBook,\n proposal: BrandProposal,\n resolution: \"accepted\" | \"rejected\",\n receiptId: string,\n paletteId?: string,\n): Promise<ProposalDecisionState> {\n const needsPalette = resolution === \"accepted\" &&\n (proposal.kind === \"palette\" || proposal.kind === \"typography\");\n const paletteDep = needsPalette ? await activePalette(ctx, book) : {};\n const typeDep = resolution === \"accepted\" && proposal.kind === \"palette\"\n ? await approvedTypography(ctx, book)\n : {};\n const dependencyGuards: BrandTransactGuard[] = [];\n const source = proposal.provenance.sourceAsset;\n let sourceAsset: (BrandAsset & { book?: Array<{ id: string }> }) | undefined;\n if (source && resolution === \"accepted\") {\n const result = await ctx.db.query({\n [BRAND_NS.asset]: {\n $: { where: { id: source.assetId, bookId: book.id } },\n book: {},\n },\n });\n sourceAsset = (result[BRAND_NS.asset] ?? [])[0] as\n | (BrandAsset & { book?: Array<{ id: string }> })\n | undefined;\n if (\n !sourceAsset ||\n sourceAsset.id !== source.assetId ||\n sourceAsset.bookId !== book.id ||\n sourceAsset.status !== \"live\" ||\n sourceAsset.deletedAt !== undefined ||\n sourceAsset.contentDigest !== source.contentDigest ||\n sourceAsset.size !== source.objectSize ||\n sourceAsset.contentType !== source.contentType ||\n (await brandJsonDigest({ appId: ctx.appId, path: sourceAsset.path })) !==\n source.pathDigest ||\n sourceAsset.analysisRevision !== source.analysisRevision ||\n (sourceAsset.analysisDigest ?? null) !== source.analysisDigest ||\n !Array.isArray(sourceAsset.book) ||\n sourceAsset.book.length !== 1 ||\n sourceAsset.book[0]?.id !== book.id\n ) throw new BrandConflictError(\n \"source asset changed since the proposal was reviewed\",\n );\n if (!(await ctx.verifySourceAssetSnapshot({\n req,\n appId: ctx.appId,\n bookId: book.id,\n assetId: source.assetId,\n path: sourceAsset.path,\n snapshot: source,\n }))) throw new BrandConflictError(\n \"source asset bytes changed since the proposal was reviewed\",\n );\n dependencyGuards.push({\n ns: BRAND_NS.asset,\n id: sourceAsset.id,\n exists: true,\n equals: {\n bookId: book.id,\n status: \"live\",\n path: sourceAsset.path,\n storageObjectId: sourceAsset.storageObjectId,\n contentDigest: source.contentDigest,\n contentType: source.contentType,\n size: source.objectSize,\n analysisRevision: source.analysisRevision,\n ...(source.analysisDigest ? { analysisDigest: source.analysisDigest } : {}),\n },\n });\n }\n if (paletteDep.palette && paletteDep.receipt) {\n dependencyGuards.push({\n ns: BRAND_NS.palette,\n id: paletteDep.palette.id,\n exists: true,\n equals: {\n bookId: book.id,\n status: \"active\",\n name: paletteDep.palette.name,\n swatches: paletteDep.palette.swatches,\n seedHex: paletteDep.palette.seedHex ?? null,\n source: paletteDep.palette.source,\n rationale: paletteDep.palette.rationale,\n proposalId: paletteDep.palette.proposalId,\n approvalReceiptId: paletteDep.palette.approvalReceiptId,\n approvalActionDigest: paletteDep.palette.approvalActionDigest,\n audience: paletteDep.palette.audience,\n createdAt: paletteDep.palette.createdAt,\n updatedAt: paletteDep.palette.updatedAt,\n },\n }, receiptGuard(paletteDep.receipt));\n }\n if (typeDep.section && typeDep.receipt) {\n dependencyGuards.push({\n ns: BRAND_NS.section,\n id: typeDep.section.id,\n exists: true,\n equals: {\n key: typeDep.section.key,\n bookId: book.id,\n kind: \"typography\",\n status: \"approved\",\n content: typeDep.section.content,\n approvalReceiptId: typeDep.section.approvalReceiptId,\n approvalActionDigest: typeDep.section.approvalActionDigest,\n updatedAt: typeDep.section.updatedAt,\n },\n }, receiptGuard(typeDep.receipt));\n }\n\n let approvedContent: Record<string, unknown> | null = null;\n let paletteResult: Record<string, unknown> | null = null;\n if (resolution === \"accepted\" && proposal.kind === \"palette\") {\n if (!paletteId) throw new BrandNotFoundError(\"resulting palette id\");\n paletteResult = {\n id: paletteId,\n name: capString(proposal.payload.name, \"payload.name\", 120),\n swatches: assertSwatches(proposal.payload.swatches),\n seedHex: proposal.payload.seedHex ?? null,\n receiptId,\n archivePaletteId: paletteDep.palette?.id ?? null,\n };\n } else if (resolution === \"accepted\") {\n approvedContent = assertSectionContent(\n proposal.kind,\n proposal.payload.content,\n );\n }\n const tokenSources = resolution === \"accepted\" && (\n proposal.kind === \"palette\" || proposal.kind === \"typography\"\n ) ? {\n paletteReceiptId: proposal.kind === \"palette\"\n ? receiptId\n : paletteDep.palette?.approvalReceiptId ?? null,\n paletteActionDigest: proposal.kind === \"palette\"\n ? \"this-action\"\n : paletteDep.palette?.approvalActionDigest ?? null,\n typographyReceiptId: proposal.kind === \"typography\"\n ? receiptId\n : typeDep.section?.approvalReceiptId ?? null,\n typographyActionDigest: proposal.kind === \"typography\"\n ? \"this-action\"\n : typeDep.section?.approvalActionDigest ?? null,\n } : null;\n const effectDescriptor = {\n proposalId: proposal.id,\n resolution,\n nextBookVersion: resolution === \"accepted\" ? book.version + 1 : null,\n nextActivationRevision:\n resolution === \"accepted\" ? book.activationRevision + 1 : null,\n resultingActivePaletteId: proposal.kind === \"palette\" && resolution === \"accepted\"\n ? paletteId ?? null\n : book.activePaletteId ?? null,\n palette: paletteResult,\n approvedSection: approvedContent\n ? { kind: proposal.kind, content: approvedContent, receiptId }\n : null,\n tokenSources,\n };\n const binding: BrandDecisionBinding = {\n version: 1,\n bookVersion: book.version,\n activationRevision: book.activationRevision,\n activePaletteId: book.activePaletteId ?? null,\n memberIdsDigest: await brandJsonDigest(book.memberIds),\n activePaletteDigest: paletteDep.palette\n ? await brandJsonDigest({\n id: paletteDep.palette.id,\n swatches: paletteDep.palette.swatches,\n approvalReceiptId: paletteDep.palette.approvalReceiptId,\n approvalActionDigest: paletteDep.palette.approvalActionDigest,\n })\n : null,\n typographyDigest: typeDep.section\n ? await brandJsonDigest({\n key: typeDep.section.key,\n content: typeDep.section.content,\n approvalReceiptId: typeDep.section.approvalReceiptId,\n approvalActionDigest: typeDep.section.approvalActionDigest,\n })\n : null,\n sourceAssetDigest: source\n ? await brandJsonDigest(source)\n : null,\n effectDigest: await brandJsonDigest(effectDescriptor),\n };\n return {\n ...(paletteDep.palette ? { priorPalette: paletteDep.palette } : {}),\n ...(typeDep.section ? { approvedTypography: typeDep.section } : {}),\n binding,\n effectDescriptor,\n dependencyGuards,\n };\n}\n","// Decisions consume one credential-bound central `human_exact` authority use.\n// Local receipts are immutable projections; their hash proves consistency,\n// while authenticity comes only from the host's central receipt verifier.\nimport { BRAND_NS } from \"../constants\";\nimport {\n BrandConflictError,\n BrandForbiddenError,\n BrandNotFoundError,\n BrandReviewStateChangedError,\n} from \"../errors\";\nimport {\n brandAuthorityRef,\n brandJsonDigest,\n canonicalBrandJson,\n verifyBrandApprovalReceipt,\n} from \"../review\";\nimport type {\n BrandApprovalReceipt,\n BrandProposal,\n BrandTransactGuard,\n} from \"../types\";\nimport {\n json,\n loadMemberBook,\n methodNotAllowed,\n readJson,\n type BrandRouteCtx,\n} from \"./http\";\nimport {\n parseProposalResolutionRequest,\n proposalGuardEquals,\n proposalReviewSnapshot,\n} from \"./proposal-input\";\nimport { proposalDecisionOps } from \"./proposal-effects\";\nimport {\n consumeProposalAuthority,\n proposalReceiptByMutation,\n proposalResolutionMutationKey,\n sameProposalResolutionRequest,\n} from \"./proposal-resolution-receipts\";\nimport { proposalDecisionState } from \"./proposal-state\";\n\nexport { proposalResolutionMutationKey } from \"./proposal-resolution-receipts\";\n\nconst record = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\nconst sameStrings = (left: string[], right: string[]): boolean =>\n left.length === right.length && left.every((value, index) => value === right[index]);\nconst guardFailure = (error: unknown): boolean =>\n record(error) && error.code === \"transact_guard_failed\";\n\n/** `POST /books/:bookId/proposals/:proposalId/resolve` — direct human member\n * plus current app owner/co-owner central approval. */\nexport async function handleProposalResolution(\n ctx: BrandRouteCtx,\n req: Request,\n bookId: string,\n proposalId: string,\n): Promise<Response> {\n if (req.method !== \"POST\") return methodNotAllowed();\n const book = await loadMemberBook(ctx.db, bookId, ctx.actor.id);\n if (ctx.actor.kind !== \"human\")\n throw new BrandForbiddenError(\"only a directly authenticated human can resolve a proposal\");\n\n const body = await readJson(req);\n const {\n mutationId,\n resolution,\n reviewed,\n resolutionNote,\n } = parseProposalResolutionRequest(body, bookId, proposalId);\n const mutationKey = await proposalResolutionMutationKey(\n bookId,\n proposalId,\n mutationId,\n );\n const stable = (await brandJsonDigest({ mutationKey })).slice(7);\n const receiptId = `brand-receipt-${stable.slice(0, 32)}`;\n const paletteId = resolution === \"accepted\" && reviewed.kind === \"palette\"\n ? `brand-palette-${stable.slice(32)}`\n : undefined;\n\n // Completed retries re-authenticate and replay the exact central receipt;\n // they never need the now-resolved proposal row.\n const existing = await proposalReceiptByMutation(ctx, mutationKey);\n if (existing) {\n if (\n !(await verifyBrandApprovalReceipt(existing)) ||\n !sameProposalResolutionRequest(\n existing, reviewed, resolution, resolutionNote, paletteId,\n )\n ) throw new BrandConflictError(\"mutationId was used for another decision\");\n const replayed = await consumeProposalAuthority(\n ctx, req, bookId, proposalId, existing.actionDigest, mutationKey,\n );\n if (\n canonicalBrandJson(replayed) !==\n canonicalBrandJson(existing.authorityConsumption)\n ) throw new BrandConflictError(\"central approval receipt changed\");\n return json({ receipt: existing, duplicate: true });\n }\n\n const result = await ctx.db.query({\n [BRAND_NS.proposal]: {\n $: { where: { id: proposalId, bookId } },\n book: {},\n },\n });\n const proposal = (result[BRAND_NS.proposal] ?? [])[0] as\n | (BrandProposal & { book?: Array<{ id: string }> })\n | undefined;\n if (\n !proposal ||\n proposal.bookId !== book.id ||\n !Array.isArray(proposal.book) ||\n proposal.book.length !== 1 ||\n proposal.book[0]?.id !== book.id\n ) throw new BrandNotFoundError(`proposal ${proposalId}`);\n const current = proposalReviewSnapshot(proposal);\n const { reviewDigest, ...unsignedReview } = current;\n if (\n (await brandJsonDigest(unsignedReview)) !== reviewDigest ||\n canonicalBrandJson(current) !== canonicalBrandJson(reviewed)\n ) throw new BrandConflictError(\"proposal changed since review\");\n // Acceptance applies live effects and therefore requires a fresh review\n // against the current roster. Rejection applies no Brand materialization:\n // a current human owner who remains a book member may close the exact\n // immutable stale proposal instead of leaving it permanently unresolvable.\n if (resolution === \"accepted\" && !sameStrings(current.audience, book.memberIds))\n throw new BrandConflictError(\"book membership changed; review the proposal again\");\n\n const state = await proposalDecisionState(\n ctx, req, book, proposal, resolution, receiptId, paletteId,\n );\n const actionDigest = await brandJsonDigest({\n version: 1,\n reviewedProposal: current,\n resolution,\n resolutionNote: resolutionNote ?? null,\n paletteId: paletteId ?? null,\n decisionBinding: state.binding,\n });\n const authority = await consumeProposalAuthority(\n ctx, req, bookId, proposalId, actionDigest, mutationKey,\n );\n const receiptBase = {\n version: 1 as const,\n id: receiptId,\n mutationKey,\n bookId,\n proposalId,\n resolution,\n ...(paletteId ? { paletteId } : {}),\n ...(resolutionNote ? { resolutionNote } : {}),\n reviewedProposal: current,\n actionDigest,\n decisionBinding: state.binding,\n approvedBy: ctx.actor.id,\n approvedByKind: \"human\" as const,\n appliedBy: ctx.actor.id,\n appliedByKind: \"human\" as const,\n authorityRef: brandAuthorityRef(authority),\n authorityCapability: \"brand.approve\" as const,\n authorityConsumption: authority,\n createdAt: authority.consumedAt,\n };\n const receipt: BrandApprovalReceipt = {\n ...receiptBase,\n receiptDigest: await brandJsonDigest(receiptBase),\n };\n const ops = await proposalDecisionOps({\n proposal: { ...proposal, audience: [...book.memberIds] },\n book,\n resolution,\n receiptId,\n actionDigest,\n ...(paletteId ? { paletteId } : {}),\n ...(state.priorPalette ? { priorPalette: state.priorPalette } : {}),\n ...(state.approvedTypography\n ? { approvedTypography: state.approvedTypography }\n : {}),\n actorId: ctx.actor.id,\n now: authority.consumedAt,\n resolutionNote,\n });\n ops.push({\n t: \"update\",\n ns: BRAND_NS.approvalReceipt,\n id: receipt.id,\n attrs: receipt,\n }, {\n t: \"link\",\n ns: BRAND_NS.approvalReceipt,\n id: receipt.id,\n label: \"book\",\n target: bookId,\n });\n const guards: BrandTransactGuard[] = [\n {\n ns: BRAND_NS.proposal,\n id: proposalId,\n exists: true,\n equals: proposalGuardEquals(current),\n },\n { ns: BRAND_NS.approvalReceipt, id: receiptId, exists: false },\n {\n ns: BRAND_NS.book,\n id: bookId,\n exists: true,\n equals: {\n version: book.version,\n activationRevision: book.activationRevision,\n memberIds: book.memberIds,\n },\n },\n ...state.dependencyGuards,\n ];\n if (paletteId) {\n guards.push({ ns: BRAND_NS.palette, id: paletteId, exists: false });\n }\n try {\n const tx = await ctx.db.transact(ops, {\n mutationId: mutationKey,\n guards,\n asUser: ctx.actor.id,\n ...(ctx.actor.email ? { asEmail: ctx.actor.email } : {}),\n asPrincipalKind: \"human\",\n });\n if (tx.duplicate) {\n const replay = await proposalReceiptByMutation(ctx, mutationKey);\n if (\n !replay ||\n !(await verifyBrandApprovalReceipt(replay)) ||\n !sameProposalResolutionRequest(\n replay, reviewed, resolution, resolutionNote, paletteId,\n ) ||\n canonicalBrandJson(replay.authorityConsumption) !==\n canonicalBrandJson(authority)\n )\n throw new BrandConflictError(\"proposal decision replay is invalid\");\n return json({ receipt: replay, duplicate: true });\n }\n return json({ receipt, duplicate: false });\n } catch (error) {\n if (guardFailure(error)) throw new BrandReviewStateChangedError();\n throw error;\n }\n}\n","// Tokens are served only from an approval-bound cache. GET never compiles\n// drafts or repairs stale state; any missing/mismatched dependency fails\n// closed until a new human-approved activation recompiles the cache.\nimport { BRAND_NS } from \"../constants\";\nimport { BrandNotFoundError } from \"../errors\";\nimport { brandJsonDigest, verifyBrandApprovalReceipt } from \"../review\";\nimport { renderTokensCss } from \"../tokens/css\";\nimport type { BrandTokens } from \"../tokens/types\";\nimport type {\n BrandActor,\n BrandApprovalReceipt,\n BrandBook,\n BrandPalette,\n BrandSection,\n BrandTokensSnapshot,\n} from \"../types\";\nimport { json, loadBook, loadMemberBook, methodNotAllowed } from \"./http\";\n\nconst record = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\nconst missing = (bookId: string): never => {\n throw new BrandNotFoundError(`compiled tokens for brand book ${bookId}`);\n};\n\nasync function acceptedReceipt(\n db: Parameters<typeof loadBook>[0],\n bookId: string,\n receiptId: string,\n actionDigest: string,\n): Promise<BrandApprovalReceipt> {\n const result = await db.query({\n [BRAND_NS.approvalReceipt]: {\n $: { where: { id: receiptId, bookId } },\n book: {},\n },\n });\n const receipt = (result[BRAND_NS.approvalReceipt] ?? [])[0] as\n | (BrandApprovalReceipt & { book?: Array<{ id: string }> })\n | undefined;\n if (\n !receipt ||\n receipt.resolution !== \"accepted\" ||\n receipt.actionDigest !== actionDigest ||\n !Array.isArray(receipt.book) ||\n receipt.book.length !== 1 ||\n receipt.book[0]?.id !== bookId\n ) return missing(bookId);\n const { book: _book, ...unhydrated } = receipt;\n if (!(await verifyBrandApprovalReceipt(unhydrated))) return missing(bookId);\n return unhydrated as BrandApprovalReceipt;\n}\n\nasync function approvedCache(\n db: Parameters<typeof loadBook>[0],\n book: BrandBook,\n): Promise<BrandTokensSnapshot> {\n const cache = book.tokens;\n if (\n !cache ||\n !record(cache.light) ||\n !record(cache.dark) ||\n !book.activePaletteId ||\n cache.paletteId !== book.activePaletteId ||\n !cache.paletteReceiptId ||\n !cache.paletteActionDigest ||\n !cache.sourceDigest\n ) return missing(book.id);\n const paletteResult = await db.query({\n [BRAND_NS.palette]: {\n $: { where: { id: cache.paletteId, bookId: book.id } },\n book: {},\n },\n });\n const palette = (paletteResult[BRAND_NS.palette] ?? [])[0] as\n | (BrandPalette & { book?: Array<{ id: string }> })\n | undefined;\n if (\n !palette ||\n palette.status !== \"active\" ||\n palette.approvalReceiptId !== cache.paletteReceiptId ||\n palette.approvalActionDigest !== cache.paletteActionDigest ||\n !Array.isArray(palette.book) ||\n palette.book.length !== 1 ||\n palette.book[0]?.id !== book.id\n ) return missing(book.id);\n await acceptedReceipt(\n db, book.id, cache.paletteReceiptId, cache.paletteActionDigest,\n );\n\n const hasTypeId = cache.typographyReceiptId !== undefined;\n const hasTypeDigest = cache.typographyActionDigest !== undefined;\n if (hasTypeId !== hasTypeDigest) return missing(book.id);\n const sectionResult = await db.query({\n [BRAND_NS.section]: {\n $: { where: { key: `${book.id}:typography` } },\n book: {},\n },\n });\n const typography = (sectionResult[BRAND_NS.section] ?? [])[0] as\n | (BrandSection & { book?: Array<{ id: string }> })\n | undefined;\n if (hasTypeId) {\n if (\n !typography ||\n typography.bookId !== book.id ||\n typography.kind !== \"typography\" ||\n typography.status !== \"approved\" ||\n typography.approvalReceiptId !== cache.typographyReceiptId ||\n typography.approvalActionDigest !== cache.typographyActionDigest ||\n !Array.isArray(typography.book) ||\n typography.book.length !== 1 ||\n typography.book[0]?.id !== book.id\n ) return missing(book.id);\n await acceptedReceipt(\n db,\n book.id,\n cache.typographyReceiptId!,\n cache.typographyActionDigest!,\n );\n } else if (\n typography?.status === \"approved\" &&\n (typography.approvalReceiptId || typography.approvalActionDigest)\n ) {\n // An approved dependency exists but the cache omits it.\n return missing(book.id);\n }\n const sourceDigest = await brandJsonDigest({\n paletteId: cache.paletteId,\n paletteReceiptId: cache.paletteReceiptId,\n paletteActionDigest: cache.paletteActionDigest,\n typographyReceiptId: cache.typographyReceiptId ?? null,\n typographyActionDigest: cache.typographyActionDigest ?? null,\n });\n if (sourceDigest !== cache.sourceDigest) return missing(book.id);\n return cache;\n}\n\n/** Serve approved cached CSS/JSON, optionally public. ETags are derived from\n * immutable dependency provenance, never wall-clock timestamps. */\nexport async function handleTokens(\n db: Parameters<typeof loadBook>[0],\n req: Request,\n bookId: string,\n which: \"tokens.css\" | \"tokens.json\",\n actor: BrandActor | null,\n): Promise<Response> {\n if (req.method !== \"GET\") return methodNotAllowed();\n const book = actor === null\n ? await loadBook(db, bookId)\n : await loadMemberBook(db, bookId, actor.id);\n const cache = await approvedCache(db, book);\n const light = cache.light as BrandTokens;\n const dark = cache.dark as BrandTokens;\n if (which === \"tokens.json\") return json({ light, dark });\n const etag = `\"brand-tokens-${book.activationRevision}-${cache.sourceDigest.slice(7)}\"`;\n if (\n req.headers.get(\"if-none-match\")\n ?.split(\",\")\n .map((value) => value.trim())\n .includes(etag)\n ) return new Response(null, { status: 304, headers: { etag } });\n return new Response(renderTokensCss(light, { dark }), {\n status: 200,\n headers: {\n \"content-type\": \"text/css; charset=utf-8\",\n \"cache-control\": \"public, max-age=0, must-revalidate\",\n etag,\n },\n });\n}\n","import { BRAND_NS } from \"../constants\";\nimport {\n brandDiscussionReferenceHref,\n brandDiscussionReferenceId,\n parseBrandDiscussionReference,\n type BrandDiscussionReference,\n type BrandDiscussionReferenceKind,\n type BrandDiscussionReferenceTarget,\n} from \"../discussion-reference\";\nimport type {\n BrandApprovalReceipt,\n BrandAsset,\n BrandBook,\n BrandPalette,\n BrandProposal,\n} from \"../types\";\nimport { isMember, json, loadMemberBook, methodNotAllowed, type BrandRouteCtx } from \"./http\";\n\ntype Child = BrandAsset | BrandPalette | BrandProposal | BrandApprovalReceipt;\n\nconst capLimit = (raw: string | null): number => {\n const parsed = Number(raw ?? 20);\n return Number.isInteger(parsed) ? Math.max(1, Math.min(parsed, 20)) : 20;\n};\n\nconst targetFromQuery = (url: URL): BrandDiscussionReferenceTarget | null => {\n const kind = url.searchParams.get(\"kind\");\n const id = url.searchParams.get(\"id\");\n if (!kind && !id) return null;\n if (!kind || !id) return null;\n const value = new URL(\"https://brand.invalid\");\n value.searchParams.set(\"odla-ref\", `${kind}/${id}`);\n return parseBrandDiscussionReference(value);\n};\n\nconst childNamespace = (\n kind: BrandDiscussionReferenceKind,\n): string | null => ({\n \"brand:asset\": BRAND_NS.asset,\n \"brand:palette\": BRAND_NS.palette,\n \"brand:proposal\": BRAND_NS.proposal,\n \"brand:receipt\": BRAND_NS.approvalReceipt,\n} as Partial<Record<BrandDiscussionReferenceKind, string>>)[kind] ?? null;\n\nconst childTarget = (\n kind: Exclude<BrandDiscussionReferenceKind, \"brand:book\">,\n row: Child,\n): BrandDiscussionReferenceTarget => ({\n kind,\n bookId: row.bookId,\n resourceId: row.id,\n});\n\nconst projection = (\n req: Request,\n ctx: BrandRouteCtx,\n book: BrandBook,\n target: BrandDiscussionReferenceTarget,\n row: BrandBook | Child,\n): BrandDiscussionReference => {\n let label = book.name;\n let hint = `${book.status} brand book`;\n let summary = `${book.name} brand book`;\n let status: string = book.status;\n let destination = \"Brand Studio · Brand book\";\n if (target.kind === \"brand:asset\") {\n const asset = row as BrandAsset;\n label = asset.title?.trim() || `${asset.kind} asset`;\n hint = `${book.name} · ${asset.status}`;\n summary = `${asset.kind} source asset in ${book.name}`;\n status = asset.status;\n destination = \"Brand Studio · Conversation\";\n } else if (target.kind === \"brand:palette\") {\n const palette = row as BrandPalette;\n label = palette.name;\n hint = `${book.name} · ${palette.status} palette`;\n summary = `${palette.swatches.length}-color palette in ${book.name}`;\n status = palette.status;\n destination = \"Brand Studio · Review changes\";\n } else if (target.kind === \"brand:proposal\") {\n const proposal = row as BrandProposal;\n label = `${proposal.kind} proposal`;\n hint = `${book.name} · ${proposal.status}`;\n summary = proposal.rationale;\n status = proposal.status;\n destination = \"Brand Studio · Review changes\";\n } else if (target.kind === \"brand:receipt\") {\n const receipt = row as BrandApprovalReceipt;\n label = `${receipt.resolution} ${receipt.reviewedProposal.kind} change`;\n hint = `${book.name} · approval receipt`;\n summary = `${receipt.resolution} ${receipt.reviewedProposal.kind} decision`;\n status = receipt.resolution;\n destination = \"Brand Studio · Review changes\";\n }\n return {\n kind: target.kind,\n id: brandDiscussionReferenceId(target),\n label,\n hint,\n summary,\n status,\n destination,\n href: brandDiscussionReferenceHref(\n new URL(req.url),\n target,\n ctx.discussionBasePath,\n ),\n };\n};\n\nasync function exact(\n ctx: BrandRouteCtx,\n req: Request,\n target: BrandDiscussionReferenceTarget,\n): Promise<BrandDiscussionReference[]> {\n const book = await loadMemberBook(ctx.db, target.bookId, ctx.actor.id)\n .catch(() => null);\n if (!book) return [];\n if (target.kind === \"brand:book\") {\n return [projection(req, ctx, book, target, book)];\n }\n const namespace = childNamespace(target.kind);\n if (!namespace || !target.resourceId) return [];\n const result = await ctx.db.query({\n [namespace]: {\n $: { where: { id: target.resourceId }, limit: 1 },\n },\n });\n const row = (result[namespace] ?? [])[0] as Child | undefined;\n if (\n !row ||\n row.bookId !== book.id ||\n (target.kind === \"brand:asset\" && (row as BrandAsset).status !== \"live\")\n ) return [];\n return [projection(req, ctx, book, target, row)];\n}\n\nconst matches = (\n item: BrandDiscussionReference,\n needle: string,\n): boolean => !needle ||\n `${item.label}\\n${item.hint}\\n${item.id}`.toLowerCase().includes(needle);\n\nasync function search(\n ctx: BrandRouteCtx,\n req: Request,\n url: URL,\n): Promise<BrandDiscussionReference[]> {\n const result = await ctx.db.query({\n [BRAND_NS.book]: { $: { order: { updatedAt: \"desc\" }, limit: 100 } },\n [BRAND_NS.asset]: { $: { order: { createdAt: \"desc\" }, limit: 100 } },\n [BRAND_NS.palette]: { $: { order: { updatedAt: \"desc\" }, limit: 100 } },\n [BRAND_NS.proposal]: { $: { order: { createdAt: \"desc\" }, limit: 100 } },\n [BRAND_NS.approvalReceipt]: {\n $: { order: { createdAt: \"desc\" }, limit: 100 },\n },\n });\n const books = ((result[BRAND_NS.book] ?? []) as unknown as BrandBook[])\n .filter((book) => isMember(book, ctx.actor.id));\n const bookById = new Map(books.map((book) => [book.id, book]));\n const items = books.map((book) =>\n projection(req, ctx, book, { kind: \"brand:book\", bookId: book.id }, book)\n );\n const append = (\n kind: Exclude<BrandDiscussionReferenceKind, \"brand:book\">,\n rows: unknown[],\n ) => {\n for (const row of rows as Child[]) {\n const book = bookById.get(row.bookId);\n if (\n !book ||\n (kind === \"brand:asset\" && (row as BrandAsset).status !== \"live\")\n ) continue;\n items.push(projection(req, ctx, book, childTarget(kind, row), row));\n }\n };\n append(\"brand:asset\", result[BRAND_NS.asset] ?? []);\n append(\"brand:palette\", result[BRAND_NS.palette] ?? []);\n append(\"brand:proposal\", result[BRAND_NS.proposal] ?? []);\n append(\"brand:receipt\", result[BRAND_NS.approvalReceipt] ?? []);\n const needle = (url.searchParams.get(\"q\") ?? \"\").trim().toLowerCase()\n .slice(0, 120);\n return items.filter((item) => matches(item, needle))\n .slice(0, capLimit(url.searchParams.get(\"limit\")));\n}\n\n/**\n * Authenticated product-owned Brand reference search and exact resolution.\n * Membership and row existence are checked here, never inferred by Registry.\n */\nexport async function handleBrandDiscussionReferences(\n ctx: BrandRouteCtx,\n req: Request,\n url: URL,\n): Promise<Response> {\n if (req.method !== \"GET\") return methodNotAllowed();\n const kind = url.searchParams.get(\"kind\");\n const id = url.searchParams.get(\"id\");\n if ((kind && !id) || (!kind && id)) return json({ error: \"kind and id must be paired\" }, 400);\n const target = targetFromQuery(url);\n if ((kind || id) && !target) return json({ items: [] });\n return json({\n items: target ? await exact(ctx, req, target) : await search(ctx, req, url),\n });\n}\n","// The mountable route factory (crm's createCrmRoutes contract): the host\n// worker composes it —\n// const brandRoutes = createBrandRoutes({ db, authorize, … });\n// return (await brandRoutes(request)) ?? next(request);\n// — keeping full ownership of auth (`authorize`) and the admin db key.\nimport { handleAssetContent, handleAssetItem, handleAssetsRoot } from \"./assets\";\nimport { handleBookItem, handleBookMembers, handleBooksRoot } from \"./books\";\nimport { errorResponse, json, type BrandRouteCtx, type BrandRouteOpts } from \"./http\";\nimport { handleProposalResolution } from \"./proposals\";\nimport { handleTokens } from \"./tokens\";\nimport { handleBrandDiscussionReferences } from \"./discussion-references\";\n\nexport type { BrandRouteCtx, BrandRouteOpts } from \"./http\";\nexport { proposalReviewSnapshot } from \"./proposal-input\";\n\ntype TokensFile = \"tokens.css\" | \"tokens.json\";\n\n/** `/books/:id/tokens.css|json` recognizer — the only publicTokens-eligible paths. */\nconst tokensFile = (seg: string[]): TokensFile | null =>\n seg.length === 3 && seg[0] === \"books\" && (seg[2] === \"tokens.css\" || seg[2] === \"tokens.json\")\n ? (seg[2] as TokensFile)\n : null;\n\nasync function route(\n ctx: BrandRouteCtx,\n req: Request,\n url: URL,\n seg: string[],\n): Promise<Response | null> {\n const [head, id, sub, subId, action] = seg;\n if (head === \"discussion-references\" && seg.length === 1)\n return handleBrandDiscussionReferences(ctx, req, url);\n if (head !== \"books\") return null;\n if (seg.length === 1) return handleBooksRoot(ctx, req);\n if (seg.length === 2) return handleBookItem(ctx, req, id!);\n if (seg.length === 3 && sub === \"members\") return handleBookMembers(ctx, req, id!);\n if (sub === \"assets\") {\n if (seg.length === 3) return handleAssetsRoot(ctx, req, id!);\n if (seg.length === 4) return handleAssetItem(ctx, req, id!, subId!);\n if (seg.length === 5 && action === \"content\")\n return handleAssetContent(ctx, req, id!, subId!);\n return null;\n }\n if (sub === \"proposals\" && seg.length === 5 && action === \"resolve\")\n return handleProposalResolution(ctx, req, id!, subId!);\n const file = tokensFile(seg);\n if (file) return handleTokens(ctx.db, req, id!, file, ctx.actor);\n return null;\n}\n\n/**\n * Build the brand fetch handler. Returns `null` for requests outside\n * `basePath` (default `/api/brand`) so the host worker falls through to its\n * own routes; inside it, every route requires `authorize` to resolve an\n * actor (401 otherwise) EXCEPT the two tokens routes when `publicTokens` is\n * true — compiled tokens are the one intentionally publishable surface.\n * Domain errors map to 400/404 JSON; anything unexpected is an opaque 500.\n */\nexport function createBrandRoutes(options: BrandRouteOpts): (req: Request) => Promise<Response | null> {\n const basePath = options.basePath ?? \"/api/brand\";\n const publicTokens = options.publicTokens === true;\n const base = {\n db: options.db,\n appId: options.appId,\n authorizeCapability: options.authorizeCapability,\n consumeHumanExact: options.consumeHumanExact,\n verifySourceAssetSnapshot: options.verifySourceAssetSnapshot,\n now: options.now ?? Date.now,\n newId: options.newId ?? (() => crypto.randomUUID()),\n maxUploadBytes: options.maxUploadBytes ?? 8 * 1024 * 1024,\n discussionBasePath: options.discussionBasePath ?? \"/\",\n };\n return async (req: Request): Promise<Response | null> => {\n const url = new URL(req.url);\n if (url.pathname !== basePath && !url.pathname.startsWith(`${basePath}/`)) return null;\n const seg = url.pathname.slice(basePath.length).split(\"/\").filter(Boolean);\n try {\n const file = tokensFile(seg);\n if (publicTokens && file) return await handleTokens(base.db, req, seg[1]!, file, null);\n const actor = await (\n seg[0] === \"discussion-references\"\n ? options.authorizeDiscussionReferences ?? options.authorize\n : options.authorize\n )(req);\n if (!actor) return json({ error: \"unauthorized\" }, 401);\n return (await route({ ...base, actor }, req, url, seg)) ??\n json({ error: \"not found\" }, 404);\n } catch (error) {\n return errorResponse(error);\n }\n };\n}\n","import { BRAND_NS } from \"./constants\";\nimport type { BrandAsset, BrandBook, BrandDb } from \"./types\";\n\nconst MAX_MESSAGE_ASSETS = 12;\n\nfunction candidateAssetIds(row: Record<string, unknown>): string[] {\n const standard = Array.isArray(row.attachments)\n ? row.attachments.flatMap((value) => {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return [];\n const id = (value as Record<string, unknown>).id;\n return typeof id === \"string\" && id.length > 0 && id.length <= 200\n ? [id]\n : [];\n })\n : [];\n // Compatibility for rows written before standard Chat attachments were\n // included in the initial message transaction.\n const legacy = Array.isArray(row.assetIds)\n ? row.assetIds.filter((value): value is string =>\n typeof value === \"string\" && value.length > 0 && value.length <= 200)\n : [];\n return [...new Set([...standard, ...legacy])].slice(0, MAX_MESSAGE_ASSETS);\n}\n\n/** Reload message attachment ids against the exact live linked Brand book. */\nexport async function attachedBrandAssetIds(\n db: BrandDb,\n book: BrandBook,\n row: Record<string, unknown>,\n): Promise<string[]> {\n const candidates = candidateAssetIds(row);\n const assets = await Promise.all(candidates.map(async (id) => {\n const result = await db.query({\n [BRAND_NS.asset]: {\n $: { where: { id, bookId: book.id, status: \"live\" }, limit: 2 },\n book: { $: { limit: 2 } },\n },\n });\n const rows = result[BRAND_NS.asset] ?? [];\n if (rows.length !== 1) return null;\n const asset = rows[0] as BrandAsset & { book?: Array<{ id: string }> };\n return asset.id === id &&\n asset.bookId === book.id &&\n asset.status === \"live\" &&\n asset.deletedAt === undefined &&\n Array.isArray(asset.book) &&\n asset.book.length === 1 &&\n asset.book[0]?.id === book.id\n ? id\n : null;\n }));\n return assets.filter((id): id is string => id !== null);\n}\n","// Commit-trigger config brand installs into odla-db (POST to\n// `/app/:id/admin/triggers`), mirroring @odla-ai/chat's botTrigger: the\n// @odla/server commit hook fires on matching human-authored chat-message\n// writes and dispatches to the host's agent worker with `skill: \"brand\"`.\n// Two deployment modes, both this one builder:\n// - global mention-gated: one bot, `mention: \"@brand\"`, no `channels`;\n// - per-book channel-scoped: `channels: [book.channelId]`, no mention.\n\n/** The odla-db namespace chat messages live in.\n * PROVENANCE: @odla-ai/chat `CHAT_NS.message` (packages/chat/src/constants.ts)\n * — duplicated as a local const because this package is zero-dep and the wire\n * value is a stable contract, not an implementation detail. */\nexport const CHAT_MESSAGE_NS = \"chat_message\";\n\n/** Matches @odla/server's `Trigger` (the exact JSON POSTed to\n * `/app/:id/admin/triggers`) — the same wire shape as chat's `ChatTrigger`. */\nexport interface BrandTrigger {\n id: string;\n watch: { ns: string; on: \"create\" | \"update\" };\n when?: string;\n runAs: { agentId: string; persona: string };\n skill: string;\n maxDepth?: number;\n channels?: string[];\n validate?: string;\n}\n\n/** Options for {@link brandBotTrigger}. */\nexport interface BrandBotTriggerOpts {\n /** Trigger id (unique per app). */\n id: string;\n /** The bot's agent id — must be in each target book's `memberIds` roster. */\n agentId: string;\n /** Persona name the dispatching worker runs. */\n persona: string;\n /** Fire only on messages mentioning this handle, e.g. \"@brand\". */\n mention?: string;\n /** Extra CEL over the new message row, ANDed with the built-in guards. */\n when?: string;\n /** Restrict to specific channel ids (the per-book mode). */\n channels?: string[];\n /** Watched write kind (default \"create\"). */\n on?: \"create\" | \"update\";\n}\n\n/** Escape a value for embedding inside a CEL double-quoted string literal —\n * copied verbatim from @odla-ai/chat (packages/chat/src/triggers.ts):\n * `mention` is matched as literal text, so a stray quote or backslash must\n * not break out of the literal into CEL syntax. */\nconst celString = (value: string): string => value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n\n/**\n * Build a trigger that runs the brand agent on human chat messages\n * (optionally @-mentions, optionally channel-scoped): chat's `botTrigger`\n * shape with `skill: \"brand\"` and `maxDepth: 1` so a bot reply can never\n * re-trigger a bot.\n */\nexport function brandBotTrigger(opts: BrandBotTriggerOpts): BrandTrigger {\n const clauses = ['data.authorKind == \"human\"'];\n if (opts.mention) clauses.push(`data.body.contains(\"${celString(opts.mention)}\")`);\n // `when` is documented as caller-authored CEL, so it is intentionally not escaped.\n if (opts.when) clauses.push(`(${opts.when})`);\n return {\n id: opts.id,\n watch: { ns: CHAT_MESSAGE_NS, on: opts.on ?? \"create\" },\n when: clauses.join(\" && \"),\n runAs: { agentId: opts.agentId, persona: opts.persona },\n skill: \"brand\",\n maxDepth: 1,\n ...(opts.channels ? { channels: opts.channels } : {}),\n };\n}\n","// Host dispatch for one Brand chat turn. The service DB resolves the book;\n// tools receive a separate rules-scoped DB bound to the exact runAs agent.\nimport type { ImageBlock, OracleContentBlock } from \"@odla-ai/ai\";\nimport { BRAND_NS } from \"./constants\";\nimport {\n BrandConflictError,\n BrandForbiddenError,\n BrandNotFoundError,\n} from \"./errors\";\nimport { attachedBrandAssetIds } from \"./dispatch-assets\";\nimport { createBrandPersona, supportsBrandVision } from \"./skill/persona\";\nimport type { BrandSkillSelf } from \"./skill/skill\";\nimport { CHAT_MESSAGE_NS } from \"./triggers\";\nimport type { BrandBook, BrandDb } from \"./types\";\nimport type { BrandDispatchBody, BrandDispatchDeps } from \"./dispatch-types\";\nimport type { BrandPrincipalProjection } from \"./skill/agent-types\";\n\nexport type { BrandDispatchBody, BrandDispatchDeps } from \"./dispatch-types\";\nexport { attachedBrandAssetIds } from \"./dispatch-assets\";\n\n/** Strict-enough structural parse for the signed host dispatch envelope. */\nexport function parseBrandDispatch(raw: unknown): BrandDispatchBody | null {\n if (!raw || typeof raw !== \"object\") return null;\n const body = raw as Record<string, unknown>;\n const trigger = body.trigger as {\n id?: unknown;\n skill?: unknown;\n maxDepth?: unknown;\n runAs?: { agentId?: unknown; persona?: unknown };\n } | undefined;\n const event = body.event as {\n ns?: unknown;\n id?: unknown;\n row?: unknown;\n } | undefined;\n if (\n body.v !== 2 ||\n typeof body.appId !== \"string\" ||\n !body.appId ||\n typeof body.appIncarnation !== \"string\" ||\n !/^[0-9a-f]{32}$/.test(body.appIncarnation) ||\n typeof body.jobId !== \"string\" ||\n !body.jobId ||\n !trigger ||\n typeof trigger.runAs?.agentId !== \"string\" ||\n !trigger.runAs.agentId ||\n typeof trigger.runAs.persona !== \"string\" ||\n !event ||\n typeof event.id !== \"string\" ||\n !event.row ||\n typeof event.row !== \"object\" ||\n Array.isArray(event.row)\n ) return null;\n return {\n v: 2,\n appId: body.appId,\n appIncarnation: body.appIncarnation,\n jobId: body.jobId,\n trigger: {\n id: typeof trigger.id === \"string\" ? trigger.id : \"\",\n skill: typeof trigger.skill === \"string\" ? trigger.skill : \"\",\n runAs: {\n agentId: trigger.runAs.agentId,\n persona: trigger.runAs.persona,\n },\n ...(typeof trigger.maxDepth === \"number\"\n ? { maxDepth: trigger.maxDepth }\n : {}),\n },\n event: {\n ns: typeof event.ns === \"string\" ? event.ns : CHAT_MESSAGE_NS,\n id: event.id,\n row: event.row as Record<string, unknown>,\n },\n };\n}\n\n/** Channel ids are unique by schema, but ambiguity still fails closed if a\n * legacy/corrupt store returns more than one row. */\nexport async function bookForChannel(\n db: BrandDb,\n channelId: string,\n): Promise<BrandBook | null> {\n if (!channelId) return null;\n const result = await db.query({\n [BRAND_NS.book]: { $: { where: { channelId } } },\n });\n const books = (result[BRAND_NS.book] ?? []) as BrandBook[];\n if (books.length > 1)\n throw new BrandConflictError(`multiple brand books claim channel ${channelId}`);\n return books[0] ?? null;\n}\n\n/** Assemble the conversational request. Attachments remain supported as a\n * pure helper, but secure dispatch does not pass signed/private URLs here. */\nexport function brandInputFor(\n body: BrandDispatchBody,\n attachments?: ImageBlock[],\n author?: BrandPrincipalProjection,\n attachedAssetIds: readonly string[] = [],\n): string | OracleContentBlock[] {\n const row = body.event.row;\n const actor = author\n ? `${author.displayName} (${author.kind}` +\n `${author.managerDisplayName\n ? `, managed by ${author.managerDisplayName}`\n : \"\"})`\n : row.authorKind === \"bot\"\n ? \"a managed agent\"\n : \"a participant\";\n const prompt =\n `A new message arrived in this brand book's channel from ` +\n `${actor}: ` +\n `\"${String(row.body ?? \"\")}\". Ground yourself first (read_brand_book, ` +\n \"list_assets), then move the work forward. Study real material, justify \" +\n \"colors, and park exact proposals. A human approves in the Brand surface; \" +\n \"acceptance applies the reviewed facet and recompiles dependent tokens. \" +\n (attachedAssetIds.length > 0\n ? `This message atomically attached Brand asset id${attachedAssetIds.length === 1 ? \"\" : \"s\"} ` +\n `${attachedAssetIds.join(\", \")}; use view_asset on those exact ids before drawing conclusions. `\n : \"\") +\n \"Keep any chat reply concise.\";\n return attachments?.length\n ? [...attachments, { type: \"text\", text: prompt }]\n : prompt;\n}\n\n/** Preflight exact app/skill/channel/roster/live brand.read before the model\n * is invoked. Every tool revalidates its own read/edit capability as well. */\nexport async function dispatchBrandTurn(\n deps: BrandDispatchDeps,\n body: BrandDispatchBody,\n): Promise<{ finalText: string; durableOutcome: boolean }> {\n if (\n body.appId !== deps.appId ||\n body.trigger.skill !== \"brand\" ||\n body.event.ns !== CHAT_MESSAGE_NS\n ) throw new BrandForbiddenError(\"foreign or non-brand dispatch\");\n const channelId = String(body.event.row.channelId ?? \"\");\n const book = await bookForChannel(deps.db, channelId);\n if (!book)\n throw new BrandNotFoundError(\n `brand book for channel ${channelId || \"(missing channelId)\"}`,\n );\n const agentId = body.trigger.runAs.agentId;\n if (!book.memberIds.includes(agentId))\n throw new BrandNotFoundError(`brand book for channel ${channelId}`);\n const read = await deps.authorizeCapability({\n agentId,\n bookId: book.id,\n capability: \"brand.read\",\n });\n if (!read || read.capability !== \"brand.read\" || !read.authorityRef)\n throw new BrandForbiddenError(\"agent lacks live brand.read\");\n const authorId =\n typeof body.event.row.authorId === \"string\"\n ? body.event.row.authorId\n : \"\";\n const authors = authorId\n ? await deps.resolvePrincipals({\n requesterAgentId: agentId,\n bookId: book.id,\n principalIds: [authorId],\n })\n : [];\n const author = authors.find((candidate) => candidate.id === authorId);\n const attachedAssetIds = await attachedBrandAssetIds(\n deps.db,\n book,\n body.event.row,\n );\n const runtime = await deps.agentRuntimeFor({\n appId: body.appId,\n agentId,\n bookId: book.id,\n triggerId: body.trigger.id,\n eventId: body.event.id,\n jobId: body.jobId,\n });\n if (\n !runtime.credentialRef ||\n !runtime.jobId ||\n runtime.jobId !== body.jobId\n )\n throw new BrandForbiddenError(\"agent data credential is not bound\");\n let durableOutcome = false;\n const bridge = {\n ...runtime.bridge,\n createProposal: async (\n input: Parameters<typeof runtime.bridge.createProposal>[0],\n ) => {\n const proposal = await runtime.bridge.createProposal(input);\n durableOutcome = true;\n return proposal;\n },\n recordAssetAnalysis: async (\n input: Parameters<typeof runtime.bridge.recordAssetAnalysis>[0],\n ) => {\n const asset = await runtime.bridge.recordAssetAnalysis(input);\n durableOutcome = true;\n return asset;\n },\n };\n\n const visionInToolResults = supportsBrandVision(\n deps.catalog?.[deps.model],\n );\n const self: BrandSkillSelf = {\n selfId: agentId,\n kind: \"bot\",\n displayName: body.trigger.runAs.persona,\n };\n const persona = createBrandPersona({\n model: deps.model,\n brand: {\n db: runtime.db,\n bookId: book.id,\n self,\n agentDbBinding: {\n principalId: agentId,\n credentialRef: runtime.credentialRef,\n },\n agentJobId: runtime.jobId,\n agentBridge: bridge,\n authorizeCapability: deps.authorizeCapability,\n resolvePrincipals: deps.resolvePrincipals,\n visionInToolResults,\n ...(deps.newId ? { newId: deps.newId } : {}),\n },\n skills: deps.chatSkillFor\n ? [deps.chatSkillFor(channelId, self)]\n : [],\n });\n const run = await deps.runAgent(deps.inference, persona, {\n // Models without tool-result vision receive no raw/signed fallback URL.\n input: brandInputFor(body, undefined, author, attachedAssetIds),\n });\n return { finalText: run.finalText, durableOutcome };\n}\n","// The integration descriptor: documentation-as-data for the brand capability,\n// following the crm/chat pattern — what installing @odla-ai/brand into an app\n// means (schema, deny-all rules, per-bot triggers, worker mount), described\n// but not performed. The base shapes are inlined so the zero-dependency\n// package does not depend on the CLI; the CLI consumes descriptors\n// structurally from odla.config.mjs.\nimport { BRAND_SCHEMA, type SerializedSchema } from \"./schema\";\nimport { brandRules, type BrandRules } from \"./rules\";\nimport type { BrandTrigger } from \"./triggers\";\nimport {\n BRAND_AGENT_PROFILE,\n type BrandAgentProfile,\n} from \"./agent-profile\";\n\n/** One owner-facing setting the integration exposes (crm's shape). */\nexport interface IntegrationSetting {\n key: string;\n description: string;\n public: boolean;\n pattern?: string;\n perEnv: boolean;\n source: string;\n}\n\n/** One vault secret the integration needs (brand core needs none). */\nexport interface IntegrationSecret {\n key: string;\n description: string;\n pattern?: string;\n vault: boolean;\n}\n\n/** Human / CLI / doctor provisioning steps, documentation-as-data. */\nexport interface IntegrationProvision {\n human: string[];\n cli: string[];\n doctor: string[];\n}\n\n/** Unauthenticated route check run by `odla-ai smoke`. */\nexport interface BrandIntegrationProbe {\n path: string;\n expectedStatus: number;\n}\n\n/** The brand descriptor shape: the shared base plus the schema + rules\n * provisioning installs and the (app-supplied) bot triggers. */\nexport interface BrandIntegrationDescriptor {\n id: string;\n title: string;\n npm: string;\n settings: IntegrationSetting[];\n secrets: IntegrationSecret[];\n /** The schema to POST at /app/:id/schema. */\n schema: SerializedSchema;\n /** The default-deny rules to install at /app/:id/admin/rules (merged with existing). */\n rules: BrandRules;\n /** Commit triggers to register at /app/:id/admin/triggers (per-bot; app-supplied). */\n triggers: BrandTrigger[];\n /** Least-privilege agent capabilities and semantic-operation boundary. */\n agentProfile: BrandAgentProfile;\n probes?: BrandIntegrationProbe[];\n provision: IntegrationProvision;\n}\n\n/**\n * The static documentation descriptor for @odla-ai/brand. Data only: it\n * describes what installing the brand capability means — push\n * {@link BRAND_SCHEMA}, install the default-deny `brandRules()`, register\n * `brandBotTrigger`s (app-supplied, in either the global mention-gated or the\n * per-book channel-scoped mode), mount `createBrandRoutes` in the app worker\n * — and performs none of it. Use {@link createBrandIntegration} in\n * `odla.config.mjs` to add the live route probe the CLI can execute.\n */\nexport const brandIntegration: BrandIntegrationDescriptor = {\n id: \"brand\",\n title: \"Brand books (assets, palettes, proposals, design tokens)\",\n npm: \"@odla-ai/brand\",\n settings: [\n {\n key: \"basePath\",\n description: 'Route mount point the app worker serves brand under. Default \"/api/brand\".',\n public: true,\n perEnv: false,\n source: \"createBrandRoutes({ basePath }) in the app worker\",\n },\n {\n key: \"publicTokens\",\n description:\n \"Serve GET /books/:id/tokens.css and tokens.json without authorization (compiled tokens \" +\n \"only — books and assets always authorize). Default false.\",\n public: true,\n perEnv: false,\n source: \"createBrandRoutes({ publicTokens }) in the app worker\",\n },\n ],\n secrets: [],\n schema: BRAND_SCHEMA,\n rules: brandRules(),\n triggers: [],\n agentProfile: BRAND_AGENT_PROFILE,\n provision: {\n human: [\n \"Configure direct Clerk human approval through authorizeCapability + consumeHumanExact; delegated, machine, and agent principals must not resolve proposals.\",\n \"Choose the trigger mode: one global mention-gated bot (brandBotTrigger({ mention: \\\"@brand\\\" }), no channels) or per-book channel-scoped bots (channels: [book.channelId], no mention).\",\n \"Pick a model where supportsBrandVision(catalog[model]) is true for in-conversation asset viewing; secure dispatch never falls back to signed or persistent asset URLs.\",\n \"Decide whether compiled tokens are public (publicTokens serves tokens.css/tokens.json unauthenticated).\",\n ],\n cli: [\n \"POST BRAND_SCHEMA to /app/:id/schema.\",\n \"Install brandRules() at /app/:id/admin/rules (merged with the app's existing rules).\",\n \"Register a brandBotTrigger(...) per bot at /app/:id/admin/triggers — global mention-gated, or channel-scoped per book.\",\n \"Seed the bot's agent id into each brand_book.memberIds roster (audienceFanoutOps covers existing child rows).\",\n \"Issue the bot brand.read + brand.edit and expose only BRAND_AGENT_PROFILE semantic operations; deny raw brand_* writes and raw file operations.\",\n \"Provision private file signing and verifySourceAssetSnapshot; never expose an admin credential or persistent asset URL to the agent.\",\n ],\n doctor: [\n \"All six brand_* namespaces have rules installed; raw browser/agent writes are denied and child reads use current linked-book membership.\",\n \"The agent runtime matches BRAND_AGENT_PROFILE: brand.read/edit only, semantic operations only, no raw brand_* or file access.\",\n \"Proposal decisions consume a direct-human exact brand.approve authority use and persist one guarded brand_approval_receipt.\",\n \"Private source assets are signed briefly and verifySourceAssetSnapshot revalidates path, ETag, size, content type, and digest before approval.\",\n \"brand_book.id/slug, brand_section.key, and the other mirrored id attrs are unique.\",\n \"Each registered trigger's agent id is present in its target books' memberIds rosters.\",\n \"Books with channelId set point at real chat channels when @odla-ai/chat is installed.\",\n ],\n },\n};\n\n/** Options for {@link createBrandIntegration}. */\nexport interface CreateBrandIntegrationOptions {\n /** Worker mount path; defaults to `/api/brand`. */\n basePath?: string;\n /** Document (and probe-plan for) unauthenticated tokens routes. */\n publicTokens?: boolean;\n /** The global bot's mention handle — folded into the CLI trigger step. */\n mention?: string;\n}\n\n/**\n * Build the project-specific, CLI-consumable brand integration descriptor:\n * {@link brandIntegration} plus a live smoke probe (an anonymous GET of\n * `<basePath>/books` must answer 401 — routes mounted, authorize enforced,\n * exactly crm's probe idiom) and, when `mention`/`publicTokens` are given,\n * concrete CLI steps carrying the app's actual values. Mounting\n * `createBrandRoutes` remains app-owned source work.\n */\nexport function createBrandIntegration(\n options: CreateBrandIntegrationOptions = {},\n): BrandIntegrationDescriptor {\n const basePath = options.basePath ?? \"/api/brand\";\n if (!/^\\/[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/.test(basePath) || basePath.endsWith(\"/\")) {\n throw new Error(\"createBrandIntegration: basePath must be an absolute path without a trailing slash\");\n }\n const cli = [...brandIntegration.provision.cli];\n if (options.mention !== undefined)\n cli.push(`Gate the global bot on mentions: brandBotTrigger({ mention: ${JSON.stringify(options.mention)}, ... }).`);\n if (options.publicTokens === true)\n cli.push(`Mount createBrandRoutes({ publicTokens: true }) so ${basePath}/books/:id/tokens.css serves unauthenticated.`);\n return {\n ...brandIntegration,\n provision: { ...brandIntegration.provision, cli },\n probes: [{ path: `${basePath}/books`, expectedStatus: 401 }],\n };\n}\n"],"mappings":"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","names":["record","receipt","a","record","record","ops","receipt","record","sameStrings","guardFailure","receipt","record","receipt","receipt"]}