mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-21 10:36:27 +03:00
Add concept world catalog and review workflow
AI-assisted: prepared by Codex at Paul's request.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* External concept seed: the dice half of new-work's world and surface
|
||||
* selection procedures.
|
||||
* External concept seed: the dice half of new-work's coupled-direction and
|
||||
* established-world surface procedures.
|
||||
*
|
||||
* The model derives a grounded shortlist of candidate FORMS from the
|
||||
* audience's world and the subject's cultural home (see
|
||||
@@ -23,94 +23,128 @@
|
||||
* material and win over thin categories, which is the intended shape.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/concept-seed.mjs --scope surface
|
||||
* node scripts/concept-seed.mjs --scope world --from <key>
|
||||
* node scripts/concept-seed.mjs --scope direction
|
||||
* node scripts/concept-seed.mjs --scope surface --from <key>
|
||||
*
|
||||
* Env vars:
|
||||
* IMPECCABLE_CONCEPT_SEED — same as --from; for reproducible eval runs.
|
||||
*/
|
||||
|
||||
import crypto from 'node:crypto';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import {
|
||||
approvedPoolRevision,
|
||||
deterministicRank,
|
||||
readConceptCatalog,
|
||||
} from './lib/concept-catalog.mjs';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const pool = JSON.parse(readFileSync(join(here, 'concept-ingredients.json'), 'utf8'));
|
||||
const { concepts } = readConceptCatalog(
|
||||
join(here, 'concept-ingredients.json'),
|
||||
join(here, 'concept-reviews.json')
|
||||
);
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const fromIdx = args.indexOf('--from');
|
||||
const scopeIdx = args.indexOf('--scope');
|
||||
const scope = scopeIdx !== -1 ? args[scopeIdx + 1] : 'surface';
|
||||
if (scope !== 'surface' && scope !== 'world') {
|
||||
process.stderr.write('concept-seed: --scope must be world or surface\n');
|
||||
process.exit(1);
|
||||
}
|
||||
// When no key is supplied, generate one and print it: a user reporting a
|
||||
// bad outcome can hand us the key and we replay the exact roll.
|
||||
const key = fromIdx !== -1
|
||||
? args[fromIdx + 1]
|
||||
: (process.env.IMPECCABLE_CONCEPT_SEED || crypto.randomBytes(4).toString('hex'));
|
||||
|
||||
function hashUnit(k, salt) {
|
||||
const h = crypto.createHash('sha256').update(`${scope}:${salt}:${k}`).digest();
|
||||
return h.readUInt32BE(0) / 0xffffffff;
|
||||
}
|
||||
const unit = (salt) => hashUnit(key, salt);
|
||||
|
||||
const buildIndex = 3 + Math.floor(unit('index') * 5); // 3..7
|
||||
|
||||
const entries = Object.entries(pool)
|
||||
.filter(([k]) => !k.startsWith('_'))
|
||||
.flatMap(([, list]) => list);
|
||||
const picks = [];
|
||||
const taken = new Set();
|
||||
for (let i = 0; picks.length < 3 && i < 60; i++) {
|
||||
const idx = Math.floor(unit(`challenger-${i}`) * entries.length) % entries.length;
|
||||
if (!taken.has(idx)) {
|
||||
taken.add(idx);
|
||||
picks.push(entries[idx]);
|
||||
export function selectApprovedChallengers({ scope, key, sourceConcepts = concepts }) {
|
||||
const approved = sourceConcepts.filter(concept => concept.status === 'approved');
|
||||
const approvedByFamily = new Map();
|
||||
for (const concept of approved) {
|
||||
const family = approvedByFamily.get(concept.familyId) || [];
|
||||
family.push(concept);
|
||||
approvedByFamily.set(concept.familyId, family);
|
||||
}
|
||||
if (approvedByFamily.size < 3) {
|
||||
throw new Error('concept-seed: at least three families need approved concepts');
|
||||
}
|
||||
const familyIds = deterministicRank(
|
||||
[...approvedByFamily.keys()].map(id => ({ id })),
|
||||
`${scope}:${key}:families`
|
||||
).slice(0, 3).map(item => item.id);
|
||||
const picks = familyIds.map((familyId, index) => deterministicRank(
|
||||
approvedByFamily.get(familyId),
|
||||
`${scope}:${key}:challenger-${index}`
|
||||
)[0]);
|
||||
return {
|
||||
approved,
|
||||
picks,
|
||||
poolRevision: approvedPoolRevision(sourceConcepts),
|
||||
};
|
||||
}
|
||||
|
||||
const promotedInstruction = scope === 'world'
|
||||
? `After ordering the grounded visual-world candidates by product fit, promote
|
||||
candidate ${buildIndex} into the serious shortlist. Present it beside the
|
||||
strongest materially different candidates and let the user select or revise
|
||||
the durable world. It must survive navigation, quiet and dense content,
|
||||
interaction and state, and a surface unlike the current request.`
|
||||
export function renderConceptSeed({
|
||||
scope = 'surface',
|
||||
key = process.env.IMPECCABLE_CONCEPT_SEED || crypto.randomBytes(4).toString('hex'),
|
||||
} = {}) {
|
||||
if (scope !== 'surface' && scope !== 'direction') {
|
||||
throw new Error('concept-seed: --scope must be direction or surface');
|
||||
}
|
||||
const unit = (salt) => {
|
||||
const h = crypto.createHash('sha256').update(`${scope}:${salt}:${key}`).digest();
|
||||
return h.readUInt32BE(0) / 0xffffffff;
|
||||
};
|
||||
const buildIndex = 3 + Math.floor(unit('index') * 5); // 3..7
|
||||
const { approved, picks, poolRevision } = selectApprovedChallengers({ scope, key });
|
||||
|
||||
const promotedInstruction = scope === 'direction'
|
||||
? `After ordering the grounded coupled directions by product fit, promote
|
||||
candidate ${buildIndex} into the serious shortlist. Each candidate must join
|
||||
a durable visual system to a concrete expression for the requested first
|
||||
surface; select or revise that pair as one decision. It must survive the
|
||||
current task plus navigation, quiet and dense content, interaction and state,
|
||||
and a substantially different future surface.`
|
||||
: `After ordering the task's grounded structural candidates by resonance,
|
||||
promote candidate ${buildIndex} into the serious shortlist. In an attended
|
||||
run, present it beside the strongest materially different candidates and
|
||||
let the user select or revise the surface concept. In a truly unattended
|
||||
run, use it when it survives audience identification and product clarity.`;
|
||||
|
||||
const challengerInstruction = scope === 'world'
|
||||
? `A challenger enters the world shortlist only when its structure can become
|
||||
reusable identity grammar across the product, not a one-page costume. Weigh
|
||||
product identification, product clarity, and cross-surface system breadth.`
|
||||
const challengerInstruction = scope === 'direction'
|
||||
? `Translate each challenger's organizing logic into reusable identity grammar
|
||||
and a strong first-surface structure before judging it. Noticeable form is
|
||||
allowed when the product stays clear. Compare only audience identification
|
||||
and product clarity.`
|
||||
: `A challenger wins only when it beats the grounded list on both audience
|
||||
identification and product clarity. It may change task topology or
|
||||
interaction, but never the committed visual identity.`;
|
||||
|
||||
const authorityInstruction = scope === 'world'
|
||||
? `PRODUCT.md and explicit incumbent brand commitments constrain every world.
|
||||
The seed never chooses exact colors, fonts, tokens, or a user preference.`
|
||||
const authorityInstruction = scope === 'direction'
|
||||
? `PRODUCT.md and explicit incumbent brand commitments constrain every coupled
|
||||
direction. The seed never chooses exact colors, fonts, tokens, or a user
|
||||
preference, and it never permits the world and first surface to be selected
|
||||
independently.`
|
||||
: `PRODUCT.md and DESIGN.md constrain every surface candidate's identity
|
||||
vocabulary; they do not cancel task-level composition. The seed never
|
||||
authorizes a new palette, type system, material world, or unfamiliar control
|
||||
behavior.`;
|
||||
|
||||
process.stdout.write(`${scope.toUpperCase()} CONCEPT SEED (key: ${key}; rerun with --scope ${scope} --from ${key} to reproduce this roll)
|
||||
return `${scope.toUpperCase()} CONCEPT SEED (key: ${key}; approved pool: ${poolRevision}; ${approved.length}/${concepts.length} human-approved; rerun with --scope ${scope} --from ${key} to reproduce this roll against this catalog revision)
|
||||
PROMOTED INDEX: ${buildIndex}
|
||||
${promotedInstruction}
|
||||
The promotion exists to refuse the model's ranking rut, not to outrank the
|
||||
user or the brief.
|
||||
user or the brief. Never expose promotion metadata in choice labels or order.
|
||||
CHALLENGERS:
|
||||
1. ${picks[0]}
|
||||
2. ${picks[1]}
|
||||
3. ${picks[2]}
|
||||
1. ${picks[0].form}
|
||||
2. ${picks[1].form}
|
||||
3. ${picks[2].form}
|
||||
${challengerInstruction}
|
||||
${authorityInstruction}
|
||||
A user- or brief-pinned decision beats the roll, always.
|
||||
`);
|
||||
`;
|
||||
}
|
||||
|
||||
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
const args = process.argv.slice(2);
|
||||
const fromIdx = args.indexOf('--from');
|
||||
const scopeIdx = args.indexOf('--scope');
|
||||
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')),
|
||||
}));
|
||||
} catch (error) {
|
||||
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user