diff --git a/.agents/skills/impeccable/scripts/lib/composition-catalog.mjs b/.agents/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.agents/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.agents/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.agents/skills/impeccable/scripts/lib/roll-selection.mjs b/.agents/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.agents/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.agents/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.claude/skills/impeccable/scripts/lib/composition-catalog.mjs b/.claude/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.claude/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.claude/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.claude/skills/impeccable/scripts/lib/roll-selection.mjs b/.claude/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.claude/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.claude/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.cursor/skills/impeccable/scripts/lib/composition-catalog.mjs b/.cursor/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.cursor/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.cursor/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.cursor/skills/impeccable/scripts/lib/roll-selection.mjs b/.cursor/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.cursor/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.cursor/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.gemini/skills/impeccable/scripts/lib/composition-catalog.mjs b/.gemini/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.gemini/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.gemini/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.gemini/skills/impeccable/scripts/lib/roll-selection.mjs b/.gemini/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.gemini/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.gemini/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.github/skills/impeccable/scripts/lib/composition-catalog.mjs b/.github/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.github/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.github/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.github/skills/impeccable/scripts/lib/roll-selection.mjs b/.github/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.github/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.github/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.grok/skills/impeccable/scripts/lib/composition-catalog.mjs b/.grok/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.grok/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.grok/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.grok/skills/impeccable/scripts/lib/roll-selection.mjs b/.grok/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.grok/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.grok/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.kiro/skills/impeccable/scripts/lib/composition-catalog.mjs b/.kiro/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.kiro/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.kiro/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.kiro/skills/impeccable/scripts/lib/roll-selection.mjs b/.kiro/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.kiro/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.kiro/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.opencode/skills/impeccable/scripts/lib/composition-catalog.mjs b/.opencode/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.opencode/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.opencode/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.opencode/skills/impeccable/scripts/lib/roll-selection.mjs b/.opencode/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.opencode/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.opencode/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.pi/skills/impeccable/scripts/lib/composition-catalog.mjs b/.pi/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.pi/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.pi/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.pi/skills/impeccable/scripts/lib/roll-selection.mjs b/.pi/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.pi/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.pi/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.qoder/skills/impeccable/scripts/lib/composition-catalog.mjs b/.qoder/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.qoder/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.qoder/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.qoder/skills/impeccable/scripts/lib/roll-selection.mjs b/.qoder/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.qoder/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.qoder/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.rovodev/skills/impeccable/scripts/lib/composition-catalog.mjs b/.rovodev/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.rovodev/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.rovodev/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.rovodev/skills/impeccable/scripts/lib/roll-selection.mjs b/.rovodev/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.rovodev/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.rovodev/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.trae-cn/skills/impeccable/scripts/lib/composition-catalog.mjs b/.trae-cn/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.trae-cn/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.trae-cn/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.trae-cn/skills/impeccable/scripts/lib/roll-selection.mjs b/.trae-cn/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.trae-cn/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.trae-cn/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.trae/skills/impeccable/scripts/lib/composition-catalog.mjs b/.trae/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.trae/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.trae/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.trae/skills/impeccable/scripts/lib/roll-selection.mjs b/.trae/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.trae/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.trae/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/.vibe/skills/impeccable/scripts/lib/composition-catalog.mjs b/.vibe/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/.vibe/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/.vibe/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/.vibe/skills/impeccable/scripts/lib/roll-selection.mjs b/.vibe/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/.vibe/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/.vibe/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[] diff --git a/plugin/skills/impeccable/scripts/lib/composition-catalog.mjs b/plugin/skills/impeccable/scripts/lib/composition-catalog.mjs index fc4d76fd4..d0a6d4cc8 100644 --- a/plugin/skills/impeccable/scripts/lib/composition-catalog.mjs +++ b/plugin/skills/impeccable/scripts/lib/composition-catalog.mjs @@ -1,6 +1,11 @@ import crypto from 'node:crypto'; import { readFileSync } from 'node:fs'; import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs'; +// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file +// reads the filesystem, and the roll API imports the taxonomy to validate its +// area parameter. Re-exported so existing importers keep working. +import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs'; +export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS }; // Catalog B: compositions rather than styles. A composition organizes attention, // sequence, or manipulation on a surface and must survive being dressed in @@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [ // composition are different species, and read/experience surfaces get their own. export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']); -// Areas of concern, one level below surface. Surface alone is too coarse to deal -// against: "operate" spans onboarding, settings, dashboards and editors, so a -// build designing an onboarding flow could legitimately draw a settings -// composition and the input would read as noise. Areas name the problem the -// composition is about, not how it is built, which is what familyId already does. -// -// `area` is optional. An entry without one is eligible for any request in its -// surface, so nothing has to be backfilled before this ships, and a request for -// an area with a thin pool tops up from the rest of the surface rather than -// dealing fewer. -export const COMPOSITION_AREAS = { - persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], - operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], - read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], - experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], -}; - -export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); - -export function areasForSurface(surface) { - return COMPOSITION_AREAS[surface] ?? []; -} export function compositionContentHash(composition) { const payload = [ diff --git a/plugin/skills/impeccable/scripts/lib/roll-selection.mjs b/plugin/skills/impeccable/scripts/lib/roll-selection.mjs index 019a1330a..42964b207 100644 --- a/plugin/skills/impeccable/scripts/lib/roll-selection.mjs +++ b/plugin/skills/impeccable/scripts/lib/roll-selection.mjs @@ -21,6 +21,30 @@ export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere']; +// Areas of concern, one level below surface. Surface alone is too coarse to deal +// against: "operate" spans onboarding, settings, dashboards and editors, so a +// build designing an onboarding flow could legitimately draw a settings +// composition and the input would read as noise. Areas name the problem the +// composition is about, not how it is built, which is what familyId already does. +// +// `area` is optional. An entry without one is eligible for any request in its +// surface, so nothing has to be backfilled before this ships, and a request for +// an area with a thin pool tops up from the rest of the surface rather than +// dealing fewer. +export const COMPOSITION_AREAS = { + persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'], + operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'], + read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'], + experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'], +}; + +export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat()); + +export function areasForSurface(surface) { + return COMPOSITION_AREAS[surface] ?? []; +} + + /** * Drives a selection generator with a synchronous hash. * @param {Generator} generator yields string[] to hash, resumes with hex string[]