Components Cache History and Model Baselines
This document defines an implementation approach to run a full low-cost gemini-2.5-flash pass across all patterns without losing existing higher-quality gemini-2.5-pro artifacts.
Objective
Preserve current canonical components while enabling:
- cheap baseline generation runs,
- full traceability per run/model,
- controlled promotion of selected outputs into canonical files.
Key Decision
Use immutable run snapshots plus explicit promotion.
Do not use rolling .bak files as the primary strategy.
Why:
.bakstores only one previous state and is easily overwritten.- Immutable snapshots preserve complete lineage by run and model.
- Promotion keeps runtime output stable and intentional.
Storage Layout
Keep canonical output unchanged:
public/components/code/{normalizedId}.tsx
Add run generated artifacts (one per successful pattern):
public/components/history/{runId}/{normalizedId}.generated.tsx
Add run backups (previous canonical before overwrite when promoted):
public/components/history/{runId}/{normalizedId}.tsx
Add run metadata:
public/components/history/{runId}/manifest.json
Add global history index:
public/components/history/runs.json
Run Identity
Introduce run id format:
{YYYYMMDDTHHmmssZ}
Examples:
20260528T120405Z20260528T121110Z
Implementation Status
Implemented now in scripts/build-components-cache.mjs:
- history snapshots are enabled by default on non-dry runs,
- generated candidate artifacts are written for each successful pattern,
- backup snapshots are written only on overwrite,
- per-run manifest is written,
- global runs index is written,
- promotion mode is configurable.
Script Changes
Target file:
scripts/build-components-cache.mjs
1) New CLI Flags
--run-id=<id>: optional explicit run id.--no-history: opt out of history writes.--promote=<mode>:none | all | changed.--baseline=<name>: mark run class, e.g.flash-full.
Current defaults:
- history on by default for non-dry runs,
- promotion default
all(preserves current canonical-overwrite behavior).
2) Content Hashing
For each generated TSX:
- compute
sha256of normalized content, - store hash in per-run
manifest.json, - compare hash with canonical file hash.
Promotion rules:
none: never touch canonical file,all: always overwrite canonical,changed: overwrite only if hash differs.
3) Write Order
For each pattern:
- Generate code.
- Validate TSX syntax (existing behavior).
- Write generated candidate artifact into run history.
- If canonical will be overwritten, snapshot previous canonical into run history.
- Optionally promote generated output to canonical path per
--promote. - Record per-pattern status + hashes in run manifest.
This keeps all generated outputs traceable by run while preserving promotion as an explicit canonical publish step.
4) Status/Report Compatibility
Keep existing files to avoid breaking consumers:
public/components/components-status.jsonpublic/components/_components-report.json
Extend status payload with optional fields:
lastRunIdlastModellastHashpromoted(boolean)
5) Notion Sync Safety
When --promote=none:
- do not set Notion
Code StatustoGeneratedfor canonical state, - optionally set a separate property (future) like
Code Baseline Flash.
If no separate property exists, keep current Notion behavior unchanged for now and log that run was history-only.
New Utility Scripts (Optional but Recommended)
scripts/promote-components-run.mjs
Purpose:
- promote selected artifacts from history run into canonical output.
Flags:
--run-id=<id>--ids=<id1,id2,...>optional--limit=<n>optional--dry-run
scripts/diff-components-runs.mjs
Purpose:
- compare two runs (or run vs canonical) and produce summary.
Output:
- changed ids,
- identical count,
- missing count.
Commands for Your Primary Goal
1) Full cheap baseline (keep current pro canonical intact)
PATTERN_COMPONENTS_CACHE_MODEL=gemini-2.5-flash npm run build:components -- --force --promote=none --baseline=flash-full
Result:
- full flash run saved under history,
- current canonical pro artifacts remain untouched.
2) Evaluate differences
Use diff script (once added) to find candidates for promotion.
3) Promote selected outputs
node scripts/promote-components-run.mjs --run-id=<flash-run-id> --ids=<comma-separated-ids>
4) Regenerate selected with pro and promote changed
PATTERN_COMPONENTS_CACHE_MODEL=gemini-2.5-pro npm run build:components -- --ids=<comma-separated-ids> --force --promote=changed --baseline=pro-refine
Manifest Shape (Draft)
public/components/history/{runId}/manifest.json:
{
"runId": "20260528T120405Z-flash-components-cache-p2-react-code-only-v6",
"model": "gemini-2.5-flash",
"baseline": "flash-full",
"generatorVersion": "components-cache-p2-react-code-only-v6",
"generatedAt": "2026-05-28T12:04:05.000Z",
"counts": {
"total": 1200,
"generated": 1160,
"failed": 40,
"promoted": 0
},
"items": [
{
"id": "abc123",
"generatedFile": "public/components/history/<runId>/abc123.generated.tsx",
"backupFile": "public/components/history/<runId>/abc123.tsx",
"canonicalFile": "public/components/code/abc123.tsx",
"contentHash": "sha256:...",
"canonicalHashBefore": "sha256:...",
"canonicalHashAfter": "sha256:...",
"promoted": false,
"status": "generated"
}
]
}
Retention Policy
Recommended initial policy:
- keep last 5 flash runs,
- keep last 10 pro runs,
- never auto-delete canonical files,
- prune old history runs only after manifest/index update succeeds.
Remaining Plan
- Add promotion utility script.
- Add run diff utility script.
- Add optional retention pruning by policy.
- Extend
/debug/componentsselector to include history runs.
Risks and Mitigations
- Disk growth from snapshots:
- Mitigation: retention + optional gzip archive for old runs.
- Confusion between baseline and canonical state:
- Mitigation: explicit
--promoteflag and manifest fields.
- Mitigation: explicit
- Downstream tooling expecting only canonical directory:
- Mitigation: keep canonical location and schema unchanged.
Success Criteria
- A full flash run can complete with
--promote=noneand zero canonical overwrites. - Existing pro artifacts in
public/components/coderemain unchanged. - Every generated artifact is traceable to
runId, model, and hash. - Promotion from history to canonical can be done deterministically per id.