Add world roll API and seed telemetry client

/api/roll deals deterministic challenger rolls server-side (same salts and
sha256 ranking as the local seed, verified bit-for-bit); the request log is
the impression record. /api/chosen takes the anonymous choice ping. Events
land in Workers Analytics Engine.

concept-seed.mjs resolves data in order: local catalog dir, roll API,
degraded promotion-only seed. --chosen sends the choice ping; DO_NOT_TRACK
and IMPECCABLE_NO_TELEMETRY disable it. API-dealt seeds carry the telemetry
instruction inline.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-07-20 22:17:09 -07:00
co-authored by Claude Fable 5
parent 7557935fdb
commit b5ec969c07
17 changed files with 15904 additions and 48 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+222
View File
@@ -0,0 +1,222 @@
// Shared world-roll logic for the /api/roll and /api/chosen endpoints.
//
// This mirrors the selection mechanics in skill/scripts/concept-seed.mjs
// exactly (same salts, same sha256 ranking, same rating weights), computed
// with Web Crypto because Workers have no sync hash. Same key + same pool
// revision therefore reproduces a roll bit-for-bit.
//
// Catalog data is bundled at deploy time from functions/api/_data/, refreshed
// by scripts/sync-api-data.mjs. The catalog never ships to clients in full:
// a roll exposes exactly the entries it deals.
import conceptCatalog from './_data/concept-ingredients.json';
import conceptReviews from './_data/concept-reviews.json';
import compositionCatalog from './_data/composition-ingredients.json';
import compositionReviews from './_data/composition-reviews.json';
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
export const SEED_MODES = new Set(['persuade', 'operate', 'read', 'experience']);
const encoder = new TextEncoder();
async function sha256Hex(input) {
const digest = await crypto.subtle.digest('SHA-256', encoder.encode(input));
return [...new Uint8Array(digest)].map(byte => byte.toString(16).padStart(2, '0')).join('');
}
async function deterministicRank(items, input, idFor = item => item.id) {
const scored = await Promise.all(items.map(async item => ({
item,
id: idFor(item),
score: await sha256Hex(`${input}:${idFor(item)}`),
})));
scored.sort((a, b) => b.score.localeCompare(a.score) || a.id.localeCompare(b.id));
return scored.map(entry => entry.item);
}
function mergeConcepts() {
const reviews = conceptReviews.reviews || {};
const wellsById = new Map((conceptCatalog.wells || []).map(well => [well.id, well]));
const concepts = [];
for (const family of conceptCatalog.families || []) {
for (const concept of family.concepts || []) {
concepts.push({
...concept,
familyId: family.id,
wellTier: wellsById.get(family.well)?.tier || null,
status: reviews[concept.id]?.status || 'pending',
review: reviews[concept.id] || null,
});
}
}
return concepts;
}
function mergeCompositions() {
const reviews = compositionReviews.reviews || {};
return (compositionCatalog.compositions || []).map(composition => ({
...composition,
status: reviews[composition.id]?.status || 'pending',
}));
}
export async function approvedPoolRevision(concepts) {
const payload = concepts
.filter(concept => concept.status === 'approved')
.map(concept => `${concept.familyId}:${concept.id}:${concept.strength}:${concept.form}:${concept.spark}:${JSON.stringify(concept.system)}:${concept.webLeverage}`)
.sort()
.join('\n');
return (await sha256Hex(payload)).slice(0, 12);
}
export async function selectApprovedChallengers({ scope, key, reroll = 0, concepts }) {
const approved = concepts.filter(concept => concept.status === 'approved');
const wanted = scope === 'direction'
? new Set(['world', 'dual'])
: new Set(['composition', 'dual']);
const approvedByTier = new Map();
for (const concept of approved) {
const tier = approvedByTier.get(concept.wellTier) || [];
tier.push(concept);
approvedByTier.set(concept.wellTier, tier);
}
if (WELL_TIERS.some(tier => !(approvedByTier.get(tier) || []).length)) {
throw new Error('every challenger tier needs at least one approved concept');
}
for (const [tier, pool] of approvedByTier) {
const matching = pool.filter(concept => wanted.has(concept.strength));
if (matching.length > 0) approvedByTier.set(tier, matching);
}
const ticketsFor = pool => pool.flatMap(concept => {
const rating = concept.review?.rating;
if (rating === 1) return [];
return rating === 3
? [{ concept, ticket: 0 }, { concept, ticket: 1 }]
: [{ concept, ticket: 0 }];
});
const pickRound = async (round, excluded) => {
const salt = round === 0 ? '' : `:reroll-${round}`;
const tierOrder = (await deterministicRank(
WELL_TIERS.map(id => ({ id })),
`${scope}:${key}:tiers${salt}`
)).map(item => item.id);
const picks = [];
for (const [index, tier] of tierOrder.entries()) {
let pool = approvedByTier.get(tier).filter(concept => !excluded.has(concept.id));
if (pool.length === 0) pool = approvedByTier.get(tier);
let tickets = ticketsFor(pool);
if (tickets.length === 0) tickets = pool.map(concept => ({ concept, ticket: 0 }));
const ranked = await deterministicRank(
tickets,
`${scope}:${key}:challenger-${index}${salt}`,
entry => `${entry.concept.id}#${entry.ticket}`
);
const order = [];
const seen = new Set();
for (const entry of ranked) {
if (seen.has(entry.concept.id)) continue;
seen.add(entry.concept.id);
order.push(entry.concept);
}
const first = order[0];
const second = order.find(concept => concept.familyId !== first.familyId)
|| order.find(concept => concept.id !== first.id);
picks.push(...(second ? [first, second] : [first]));
}
return picks;
};
const excluded = new Set();
let picks = await pickRound(0, excluded);
for (let round = 1; round <= reroll; round += 1) {
for (const pick of picks) excluded.add(pick.id);
picks = await pickRound(round, excluded);
}
return { approved, picks };
}
export async function selectApprovedStaging({ scope, key, reroll = 0, mode = null, compositions }) {
let approved = compositions.filter(composition => composition.status === 'approved');
if (approved.length === 0) return null;
if (mode) {
const matching = approved.filter(composition => composition.surface === mode);
if (matching.length === 0) return null;
approved = matching;
}
const prior = new Set();
let pick = (await deterministicRank(approved, `${scope}:${key}:staging`))[0];
for (let round = 1; round <= reroll; round += 1) {
prior.add(pick.id);
const pool = approved.filter(composition => !prior.has(composition.id));
pick = (await deterministicRank(
pool.length > 0 ? pool : approved,
`${scope}:${key}:staging:reroll-${round}`
))[0];
}
return pick;
}
const publicConcept = concept => ({
id: concept.id,
form: concept.form,
spark: concept.spark,
system: concept.system,
webLeverage: concept.webLeverage,
wellTier: concept.wellTier,
});
const publicComposition = composition => ({
id: composition.id,
form: composition.form,
spark: composition.spark,
grammar: composition.grammar,
webLeverage: composition.webLeverage,
surface: composition.surface,
});
export async function rollSeed({ scope, key, mode, reroll }) {
const concepts = mergeConcepts();
const compositions = mergeCompositions();
const [poolRevision, { approved, picks }, staging] = await Promise.all([
approvedPoolRevision(concepts),
selectApprovedChallengers({ scope, key, reroll, concepts }),
selectApprovedStaging({ scope, key, reroll, mode, compositions }),
]);
return {
key,
scope,
mode: mode || null,
reroll,
poolRevision,
approvedCount: approved.length,
catalogCount: concepts.length,
challengers: picks.map(publicConcept),
staging: staging ? publicComposition(staging) : null,
};
}
// Impressions and choices land in Workers Analytics Engine when the binding
// exists; without it, logging is a silent no-op so the roll never fails.
export function logEvent(env, event, fields) {
try {
env.ROLL_ANALYTICS?.writeDataPoint({
blobs: [
event,
fields.scope || '',
fields.mode || '',
fields.poolRevision || '',
fields.chosenId || '',
...(fields.dealtIds || []),
],
doubles: [fields.reroll || 0],
indexes: [event],
});
} catch {
// Telemetry must never break a roll.
}
}
export const CORS_HEADERS = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
+30
View File
@@ -0,0 +1,30 @@
// POST /api/chosen { key, poolRevision, chosenId, scope?, mode? }
//
// Anonymous choice ping: records that a world dealt by /api/roll was selected
// as the direction. No project data, no user identity; senders honor
// DO_NOT_TRACK and IMPECCABLE_NO_TELEMETRY before calling. Always answers
// 204 so a failed record can never disturb a design flow.
import { logEvent, CORS_HEADERS } from './_worldroll.js';
export async function onRequestOptions() {
return new Response(null, { status: 204, headers: CORS_HEADERS });
}
export async function onRequestPost({ request, env }) {
try {
const body = await request.json();
const chosenId = typeof body.chosenId === 'string' ? body.chosenId.slice(0, 120) : '';
if (chosenId && /^[a-z0-9-]+$/.test(chosenId)) {
logEvent(env, 'chosen', {
scope: typeof body.scope === 'string' ? body.scope.slice(0, 16) : '',
mode: typeof body.mode === 'string' ? body.mode.slice(0, 16) : '',
poolRevision: typeof body.poolRevision === 'string' ? body.poolRevision.slice(0, 16) : '',
chosenId,
});
}
} catch {
// Malformed pings are dropped silently.
}
return new Response(null, { status: 204, headers: CORS_HEADERS });
}
+48
View File
@@ -0,0 +1,48 @@
// GET /api/roll?scope=direction|surface&mode=<persuade|operate|read|experience>&key=<key>&reroll=<n>
//
// Deals a deterministic concept roll: six challengers (two per translation
// tier, rating-weighted) plus one mode-matched staging. Same key + same pool
// revision reproduces the roll. The request itself is the impression record.
import { rollSeed, logEvent, SEED_MODES, CORS_HEADERS } from './_worldroll.js';
export async function onRequestOptions() {
return new Response(null, { status: 204, headers: CORS_HEADERS });
}
export async function onRequestGet({ request, env }) {
const url = new URL(request.url);
const scope = url.searchParams.get('scope') || 'surface';
const mode = url.searchParams.get('mode') || null;
const key = url.searchParams.get('key') || crypto.randomUUID().slice(0, 8);
const reroll = Number(url.searchParams.get('reroll') || 0);
if (scope !== 'direction' && scope !== 'surface') {
return Response.json({ error: 'scope must be direction or surface' }, { status: 400, headers: CORS_HEADERS });
}
if (mode !== null && !SEED_MODES.has(mode)) {
return Response.json({ error: 'mode must be persuade, operate, read, or experience' }, { status: 400, headers: CORS_HEADERS });
}
if (!Number.isInteger(reroll) || reroll < 0 || reroll > 8) {
return Response.json({ error: 'reroll must be an integer between 0 and 8' }, { status: 400, headers: CORS_HEADERS });
}
if (!/^[a-z0-9-]{1,64}$/i.test(key)) {
return Response.json({ error: 'key must be 1-64 alphanumeric characters' }, { status: 400, headers: CORS_HEADERS });
}
try {
const roll = await rollSeed({ scope, key, mode, reroll });
logEvent(env, 'roll', {
scope,
mode,
reroll,
poolRevision: roll.poolRevision,
dealtIds: [...roll.challengers.map(challenger => challenger.id), roll.staging?.id].filter(Boolean),
});
return Response.json(roll, {
headers: { ...CORS_HEADERS, 'Cache-Control': 'no-store' },
});
} catch (error) {
return Response.json({ error: error.message }, { status: 500, headers: CORS_HEADERS });
}
}
+1 -1
View File
@@ -52,7 +52,7 @@
"rebuild:release": "bun run clean && bun run build:release",
"dev": "bun run scripts/gen-dev-api.mjs && npx astro dev",
"preview": "bun run build && npx astro preview",
"deploy": "bun run build && wrangler pages deploy build/",
"deploy": "node scripts/sync-api-data.mjs && bun run build && wrangler pages deploy build/",
"test": "node scripts/run-tests.mjs default",
"test:core": "node scripts/run-tests.mjs core",
"test:detector": "node scripts/run-tests.mjs detector",
+1 -1
View File
@@ -646,7 +646,7 @@ function generateCFConfig(buildDir) {
// Without this, the SPA fallback serves index.html for function routes
const routes = {
version: 1,
include: ['/api/download/*', '/worlds/cards/*'],
include: ['/api/download/*', '/api/roll', '/api/chosen', '/worlds/cards/*'],
exclude: [],
};
fs.writeFileSync(path.join(buildDir, '_routes.json'), JSON.stringify(routes, null, 2));
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env node
// Copies the catalog JSON files into functions/api/_data/ so the roll API
// bundles the current revision at deploy. Run before `bun run deploy`
// whenever catalog content changed (the deploy script chains it).
import { copyFileSync, mkdirSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const SRC = join(ROOT, 'skill', 'scripts');
const DEST = join(ROOT, 'functions', 'api', '_data');
const FILES = [
'concept-ingredients.json',
'concept-reviews.json',
'composition-ingredients.json',
'composition-reviews.json',
];
mkdirSync(DEST, { recursive: true });
for (const file of FILES) {
copyFileSync(join(SRC, file), join(DEST, file));
}
process.stdout.write(`synced ${FILES.length} catalog files -> functions/api/_data\n`);
+4 -3
View File
@@ -1357,10 +1357,11 @@ button.lvg-dot {
.lvg-steer-dots {
display: inline-flex;
flex: 1;
padding: 0 12px 0 2px;
flex: 0 0 auto;
margin-left: auto;
padding: 0 12px 0 8px;
align-items: center;
justify-content: center;
justify-content: flex-end;
gap: 5px;
}
+6 -5
View File
@@ -9,7 +9,7 @@ Terms this file uses throughout, defined once:
- **World:** the durable visual identity: palette, materials, type voice, ornament logic, and component character that outlive any single surface.
- **Coupled pair:** one world joined to one concrete first-surface expression, selected together as a single decision, never as two tournaments.
- **Staging:** an identity-free structural idea for a surface (hierarchy, sequence, interaction). The seed may append one; it brings no palette, typeface, or material.
- **Candidate floor:** the four veto tests in section 4. A candidate passes all four or is discarded and replaced.
- **Candidate floor:** the five veto tests in section 4. A candidate passes all five or is discarded and replaced.
- **Direction contract:** six promise blocks written into the artifact's opening comment before code, audited against the render by the hooks.
- **Surface brief:** durable surface strategy persisted to `.impeccable/surfaces/` via `surface-brief.mjs`.
- **Attended run:** a user is present to answer questions. Unattended fallbacks apply only when no one can answer.
@@ -48,7 +48,8 @@ In an attended run, ask one round of at most three material questions without re
When generating choices, veto rather than rationalize. Before a candidate reaches the user, discard and replace it if any floor fails:
- **Truth:** every relationship it visualizes exists in product truth; resemblance is not evidence.
- **Consequence:** removing its bar-raiser materially weakens the surface's central argument or use. Otherwise it is ordinary craft.
- **Translation:** after removing source names, props, materials, and vocabulary, a product-native relationship, behavior, or proof remains. Otherwise it is costume, not a concept.
- **Consequence:** removing its bar-raiser materially weakens the surface's central argument or use; name what the visitor could no longer understand or do. Otherwise it is ordinary craft.
- **Survival:** its signature remains compelling on the primary device and within the real asset and tool budget.
- **Fit:** its risk is an honest tradeoff, not a probable violation of the brief or audience.
@@ -76,10 +77,10 @@ Unattended: use the promoted candidate when a roll ran, otherwise the strongest
### New or replacement world (A, D, or E): choose a coupled pair
1. **Ground.** Derive the product mechanism, user scene, audience's cultural home, and what this surface uniquely proves. Name the category default and its predictable contrarian response; neither may enter the shortlist unchanged.
2. **Derive pairs.** Generate five to seven grounded coupled pairs and order them by product fit. Each joins a durable system to a concrete first-surface structure, native behavior, non-routine bar-raiser, and implementation consequence. Different names or materials on the same experience are one candidate.
3. **Break the ranking rut once.** Run `node {{scripts_path}}/concept-seed.mjs --scope direction --mode <mode>`, where the mode is the first surface's: persuade, operate, read, or experience. The seed names a PROMOTED INDEX; elevate the pair at that position of your own ranked list into the serious shortlist and judge it as a peer of your top picks. Translate each challenger into a coherent system and task solution before comparing audience identification, product clarity, system leverage, and use of the medium. Keep the relationships, states, and affordances; discard the source carrier, materials, and vocabulary unless product evidence earns them. When the seed appends a FIRST-SURFACE STAGING, treat it as a candidate structure for the first surface: dress it in each shortlisted world before judging, and keep world and staging one coupled decision.
2. **Derive pairs.** Generate five to seven grounded coupled pairs and order them by product fit. Each joins a durable system to a concrete first-surface structure, native behavior, non-routine bar-raiser, and implementation consequence. State what becomes impossible without the bar-raiser. Different names or materials on the same experience are one candidate.
3. **Break the ranking rut once.** Run `node {{scripts_path}}/concept-seed.mjs --scope direction --mode <mode>`, where the mode is the first surface's: persuade, operate, read, or experience. The seed names a PROMOTED INDEX; elevate the pair at that position of your own ranked list into the serious shortlist and judge it as a peer of your top picks. For each challenger, first state the relationship, state change, or affordance it imports without naming the source; only then translate it into a coherent system and task solution. Keep that logic, but discard the source carrier, materials, and vocabulary unless product evidence earns them as functional parts of the product. A candidate still named or explained by the source object has not been translated. Compare every translated pair with the grounded list on audience identification, product clarity, system leverage, and use of the medium. When the seed appends a FIRST-SURFACE STAGING, treat it as a candidate structure for the first surface: dress it in each shortlisted world before judging, and keep world and staging one coupled decision.
4. **Test at full strength.** Apply the candidate floor. Strip names, styling, and source carrier; survivors must still differ in structure, sequence, or interaction. Their world must also govern the whole product: the navigation, a dense surface, and a quiet surface, with the last two dissimilar.
5. **Offer coupled choices.** Present two or three equally viable pairs without recommendation cues, following **Present, visualize, re-roll** below. For each, show the world rules, first-surface expression, bar-raiser, cross-surface consequence, and risk. Ask what is closest, should combine, or feels wrong; rejection is allowed.
5. **Offer coupled choices.** Present two or three equally viable pairs without recommendation cues, following **Present, visualize, re-roll** below. For each, show the world rules, first-surface expression, bar-raiser, cross-surface consequence, risk, and what fails without the bar-raiser. If fewer than two clear every veto, derive replacements rather than padding the choice. Ask what is closest, should combine, or feels wrong; rejection is allowed.
6. **Resolve once.** The user selects or revises the pair. Extract the durable rules into DESIGN.md and the task-specific strategy into the surface brief; do not reopen either half independently.
Unattended: use the assigned grounded pair only if it survives product fit, coupling, and breadth; mark assumptions. This is fallback, not user choice.
+180 -35
View File
@@ -35,13 +35,23 @@
* node scripts/concept-seed.mjs --scope direction --mode persuade
* node scripts/concept-seed.mjs --scope surface --mode operate --from <key>
* node scripts/concept-seed.mjs --scope direction --mode persuade --from <key> --reroll 1
* node scripts/concept-seed.mjs --chosen <challenger-id> --from <key> --scope direction
*
* --mode names the requested surface's mode (persuade, operate, read,
* experience) so the appended staging matches its register of work; omitted,
* the staging rolls from the full approved pool.
*
* Challenger data resolves in order: a local catalog directory (the private
* service repo, evals, and tests set IMPECCABLE_CATALOG_DIR), then the roll
* API at impeccable.style, then a degraded promotion-only seed when both are
* unavailable. --chosen sends the anonymous choice ping for API-dealt rolls;
* DO_NOT_TRACK or IMPECCABLE_NO_TELEMETRY disables it.
*
* Env vars:
* IMPECCABLE_CONCEPT_SEED — same as --from; for reproducible eval runs.
* IMPECCABLE_CATALOG_DIR — directory holding the four catalog JSON files.
* IMPECCABLE_API_URL — roll API base (default https://impeccable.style/api).
* IMPECCABLE_NO_TELEMETRY — disables the choice ping (DO_NOT_TRACK also honored).
*/
import crypto from 'node:crypto';
@@ -57,20 +67,90 @@ import {
import { readCompositionCatalog } from './lib/composition-catalog.mjs';
const here = dirname(fileURLToPath(import.meta.url));
const catalogState = readConceptCatalog(
join(here, 'concept-ingredients.json'),
join(here, 'concept-reviews.json')
);
const catalogValidation = validateConceptCatalog(catalogState.catalog, catalogState.reviewData);
if (catalogValidation.errors.length > 0) {
throw new Error(`concept-seed: invalid catalog: ${catalogValidation.errors.join('; ')}`);
// Data resolution order: a local catalog (the private service repo, evals, and
// tests point IMPECCABLE_CATALOG_DIR at one), then the roll API, then a
// degraded promotion-only seed. The full catalog does not ship with the skill.
const CATALOG_DIR = process.env.IMPECCABLE_CATALOG_DIR || here;
const API_BASE = (process.env.IMPECCABLE_API_URL || 'https://impeccable.style/api').replace(/\/$/, '');
const API_TIMEOUT_MS = Number(process.env.IMPECCABLE_API_TIMEOUT || 4000);
let localState; // undefined = untried, null = unavailable
function loadLocal() {
if (localState !== undefined) return localState;
try {
const catalogState = readConceptCatalog(
join(CATALOG_DIR, 'concept-ingredients.json'),
join(CATALOG_DIR, 'concept-reviews.json')
);
const validation = validateConceptCatalog(catalogState.catalog, catalogState.reviewData);
if (validation.errors.length > 0) {
throw new Error(`invalid catalog: ${validation.errors.join('; ')}`);
}
const compositionState = readCompositionCatalog(
join(CATALOG_DIR, 'composition-ingredients.json'),
join(CATALOG_DIR, 'composition-reviews.json')
);
localState = {
concepts: catalogState.concepts,
compositions: compositionState.compositions,
};
} catch {
localState = null;
}
return localState;
}
function requireLocalConcepts() {
const local = loadLocal();
if (!local) {
throw new Error('concept-seed: no local catalog (set IMPECCABLE_CATALOG_DIR or pass sourceConcepts)');
}
return local;
}
async function fetchRoll({ scope, key, mode, reroll }) {
const params = new URLSearchParams({ scope, key, reroll: String(reroll) });
if (mode) params.set('mode', mode);
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS);
try {
const response = await fetch(`${API_BASE}/roll?${params}`, { signal: controller.signal });
if (!response.ok) return null;
const roll = await response.json();
if (!Array.isArray(roll.challengers) || roll.challengers.length === 0) return null;
return roll;
} catch {
return null;
} finally {
clearTimeout(timer);
}
}
function telemetryDisabled() {
return Boolean(process.env.IMPECCABLE_NO_TELEMETRY || process.env.DO_NOT_TRACK);
}
// Anonymous choice ping: records only that a dealt world was selected.
// Fire-and-forget; never fails the caller.
export async function pingChosen({ chosenId, key, scope, mode }) {
if (telemetryDisabled() || !chosenId) return false;
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS);
try {
await fetch(`${API_BASE}/chosen`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chosenId, key, scope, mode }),
signal: controller.signal,
});
return true;
} catch {
return false;
} finally {
clearTimeout(timer);
}
}
const { concepts } = catalogState;
const compositionState = readCompositionCatalog(
join(here, 'composition-ingredients.json'),
join(here, 'composition-reviews.json')
);
const compositions = compositionState.compositions;
export function renderChallenger(concept, index) {
const system = concept.system.map(rule => ` - ${rule}`).join('\n');
@@ -94,8 +174,9 @@ ${grammar}
// Returns null while the composition pool has no approved entry for the
// requested mode. Cross-mode fallback would turn an absent staging into a
// misleading one. A re-roll excludes earlier stagings until the pool runs out.
export function selectApprovedStaging({ scope, key, reroll = 0, mode = null, sourceCompositions = compositions }) {
let approved = sourceCompositions.filter(composition => composition.status === 'approved');
export function selectApprovedStaging({ scope, key, reroll = 0, mode = null, sourceCompositions = null }) {
const pool = sourceCompositions ?? requireLocalConcepts().compositions;
let approved = pool.filter(composition => composition.status === 'approved');
if (approved.length === 0) return null;
if (mode) {
const matching = approved.filter(composition => composition.surface === mode);
@@ -115,8 +196,9 @@ export function selectApprovedStaging({ scope, key, reroll = 0, mode = null, sou
return pick;
}
export function selectApprovedChallengers({ scope, key, reroll = 0, sourceConcepts = concepts }) {
const approved = sourceConcepts.filter(concept => concept.status === 'approved');
export function selectApprovedChallengers({ scope, key, reroll = 0, sourceConcepts = null }) {
const source = sourceConcepts ?? requireLocalConcepts().concepts;
const approved = source.filter(concept => concept.status === 'approved');
// Direction chooses a durable identity, so it draws worlds; surface designs
// one page inside a committed identity, so it draws stagings. Duals serve
// both. A tier with no matching-strength approvals falls back to its full
@@ -192,13 +274,14 @@ export function selectApprovedChallengers({ scope, key, reroll = 0, sourceConcep
return {
approved,
picks,
poolRevision: approvedPoolRevision(sourceConcepts),
poolRevision: approvedPoolRevision(source),
catalogCount: source.length,
};
}
const SEED_MODES = new Set(['persuade', 'operate', 'read', 'experience']);
export function renderConceptSeed({
export async function renderConceptSeed({
scope = 'surface',
key = process.env.IMPECCABLE_CONCEPT_SEED || crypto.randomBytes(4).toString('hex'),
reroll = 0,
@@ -219,7 +302,34 @@ export function renderConceptSeed({
};
const indexSalt = reroll === 0 ? 'index' : `index:reroll-${reroll}`;
const buildIndex = 3 + Math.floor(unit(indexSalt) * 5); // 3..7
const { approved, picks, poolRevision } = selectApprovedChallengers({ scope, key, reroll });
// Local catalog first (private repo, evals, tests), then the roll API,
// then a degraded promotion-only seed. The promoted index is pure local
// math, so even a fully offline run keeps the anti-argmax mechanism.
let data = null;
if (loadLocal()) {
const { approved, picks, poolRevision, catalogCount } = selectApprovedChallengers({ scope, key, reroll });
data = {
source: 'local',
poolRevision,
approvedCount: approved.length,
catalogCount,
challengers: picks,
staging: selectApprovedStaging({ scope, key, reroll, mode }),
};
} else {
const roll = await fetchRoll({ scope, key, mode, reroll });
if (roll) {
data = {
source: 'api',
poolRevision: roll.poolRevision,
approvedCount: roll.approvedCount,
catalogCount: roll.catalogCount,
challengers: roll.challengers,
staging: roll.staging,
};
}
}
const promotedInstruction = scope === 'direction'
? `After ordering the grounded coupled directions by product fit, promote
@@ -268,14 +378,31 @@ artifact's rules, never just its name: grid, geometry, ornament logic,
material behavior, and information structure become the interface's. Preserve
the spark's imaginative distance: do not collapse a galaxy into a mission
dashboard, a forest into a taxonomy app, or a performance into a control
console. Use Three.js, generative motion, film language, typography, craft,
console. Translation is complete only when the source name and physical prop
can disappear while a product-native relationship, state change, or proof
remains. A carrier survives only when product evidence makes it functional;
never name a candidate after the prompt merely to preserve the spark. Use
Three.js, generative motion, film language, typography, craft,
or another ambitious medium when it materially strengthens the task; keep
semantic structure and graceful fallbacks fully capable.`;
const staging = selectApprovedStaging({ scope, key, reroll, mode });
const stagingBlock = staging
if (!data) {
return `${scope.toUpperCase()} CONCEPT SEED (key: ${key}; mode: ${mode ?? 'unscoped'}; source: degraded; rerun with --scope ${scope}${mode ? ` --mode ${mode}` : ''} --from ${key}${reroll > 0 ? ` --reroll ${reroll}` : ''})
PROMOTED INDEX: ${buildIndex}
${promotedInstruction}
The promotion exists to refuse the model's ranking rut, not to outrank the
user or the brief. Never expose promotion metadata in choice labels or order.
No challengers this run: the roll service was unreachable and no local
catalog exists. Proceed with the grounded candidates alone; the promotion
above still applies at full strength.
${authorityInstruction}
A user- or brief-pinned decision beats the roll, always.
`;
}
const stagingBlock = data.staging
? `\n${scope === 'direction' ? 'FIRST-SURFACE STAGING (identity-free; pair it with the chosen world and judge the pair as one decision):' : 'STAGING CHALLENGER (identity-free; dress it in the committed visual identity before judging):'}
${renderStaging(staging)}
${renderStaging(data.staging)}
A staging organizes attention, sequence, and manipulation; it never brings a
palette, typeface, or material. It competes on structure alone and loses to a
grounded structure that fits the product better.\n`
@@ -286,17 +413,23 @@ grounded structure that fits the product better.\n`
genuinely new grounded candidates from unexplored angles before judging
these fresh challengers.\n`
: '';
return `${scope.toUpperCase()} CONCEPT SEED (key: ${key}; mode: ${mode ?? 'unscoped'}; approved pool: ${poolRevision}; ${approved.length}/${concepts.length} human-approved; rerun with --scope ${scope}${mode ? ` --mode ${mode}` : ''} --from ${key}${reroll > 0 ? ` --reroll ${reroll}` : ''} to reproduce this roll against this catalog revision)
const telemetryBlock = data.source === 'api'
? `TELEMETRY: if the resolved direction uses one of these challengers, rerun
this script once with --chosen <challenger-id> --from ${key} --scope ${scope}${mode ? ` --mode ${mode}` : ''}
after resolution. The ping is anonymous (chosen id only) and is skipped
automatically when DO_NOT_TRACK or IMPECCABLE_NO_TELEMETRY is set.\n`
: '';
return `${scope.toUpperCase()} CONCEPT SEED (key: ${key}; mode: ${mode ?? 'unscoped'}; source: ${data.source}; approved pool: ${data.poolRevision}; ${data.approvedCount}/${data.catalogCount} human-approved; rerun with --scope ${scope}${mode ? ` --mode ${mode}` : ''} --from ${key}${reroll > 0 ? ` --reroll ${reroll}` : ''} to reproduce this roll against this catalog revision)
${rerollBlock}PROMOTED INDEX: ${buildIndex}
${promotedInstruction}
The promotion exists to refuse the model's ranking rut, not to outrank the
user or the brief. Never expose promotion metadata in choice labels or order.
CHALLENGERS:
${picks.map(renderChallenger).join('\n')}
${data.challengers.map(renderChallenger).join('\n')}
${stagingBlock}${challengerInstruction}
${authorityInstruction}
${richnessInstruction}
A user- or brief-pinned decision beats the roll, always.
${telemetryBlock}A user- or brief-pinned decision beats the roll, always.
`;
}
@@ -306,15 +439,27 @@ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.ur
const scopeIdx = args.indexOf('--scope');
const rerollIdx = args.indexOf('--reroll');
const modeIdx = args.indexOf('--mode');
const chosenIdx = args.indexOf('--chosen');
try {
process.stdout.write(renderConceptSeed({
scope: scopeIdx !== -1 ? args[scopeIdx + 1] : 'surface',
key: fromIdx !== -1
? args[fromIdx + 1]
: (process.env.IMPECCABLE_CONCEPT_SEED || crypto.randomBytes(4).toString('hex')),
reroll: rerollIdx !== -1 ? Number(args[rerollIdx + 1]) : 0,
mode: modeIdx !== -1 ? args[modeIdx + 1] : null,
}));
if (chosenIdx !== -1) {
// Choice ping: always exits 0, telemetry must never fail a design flow.
const sent = await pingChosen({
chosenId: args[chosenIdx + 1],
key: fromIdx !== -1 ? args[fromIdx + 1] : undefined,
scope: scopeIdx !== -1 ? args[scopeIdx + 1] : undefined,
mode: modeIdx !== -1 ? args[modeIdx + 1] : undefined,
});
process.stdout.write(sent ? 'choice recorded\n' : 'choice ping skipped\n');
} else {
process.stdout.write(await renderConceptSeed({
scope: scopeIdx !== -1 ? args[scopeIdx + 1] : 'surface',
key: fromIdx !== -1
? args[fromIdx + 1]
: (process.env.IMPECCABLE_CONCEPT_SEED || crypto.randomBytes(4).toString('hex')),
reroll: rerollIdx !== -1 ? Number(args[rerollIdx + 1]) : 0,
mode: modeIdx !== -1 ? args[modeIdx + 1] : null,
}));
}
} catch (error) {
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
process.exitCode = 1;
+3 -3
View File
@@ -8678,9 +8678,9 @@ void main() {
function buildSteerProcessingDots() {
const P = pageChatPalette();
const wrap = el('span', {
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
gap: '5px', flex: '1', minWidth: '0',
padding: '0 12px 0 2px',
display: 'inline-flex', alignItems: 'center', justifyContent: 'flex-end',
gap: '5px', flex: '0 0 auto', minWidth: '0', marginLeft: 'auto',
padding: '0 12px 0 8px',
pointerEvents: 'none',
});
wrap.setAttribute('aria-hidden', 'true');
+5
View File
@@ -438,6 +438,11 @@ describe('live-browser.js regression guards', () => {
/Handing off|pageChatHint\.textContent = 'Working'/,
'steer processing state should use dots-only animation, not truncated text',
);
assert.match(
SOURCE,
/function buildSteerProcessingDots\(\)[\s\S]{0,500}?justifyContent: 'flex-end'[\s\S]{0,220}?marginLeft: 'auto'/,
'steer processing dots should stay aligned to the input trailing edge',
);
assert.match(
SOURCE,
/function syncAgentPollingUi\(/,
+1
View File
@@ -53,6 +53,7 @@ test('Live UI gallery organizes states into browsable workflow clusters', () =>
assert.match(styles, /\.live-ui-gallery :where\(button, input, select\)/);
assert.match(styles, /\.lvg-configure-modifier:not\(\.is-count\) > span/);
assert.match(styles, /\.lvg-pending-pill > span:not\(\.lvg-pending-count\)/);
assert.match(styles, /\.lvg-steer-dots\s*\{[^}]*margin-left:\s*auto;[^}]*justify-content:\s*flex-end;/s);
});
test('legacy Live Lab URL redirects to the labs namespace', () => {
+6
View File
@@ -8,3 +8,9 @@ pages_build_output_dir = "./build"
[[r2_buckets]]
binding = "WORLD_CARDS"
bucket_name = "impeccable-world-cards"
# Roll/choice telemetry lands in Workers Analytics Engine. Create the dataset
# implicitly on first deploy; queries via the CF GraphQL/SQL API.
[[analytics_engine_datasets]]
binding = "ROLL_ANALYTICS"
dataset = "impeccable_world_rolls"