AI Content Creator pipeline implementation record
Status: Implemented on 2026-08-15. Source, focused fixtures, typecheck, lint, diff hygiene, documentation, old-pipeline removal audits, and an authenticated Prompt Lab smoke run through filename-pattern inference are complete. Full end-to-end processing of the live 50-state run and the full Meteor CI suite remain outside the verified boundary described below.
Purpose: Maintain one shared AI Content pipeline with an explicit early branch between bounded text-table creation and authoritative Wikipedia retrieval. Wikimedia filenames are either retrieved directly or predicted by one exact two-seed rule and accepted only after canonical Wikimedia resolution.
This plan supersedes the pipeline assumptions in ai-content-creator-cleanup-plan.md, ai-content-image-procurement-plan.md, and the current ai-content-creator-audit.md. Those documents must be removed or rewritten during implementation so that the repository has one current architectural account.
Status: Internal implementation record. This preserves design decisions and implementation history; current authoring instructions are maintained in Quick Start: Content Creation, and current behavior is defined by source. Later changes include generated/provided table strategies. Do not treat a future-tense requirement here as proof of a deployed capability.
Implementation outcome
- The Creator and Prompt Lab call the same
runAiContentPipelineorchestrator. The proven Prompt Lab retains its Admin Tests capability method and explicit stage caller unchanged; the Creator reaches the same request builder and server executor through a scoped adapter. The Creator retains only its distinct author-input, browser persistence, editable review/localization, and save responsibilities. - The interpretation stage selects one terminal route. Generated and author-supplied text tables make one bounded strict-schema call and never query Wikipedia. Explicit sources, canonical external coverage, source-based definitions, and images use the Wikipedia path.
- Wikipedia search results, one selected page containing the requested list, one selected structural region, and its extracted entries define the retrieved item set. The page title does not need to begin with
List of; page and region evaluators must choose one application-supplied opaque ID. - Text runs use generated-table, provided-table, per-source definition, or deterministic source-field mapping. Image runs expose and trace the direct-list-image and linked-detail-page branches.
- Image runs resolve files individually and test each new successful canonical filename against earlier successes until one pair establishes an exact rule. They then batch-resolve later predicted
File:titles canonically and individually retry only queued exceptions after the deterministic pass. - The Prompt Lab exposes editable author notes plus all nine live stage prompts, including table generation/formatting, per-stage reasoning, visible-output budgets, strict schemas, exact call traces, recorded-stage retry, local named checkpoints, expandable checkpoint snapshots, and the configured Admin model as read-only. A reset control checkpoints the current draft and restores every stage from the Creator's code defaults without changing author notes or saved checkpoints. Existing browser checkpoints acquire missing stages without discarding their saved edits.
- The Creator's green running-status region reports the current shared pipeline stage and item so a long list run remains observable outside the Lab.
- The Creator derives its concise review/save title deterministically from the interpretation stage's structured subject, the actual retrieved or generated item count, and the selected session mode. The lesson name retains spaces; package filenames are sanitized independently so punctuation cannot produce a traversal-like filename.
- Creator and Lab render the same shared pair-review template. Creator rows remain editable and support review-time image replacement; Lab rows are read-only previews of the same structure.
- The v5 working record retains source provenance and explicit unresolved items. Older working-record versions are rejected rather than migrated.
- The former generated-pair, topic-planning, broad traversal, dual-owner, initial-upload-generation, and separate Discovery Lab paths were removed rather than wrapped or archived.
- Focused pure fixtures cover bounded generated tables, supplied-table provenance and checkpoint migration, direct table images, linked detail-page images, mixed direct/detail routing, repeated seed-pair inference after a mismatch, normalized and redirected canonical file resolution, post-pass retry of a seed-collection failure, post-pass pattern exceptions, per-item definitions, source-field mappings, answer-leakage rejection, retry, source extraction, license/attribution rejection, obsolete-record rejection, and supplied-ID validation.
npm.cmd run typecheck,npm.cmd run lint, andgit diff --checkpassed. Focusedknipinspection reports no unused AI Content exports or exported types; the repository-wide command still reports unrelated existing findings.- The supported local hotfix server reported healthy watcher, HMR, bundle, and application readiness at
http://localhost:3200. Authenticated Prompt Lab runs verified the model/reasoning display, editable author notes, trace descriptions, real list selection, image acquisition, and filename-pattern inference. A run in which Alabama and Alaska both succeeded exposed that a one-shot inference gate disabled the fast path when those two filenames disagreed; the gate was replaced with repeated deterministic inference after each new successful image. A bounded follow-up run verified an unresolved Alabama/Alaska inference, a successful Alabama/Arizona inference, canonical batch resolution, and subsequent pattern-resolved states without per-item AI evaluation. Full 50-item completion after that correction has not yet been browser-verified. - A later run showed that inference was still gated by the next item's successful semantic evaluation: Arizona's canonical filenames were already hydrated, but a failed
evaluate-detail-imagesresponse prevented another inference attempt. Pattern discovery now compares those canonical response-bearing filenames with earlier validated images immediately after hydration and before the later semantic call. The Prompt Lab also omits raw page HTML from trace records, lazily renders individual trace JSON, and renders the complete run object only as an explicit snapshot. Typecheck, lint, diff hygiene, and hotfix readiness passed for this follow-up; the authenticated Lab itself was not re-run because the available browser session stopped at sign-in. - A later v4-compatible amendment added generated-table and provided-table strategies before Wikipedia routing. Both use one bounded strict call, trace-backed provenance, whole-result validation, and the shared Creator/Lab review. Existing Lab drafts acquire the ninth stage from code defaults. Per explicit instruction, this amendment received source and diff inspection only; automated checks and browser workflows were not run.
- A v5 amendment removes
listSearchQueryfrom the AI-owned intent and deterministically constructslist <subject>at the application-owned Wikipedia boundary. This invalidates stale v4 Creator and Prompt Lab browser state rather than preserving the contradictory prompt/schema contract. Typecheck, lint, focused fixture inspection, diff hygiene, and the explicitly authorizedCI=1 npm.cmd run test:cisuite passed with 913 passing and 7 pending tests. Live browser generation was not run.
Governing repository rules
Implementation must follow the root AGENTS.md, especially these consequences:
- Work in
mofacts/for application behavior. - Do not preserve the old pipeline through compatibility paths, alternate routes, or hidden fallbacks.
- Reuse existing helpers only after verifying that their contracts fit the new flow; do not keep an old owning module merely to reuse a few functions.
- Do not create parallel names or representations for the same list entry, response, candidate, or selected file.
- Keep OpenRouter credentials and provider calls on the server; keep safe parsing, selection orchestration, Wikipedia requests, conversion, and review state on the client where practical.
- Preserve unrelated working-tree changes.
- Run full typecheck and lint for TypeScript-bearing application changes. Any
npm run test:ciinvocation requires fresh, explicit user authorization. - Update public authoring documentation and the wiki because this rebuild changes user-visible behavior and the administrator workflow.
Approved product decisions
- A generation run has one universal prompt type:
textorimage. Mixed prompt types are not supported. - The response type is always text.
- The first pipeline stage chooses one content strategy before any Wikipedia request.
- Generated and provided tables contain at most 250 text-to-text rows, use one strict AI call, and never switch to Wikipedia after failure.
- The Wikipedia route selects one pre-existing page containing the requested list. That page defines the externally grounded item set and its title need not begin with
List of. - A Wikipedia text run either generates one succinct answer-hiding definition per extracted response or selects existing prompt and response fields once and maps their exact row values deterministically.
- Image prompts use one shared, succinct image requirement derived from the author request.
- Each list entry is inspected for a structurally associated thumbnail or Wikimedia file link.
- A list-page thumbnail is accepted only when its filename, caption, alt text, surrounding entry text, metadata, and structural role support the requested image role.
- If an entry has no appropriate direct image, the pipeline follows that entry's canonical Wikipedia detail-page link and inspects that page's image links.
- Image evaluation is textual and structural. The model does not inspect image pixels.
- The pipeline does not evaluate visual coherence across the completed set. Coherence is assumed from using one authoritative list as the source of all entries.
- Items without a usable text prompt or image remain visible and unresolved for user review and manual completion.
- The production workflow and the AI Content Prompt Lab use the same orchestrator, contracts, schemas, and stage implementations. A Lab draft may intentionally override editable prompt settings for simulation; an unedited Lab draft uses the runtime defaults.
Non-negotiable invariants
Strategy ownership and grounded selection
AI may generate a bounded text table only after interpretation selects generated-table, or reformat author-supplied rows after selecting provided-table. Those rows carry trace-backed table provenance and a visible nonblocking review notice; they never receive fabricated Wikipedia provenance.
On the Wikipedia route, AI may interpret the author request, construct search intent, rank candidates, and select candidate IDs supplied by the application. AI may not originate an item, Wikipedia page, link, Wikimedia filename, URL, license, or attribution record. The application may predict a Wikimedia File: title only under the deterministic two-seed amendment below; the Wikimedia API remains authoritative for the canonical file record and rendition URL.
Every AI selection response must reference an opaque candidate ID from the request. The application copies the associated title, label, URL, filename, and metadata from its retrieved candidate object. A model-returned title or URL is never accepted as authority.
Complete review
The final review is built from every item extracted from the selected list, not from the subset for which generation succeeded. Every item must be either resolved or explicitly unresolved.
Provenance
Every item retains this source chain:
author request
-> real Wikipedia search result
-> selected list page
-> structural list entry
-> response text
-> text definition
OR
-> selected source prompt field + selected source response field
-> deterministic row mapping
OR
-> direct Wikimedia file
OR
-> canonical detail-page link
-> detail-page Wikimedia file
-> selected and validated asset
No silent substitution
- No composite list.
- No invented missing member.
- No general-web source.
- No provider fallback.
- No invisible query-strategy retry.
- No automatic conversion of an unresolved image item into a text item.
- No reuse of downstream results after an upstream input or prompt changes.
Current implementation findings
The current source does not implement the approved model and must not be treated as a coherent base architecture:
aiContentPrompts.tsasks AI to generate the complete item set and every pair, contrary to list-page authority.aiContentOpenRouterClient.tsowns pair-generation and repair calls around that generated-set contract.aiContentContract.tsv3 makes generated{ kind, stimulus, response, imageDescription }pairs the provider contract rather than grounding items in list entries.aiContentCreationFlow.tsuses author-note regular expressions to choose between generated-pair and Wikipedia-authoritative ownership.aiContentCreator.tscontains two competing creation paths: generated pairs followed by image discovery, and separate authoritative Wikipedia enumeration.aiContentWikimediaTopics.tsturns notes or descriptions into broad collection topics rather than selecting one retrieved list page.aiContentImageSets.tscombines multiple responsibilities: Wikipedia search, collection traversal, member inference, link scoring, candidate scoring, family selection, acquisition, conversion checks, diagnostics, and two different public discovery entry points.- Current link and label-risk scoring contains domain-specific anatomy terms inside an ostensibly general resolver.
- The Prompt Lab simulates one pair-generation request and then invokes the old image-discovery path.
- A separate Wikimedia Discovery Lab exercises a different entry point, so neither lab exposes one faithful end-to-end production flow.
The rebuild must replace these owners rather than layer the new list-source model on top of them.
Target data model
The exact names may be refined during implementation, but there must be one representation for each concept and explicit validators at every persisted or provider boundary.
Run input and intent
type AiContentPromptType = 'text' | 'image';
type AiContentAuthorRequest = {
runId: string;
revision: number;
notes: string;
mode: 'learning' | 'test';
};
type AiContentIntent = {
promptType: AiContentPromptType;
responseType: 'text';
textPairingStrategy: 'definition' | 'source-field-mapping' | 'generated-table' | 'provided-table' | 'not-applicable';
subject: string;
imageRequirement: string; // empty for text runs
tableInstructions?: string;
tableScopeSummary?: string;
expectedItemCount?: number | null;
tableIssue?: string;
};
The model does not own a Wikipedia query. When interpretation selects a Wikipedia route, the application deterministically constructs the concise query list <subject> from the validated core subject. Image-role wording remains solely in imageRequirement.
Search candidates and source decision
type WikipediaListCandidate = {
candidateId: string;
rank: number;
pageId: number;
title: string;
canonicalUrl: string;
snippet: string;
leadExcerpt: string;
};
type WikipediaListDecision = {
selectedCandidateId: string | null;
rationale: string;
};
The shared decision shape permits null for selectors that may legitimately decline a candidate. The authoritative list-page stage considers at most the first three real search results and requires one supplied candidateId, normally favoring rank 1.
Structural list entries
type WikipediaListRegionCandidate = {
regionId: string;
kind: 'table' | 'list' | 'gallery';
heading: string;
entryCount: number;
sampleEntries: string[];
fields?: Array<{
fieldId: string;
label: string;
sampleValues: string[];
}>;
};
type WikipediaListEntry = {
itemId: string;
sourcePageId: number;
sourcePageTitle: string;
regionId: string;
sourceLocator: string;
displayedResponse: string;
normalizedResponseKey: string;
directImageCandidateIds: string[];
detailLinkCandidateIds: string[];
sourceFields?: Array<{
fieldId: string;
label: string;
value: string;
}>;
};
The application creates displayedResponse only from text present in the selected structural entry or its canonical linked article title. AI may select a region or entry candidate, but it may not supply response text.
Link and image candidates
type WikipediaDetailLinkCandidate = {
candidateId: string;
itemId: string;
anchorText: string;
pageId: number;
title: string;
canonicalUrl: string;
structuralRole: string;
};
type WikimediaImageCandidate = {
candidateId: string;
itemId: string;
sourcePath: 'list-page' | 'detail-page' | 'filename-pattern';
parentListPageId: number;
detailPageId?: number;
filePageId: number;
fileTitle: string;
commonsUrl: string;
renditionUrl: string;
caption: string;
altText: string;
surroundingText: string;
structuralRole: string;
mimeType: string;
width: number;
height: number;
attribution: AiPromptAttribution;
};
type ImageCandidateDecision = {
rankedCandidateIds: string[];
selectedCandidateId: string | null;
rationale: string;
};
type AiContentImageFilenamePattern = {
patternId: string;
prefix: string;
suffix: string;
extension: string;
seedSourcePath: 'list-page' | 'detail-page';
seedItemIds: [string, string];
seedResponses: [string, string];
seedFileTitles: [string, string];
};
The application rejects returned IDs that were not supplied, duplicate rankings, extra fields, or a selected ID inconsistent with the ranking.
Per-item resolution and final pair
type AiContentItemResolution = {
itemId: string;
response: string;
promptType: AiContentPromptType;
sourcePath: 'text-definition' | 'source-field-mapping' | 'list-page' | 'detail-page' | 'filename-pattern' | 'unresolved';
prompt?: string;
detailPageCandidateId?: string;
selectedImageCandidateId?: string;
filenamePatternId?: string;
unresolvedReason?: string;
};
The save/package pair shape remains small, while the browser-local working record retains the stage objects and provenance needed for review and diagnosis. These source-field additions remain optional in v4 persisted records, so the contract stays at version 4. Old v3 browser records are rejected explicitly rather than reinterpreted through compatibility logic.
End-to-end pipeline
Stage 1: interpret the author request and choose a content strategy
Run one strict AI request using the author notes. It returns only:
- universal
promptType; - constant
responseType: "text"; - succinct subject;
- one text strategy: generated table, provided table, source definition, or source-field mapping;
- one shared image requirement for image runs;
- table instructions, scope summary, exact or nullable expected count, and an explicit table issue field.
This request does not return items, page titles, links, filenames, pairs, definitions, or images.
Validate that:
promptTypeis exactlytextorimage;responseTypeis exactlytext;- a table strategy has no image requirement and contains no more than 250 expected rows;
- a provided table has an exact row count and unambiguous column direction;
- image runs have a nonblank image requirement;
- text runs have no image requirement.
Stage 2A: generate or format one text table
For generated-table or provided-table, make one strict AI request and return immediately to review. The response contains a scope summary and an ordered array of prompt-response rows. Exact-count scopes constrain the schema to that count; open scopes accept 1–250 rows. The client rejects blank fields, duplicate normalized prompts, unsupported fields, count mismatches, and oversized tables as one terminal failure. It does not repair, retain a partial result, or search Wikipedia.
Provided tables may be Markdown, CSV, TSV, or aligned text. Explicit instructions or unambiguous headers determine direction. Light spelling, capitalization, punctuation, and ordering cleanup is allowed, but adding, omitting, or semantically changing rows is prohibited.
Stage 2B: search Wikipedia
The application constructs list <subject> from the validated core subject, submits that query to the English Wikipedia search API, and builds at most three WikipediaListCandidate objects from returned pages. Page IDs, titles, URLs, snippets, and lead excerpts come from Wikipedia.
No AI-generated URL or page title is accepted. A failed API request is an explicit failed stage; it does not switch providers or sources.
Stage 3: select and retrieve one list page
Run a strict AI evaluator over the real search candidates. It receives the author request, universal prompt type, requested subject or image role, and candidate objects. When candidates exist, it must return exactly one supplied selectedCandidateId.
Selection policy:
- Prefer the earliest search result.
- Depart from that order only when supplied title, snippet, or lead evidence shows a later result is a materially better list page.
- Never select a page outside the supplied candidates.
- An article containing the authoritative list remains eligible even when the article title does not begin with
List ofor the lead does not summarize its embedded table.
The application then retrieves the selected page by page ID.
Stage 4: identify the authoritative list region and extract entries
The application parses the selected page into bounded structural candidates: tables, semantic lists, and galleries. It excludes navigation boxes, references, unrelated sidebars, and page chrome before AI evaluation.
For a source-field-mapping run, the application removes regions that do not expose at least two table fields before selection. If no compatible region remains, the run stops at this boundary. For other runs, every usable structural region remains eligible. If more than one eligible list region exists, a strict evaluator must select exactly one supplied regionId. The application then materializes the entries from that region. AI does not write or normalize the member names.
Each entry records:
- exact displayed response;
- normalized matching key kept separately from display text;
- page, region, and source locator;
- structurally contained thumbnails and file links;
- structurally contained article links.
Extraction must handle table headers, row and column spans, section-grouped lists, galleries, footnote markers, and repeated navigation links without crossing entry boundaries.
If the application cannot establish at least one source-anchored entry, the run stops. It does not ask AI to create missing items.
Stage 5: fork once on the universal prompt type
interpreted request
-> generated-table or provided-table
-> one bounded strict table call -> review
-> Wikipedia route
-> authoritative WikipediaListEntry[]
-> definition strategy: one definition request per entry
OR
-> source-field strategy: select two real fields once, then map rows deterministically
OR
-> image-source resolution per entry
The fork applies to the entire run. Per-item direct/detail image routing is not mixed prompt modality.
Text branch
The interpretation stage first chooses one text strategy for the whole run.
For the definition strategy, run one strict AI definition request for every authoritative list entry containing:
- the exact response term;
- the author request;
- the shared definition instructions;
- the source-list subject for context.
The application supplies the response. The model returns only a candidate learner-visible definition prompt and may not rename the response.
Acceptance rules:
- succinct but complete identification definition;
- does not contain the response term under case-insensitive normalized comparison;
- does not contain an alias or abbreviation explicitly supplied by the same source entry when that alias would reveal the answer;
- not empty, circular, or merely a generic category description;
- one result maps to exactly one
itemId.
A failed or rejected definition leaves that item unresolved and editable in review. Other items remain available.
For the source-field strategy, table extraction preserves stable field IDs, exact header labels, sample values, and exact values for every row. One strict AI request selects a distinct prompt field ID and response field ID from those supplied fields. MoFaCTS then constructs every pair in authoritative row order without further AI calls. Empty selected values and duplicate prompt values remain explicitly unresolved; the model may not invent a value or transformation.
Image branch
Stage 6A: collect direct list-entry image candidates
For each entry, resolve only thumbnails and Wikimedia file links structurally contained in that entry. Hydrate each file through Wikipedia or Commons APIs to obtain canonical file title, canonical file page, rendition URL, dimensions, MIME type, caption/alt text when available, and machine-readable attribution.
Do not use page-global images merely because they appear near the list. Outside the adopted filename-pattern path, do not infer a filename from the response.
Stage 6B: evaluate direct candidates
Run a strict text-only evaluator for the entry's direct candidates. It receives the exact response, shared image requirement, and candidate evidence. It returns a ranking over supplied candidate IDs and either selects the highest acceptable candidate or selects none.
An image is not acceptable merely because a thumbnail exists. Filename, caption, alt text, surrounding entry text, metadata, and structural role must support the requested image role. For example, a state flag does not satisfy an outline-map request.
If a direct candidate is selected, proceed to technical validation and acquisition. If no direct candidate is semantically acceptable, continue to the detail-page branch.
Stage 6C: select the canonical detail-page link
Collect article links structurally associated with the entry. Prefer a unique canonical entity link whose anchor or resolved title identifies the response. If several links remain plausible, run a strict evaluator that may select only a supplied detail-link candidate ID.
If no unambiguous detail link exists, mark the item unresolved. Do not search the web for another item page.
Stage 6D: inspect and evaluate detail-page images
Retrieve the selected detail page by page ID and enumerate its embedded or explicitly linked Wikimedia files. Build the same WikimediaImageCandidate objects, preserving the parent list entry and detail-page provenance.
Run the text-only image evaluator over those supplied candidates. It considers filenames, captions, alt text, section or infobox role, surrounding text, metadata, and the shared image requirement. It may return a ranked list and selected candidate ID or no selection.
No pixel data is supplied to the model. Ambiguous evidence produces an unresolved item rather than a guess.
Stage 6E: validate, acquire, and convert
For each ranked semantic candidate, in recorded order:
- verify the candidate still maps to the retrieved canonical file object;
- verify allowed machine-readable license and complete attribution;
- verify supported image MIME type, nonzero dimensions, and source-size bounds;
- download the recorded rendition;
- verify that the response is an image and nonempty;
- convert through the existing browser image preparation component to WebP at the existing size and quality contract;
- attach the prepared asset and provenance to the item.
If a candidate fails, record the rejection and continue the explicit ranked evaluation. This is not an invisible fallback: the ordered candidates, rejection, and next decision are part of the run record and Lab trace.
If no ranked candidate passes, leave the item unresolved.
Stage 6F: deterministic filename-pattern pass
Process source entries in list order through the ordinary direct/detail resolver until one image has passed semantic evaluation, canonical metadata validation, acquisition, and WebP conversion. As each later item's canonical file candidates are hydrated, compare its response-bearing filenames with every earlier individually validated image before invoking semantic image evaluation for that later item. Infer one filename rule only when the agreeing filenames come from the same source branch, each canonical basename contains its displayed response exactly once, and their normalized prefix, suffix, and extension agree.
When a rule is adopted, predict a File: title for every remaining unprocessed entry by placing its unmodified displayed response between the observed prefix and suffix. Resolve the predictions through Wikimedia in batches of at most 50 titles with title normalization and redirects enabled. A prediction succeeds only when the API returns a real canonical file-page ID and imageinfo; HTTP success is not evidence by itself.
Canonical resolution replaces per-item semantic AI evaluation for a pattern match, but it does not replace license, attribution, MIME, dimensions, source-size, download, or conversion checks. Record every pattern-inference attempt, each predicted title and canonical match, and each queued exception in the run trace. After the complete deterministic pass, send missing or technically invalid pattern matches and any entry left unresolved during seed collection through the ordinary individual resolver once. If one item's observed filenames disagree with the validated images, continue in list order and try inference again immediately after the next item's canonical filenames are hydrated. At most one pattern is adopted per run; if no observed filename ever agrees, the whole run remains individually resolved.
Review and save
The existing Creator review interaction remains the product destination:
- one row for every authoritative list entry;
- editable title;
- editable text definition for text runs;
- image preview or unresolved image slot for image runs;
- editable textual response;
- Wikimedia source and attribution when resolved;
- manual image replacement for unresolved or unsuitable image items;
- explicit per-item failure reason;
- Save blocked until required prompts and images are complete.
The initial upload-to-pair-generation route conflicts with list authority and must be removed. Retain image upload, drag/drop, validation, WebP conversion, and package naming only as review-time replacement components with that explicit owner.
The final save contract remains intentionally smaller than the working record. Search traces, model outputs, and diagnostics are not saved into learner content.
Full AI Content Prompt Lab rebuild
The Prompt Lab must become an exact, inspectable simulation of the complete production pipeline. The existing single pair-generation simulation and separate Wikimedia Discovery Lab must be removed.
Lab configuration
The Lab exposes:
- editable author notes;
- read-only model selected by the Admin Control Panel;
- the Admin Control Panel's baseline reasoning level;
- an explicit configurable reasoning level for every AI stage, with the effective value shown on every executed call;
- editable visible-output token budget per prompt stage;
- editable system and user-instruction templates for:
- request interpretation and list-search intent;
- generated or author-supplied table formatting;
- Wikipedia list-page candidate selection;
- list-region selection when needed;
- prompt and response source-field selection;
- per-item text definition;
- direct image-candidate evaluation;
- ambiguous detail-link evaluation;
- detail-page image-candidate evaluation;
- strict schema preview for each AI stage;
- the exact non-secret effective request for every execution.
The model is never selectable in the Lab. All Lab AI calls use the configured Admin model. Provider routing must not silently replace it. Reasoning must never be implicit in the result display.
Lab execution controls
The Lab supports:
- run the complete pipeline;
- run or retry one eligible stage from its recorded input;
- invalidate every dependent downstream object when a stage input, prompt, reasoning value, or output budget changes;
- resume from a valid upstream stage without reusing stale downstream values;
- cancel or supersede an in-flight run without letting late results overwrite the current revision.
Lab object and call trace
The Lab renders, by stage:
- input object;
- effective prompt and schema;
- configured model and effective reasoning;
- provider response, parsed JSON, validation, token usage, and cost when supplied;
- Wikipedia or Commons request URL with sensitive data excluded;
- retrieved candidate objects and their opaque IDs;
- selected and rejected IDs with rationales;
- list-region and per-entry provenance;
- direct-versus-detail route for every item;
- canonical file metadata, acquisition, license, and conversion decisions;
- explicit unresolved reasons;
- final Creator-style review with images, learner prompts, responses, and Wikimedia source links.
The direct/detail structure must be visible as a real branch:
list entry
-> acceptable direct image -> acquire
-> no acceptable direct image
-> select detail link
-> inspect detail page
-> evaluate its images
-> acquire or unresolved
Prompt iteration history
Keep browser-local working state and named checkpoints. Each checkpoint contains:
- author notes;
- every stage prompt template;
- every stage reasoning value;
- every stage token budget;
- contract version;
- timestamp and user label.
Running the pipeline creates a checkpoint automatically. Administrators can load and compare checkpoints without changing the configured model. Provider calls and results remain nonpersistent on the server. Secrets are never placed in browser-local history or displayed.
Lab consolidation
Delete the separate Wikimedia Discovery Lab UI, helpers, state, and event handlers. Its useful diagnostics move into the stage trace of the rebuilt Prompt Lab. There must be one Lab and one production orchestrator, not two diagnostic implementations.
Code ownership after the rebuild
Use the narrowest coherent module split and finalize names only after checking all adjacent concepts.
| Owner | Responsibility |
|---|---|
common/aiContentContract.ts |
One versioned working/save contract, authoritative pair/item types, and strict validators. |
| Prompt-stage module | All stage prompt constants, builders, strict schemas, and response validators. No Wikipedia fetching. |
| Wikipedia source-list module | Search API, page retrieval, structural region/entry extraction, canonical links, and source locators. No AI calls. |
| Wikimedia file module | Canonical file hydration, metadata, licenses, attribution, and rendition retrieval. No semantic item invention. |
| AI stage client | Authenticated OpenRouter stage requests through the existing server transport, with explicit operation/model/reasoning telemetry. |
| Pipeline orchestrator | Revisioned stage transitions, direct/detail branching, failure state, provenance, and final pair assembly. |
| Image asset component | Existing input validation, download preparation, WebP conversion, package filenames, and preview URLs. |
| Working store | Browser-local current run and asset bytes, updated for the new contract version. |
| Creator view | Author request, progress, review editing/replacement, and save. No search/scoring algorithms. |
| Prompt Lab view/state | Editable stage settings, checkpoint history, execution controls, trace rendering, and shared final review. No duplicate pipeline. |
Do not place the new pipeline back into one replacement megafile. Low-level Wikipedia and Wikimedia operations may be extracted from current code only after their behavior is independently verified and domain-specific scoring is removed.
Reuse, rewrite, and deletion inventory
Retain and adapt
aiContentImageAssets.tsand its tests: supported-file validation, source bounds, browser WebP conversion, unique package naming, and preview preparation.aiContentWorkingStore.ts: browser-local persistence and serialized writes, after updating the working contract and rejecting old versions explicitly.aiContentDraftBuilder.tsandaiContentPackageSave.ts: deterministic lesson/package construction and save, after verifying the new pair contract.- Creator review editing, unresolved slots, manual replacement, attribution display, and save blocking.
- Generic OpenRouter server transport, capability/catalog lookup, authentication, telemetry, and Admin authorization.
- Existing Wikimedia license and canonical-file parsing logic only as reviewed low-level helpers moved into the new file owner.
Rewrite completely
common/aiContentContract.tsand tests: replace generated-pair v3 provider ownership with the new list-source working contract and bump the version.aiContentPrompts.tsand tests: replace pair enumeration, modality regexes, shared generatedimageDescription, and pair repair with bounded stage prompts.aiContentOpenRouterClient.tsand tests: replace pair-specific calls with strict stage calls that always record effective model and reasoning.aiContentPromptLabState.tsand tests: replace one-request drafts with versioned multi-stage settings and dependency-aware checkpoints.aiContentCreator.ts: replace dual ownership and discovery paths with one orchestrator call.testRunner.tsandtestRunner.html: replace the current Prompt Lab and remove the separate Discovery Lab.aiContentCreator.cssonly as needed for shared review and stage-trace accessibility.- Current AI Content documentation and wiki descriptions.
Delete; do not archive or preserve behind wrappers
aiContentWikimediaTopics.tsand its tests.- The current
aiContentImageSets.tsowning implementation and tests after equivalent new source-list/file behavior is covered in focused modules. aiContentCreationFlow.tsand its tests, including generated-pairs versus Wikipedia-authoritative ownership heuristics.discoverWikimediaImages,discoverAuthoritativeWikimediaPairs,planWikimediaTopics,selectAiContentPairOwnership, and their associated result/diagnostic contracts.- Broad topic frontiers, collection-branch inference, response-title traversal scoring, coherent-family selection, anatomy-specific bonuses and label patterns, singleton or family recovery behavior, and generated-pair-to-discovery matching.
- The old pair-generation and pair-repair prompts and schemas.
- The current Prompt-Lab-to-old-discovery handoff.
- The separate Wikimedia Discovery Lab UI and state.
- Superseded AI Content plan/audit prose that describes generated member enumeration, collection traversal, or the two-lab architecture.
If a current helper is still useful, move its verified implementation into its new owner and update all callers before deleting the old module. Do not leave a forwarding wrapper, deprecated alias, unused export, commented copy, or compatibility branch.
Implementation sequence
Phase 0: baseline and dependency inventory
- Record current branch, status, upstream, and focused diffs.
- Separate unrelated working-tree changes from AI Content files.
- Enumerate all imports, tests, UI selectors, server methods, documentation, and persisted keys tied to the old pipeline.
- Verify the current config and wiki repository paths required by
AGENTS.md. - Identify any current creator upload behavior that reaches pair generation; plan its removal while preserving review-time replacement.
Gate: every old owning symbol has a known replacement or deletion disposition.
Phase 1: contracts and stage prompts
- Define the new versioned run, intent, candidate, list-entry, resolution, and save contracts.
- Add strict validators that reject extra fields and unknown candidate IDs.
- Define each bounded AI prompt and schema.
- Make model and reasoning explicit in every request and telemetry record.
- Add unit tests for all valid and invalid boundaries.
Gate: no prompt can return an authoritative item, URL, page title, or filename outside supplied data.
Phase 2: Wikipedia source-list discovery
- Implement request interpretation and one list-search query.
- Implement deterministic Wikipedia search and candidate construction.
- Implement strict selection among the first one to three candidates.
- Fetch the selected page by page ID.
- Parse structural list regions and extract source-anchored entries.
- Cover table, list, gallery, row-span, section, and navigation-exclusion fixtures.
Gate: every item can be traced to a source locator on the one selected page.
Phase 3: text branch
- Implement one definition call per entry for definition runs.
- Preserve table header identities and exact row values for source-field runs.
- Select the source prompt and response fields once from supplied field IDs, then construct all row pairs deterministically.
- Assign responses from source entries, never from model-generated values.
- Validate answer leakage for definitions and empty or duplicate mapped fields.
- Preserve per-item failures as unresolved review rows.
Gate: a model cannot add, remove, reorder, or rename list items.
Phase 4: image direct/detail branches
- Enumerate direct image and detail-link candidates per entry.
- Hydrate real Wikimedia file metadata.
- Evaluate direct image candidate IDs.
- Follow a canonical detail link only when no direct candidate is acceptable.
- Enumerate and evaluate detail-page image candidate IDs.
- Validate licenses and technical properties, acquire, convert, and attach assets.
- Preserve unresolved items and complete provenance.
Gate: cat-breed-style table thumbnails and U.S.-state-style detail-page maps both succeed through their intended branches, while a state flag does not terminate an outline-map search.
Phase 5: production Creator cutover
- Connect the Creator to the single orchestrator.
- Remove pair-ownership inference and both old execution paths.
- Retain review editing, image replacement, browser-local working state, and deterministic save/package construction.
- Reject old working-record versions explicitly.
- Verify stale asynchronous operations cannot overwrite a newer run revision.
Gate: production has exactly one creation entry point and no reachable old pipeline.
Phase 6: Prompt Lab replacement
- Implement the multi-stage draft and checkpoint contract.
- Add editors for every live stage prompt, reasoning value, and token budget.
- Add complete-run and stage-retry controls with downstream invalidation.
- Render every AI call, API result, data object, decision, and branch.
- Reuse the production orchestrator and final review component.
- Remove the separate Wikimedia Discovery Lab.
Gate: a Lab run and production run with the same author request and effective settings traverse the same code and produce the same stage contracts.
Phase 7: delete the old pipeline
- Delete the old modules, tests, exports, UI, selectors, events, prompts, schemas, and documentation named above.
- Remove old imports and branches from Creator, Admin Tests, and server method tests.
- Remove old persistence fields that are no longer in the new contract; do not retain compatibility readers.
- Remove old diagnostic terms and telemetry operations that imply pair generation, broad topic traversal, family selection, or separate Discovery Lab ownership.
- Run dead-code and reference searches before proceeding.
Gate: searches for every retired symbol and identifying prompt phrase return no active source or documentation references.
Phase 8: verification, documentation, and final audit
- Run focused contract, prompt, Wikipedia parsing, Wikimedia resolution, orchestrator, working-store, Creator, Prompt Lab, save, and server authorization tests.
- Run
npm.cmd run typecheckfrommofacts/. - Run
npm.cmd run lintfrommofacts/. - Run
git diff --check. - Run dead-file/export analysis appropriate to the repository, including focused
knipchecks if the full command is too noisy to attribute safely. - Perform an authenticated browser smoke test through the supported local hotfix workflow when available.
- Do not run
npm run test:ciwithout fresh explicit authorization. - Update
docs/authoring.md, the canonical developer audit, andC:\dev\MoFaCTS.wiki\Quick-Start-Content-Creation.md. - Remove or rewrite superseded plan documents so they cannot be mistaken for current behavior.
- Inspect the final focused diff and working tree, preserving all unrelated changes.
Gate: code, tests, Prompt Lab, Creator behavior, and documentation describe one pipeline and one set of contracts.
Required fixture scenarios
Source grounding
- Search returns three real pages; evaluator selects only one supplied candidate ID.
- Evaluator returns an invented ID, title, or URL; validation rejects it.
- The highest-ranked subject article contains the authoritative list but is not titled
List of ...; it remains selectable. - A page contains content tables plus navigation tables; only the selected content region supplies items.
- Entry labels with footnotes, abbreviations, and redirects preserve display text and separate normalized keys.
Text branch
- Division facts through products of 81 select
generated-table, require exactly 81 rows, and make no Wikipedia request. - A complete two-column author table selects
provided-table, preserves its row count and meanings, and carries no fabricated Wikipedia fields. - Ambiguous direction, unexplained extra columns, blank fields, duplicate normalized prompts, an incorrect exact count, or more than 250 rows rejects the complete table without repair or route switching.
- An open-ended generated table accepts one through 250 valid rows and records the actual count.
- A definition run gives every extracted item exactly one definition request.
- A source-field run makes one field-selection request and no per-item definition requests.
- English Delphic-maxim text maps deterministically to the exact Stobaeus
No.value for all 147 rows. - Definitions cannot add, remove, rename, or reorder responses.
- A definition containing the response term is rejected and left reviewable.
- One failed definition does not erase successful items.
Image branch
- Cat breeds: the selected list table contains appropriately associated thumbnails and uses the direct branch.
- U.S. states: the selected list contains state links; each detail page supplies map candidates and uses the detail branch.
- A list row contains a flag but the request requires a map; direct evaluation selects none and continues to the state page.
- A page contains images outside an item's row; they are not assigned to that item.
- A detail page contains flag, seal, locator map, and photographs; selection is constrained to supplied IDs and textual/structural evidence.
- A candidate lacks allowed license or complete attribution; it cannot resolve the item.
- A ranked candidate fails download or conversion; the recorded ranking proceeds to the next candidate.
- Direct and detail routes coexist in one image run without changing the universal image prompt type.
- No valid candidate leaves a visible unresolved item.
State and Lab
- Changing any upstream prompt or reasoning value invalidates dependent results.
- A late response from a superseded revision cannot overwrite current state.
- Every Lab call displays configured model, effective reasoning, token budget, schema, and result.
- Loading a checkpoint restores all prompt-stage settings but never overrides the configured Admin model.
- The Lab's final review matches the production review contract.
- No separate Discovery Lab remains.
Final old-pipeline removal audit
The implementation is not complete until a deliberate removal audit has been performed after all functional verification.
Required source searches
Search the application, tests, docs, config repository, and wiki for:
discoverWikimediaImagesdiscoverAuthoritativeWikimediaPairsplanWikimediaTopicsWIKIMEDIA_TOPIC_SYSTEM_PROMPTselectAiContentPairOwnershipgenerated-pairswikipedia-authoritativeAI_CONTENT_PAIR_GENERATION_INSTRUCTIONSAI_GENERATED_PAIR_RESPONSE_SCHEMA- old
imageDescriptionpair-generation ownership Wikimedia Discovery Lab- old traversal, family-selection, and anatomy-special-case diagnostic phrases
- affected-surface uses of provider fallbacks
Expected result: no active code or current documentation depends on the retired pipeline. Any intentional remaining phrase must be reviewed individually and documented in the handoff; there is no blanket exception for tests, comments, or plans.
Required structural inspection
- Verify that Creator and Prompt Lab import the same orchestrator.
- Verify that no second list-discovery or image-selection implementation exists.
- Verify that every model-selected value is an application-supplied candidate ID.
- Verify that every final pair originates from either a retrieved list entry or one complete validated table-generation trace.
- Verify that every resolved Wikimedia image has a complete provenance chain.
- Verify that review preserves the complete authoritative Wikipedia item list or the complete validated table, rather than retaining only individually successful rows.
- Verify that old working records are rejected rather than migrated through compatibility code.
- Verify that deleted modules have no forwarding wrappers, deprecated exports, copied implementations, emitted JavaScript twins, or commented archival blocks.
- Verify that old documentation is removed or rewritten.
Maintainability sign-off
The final handoff must name:
- deleted files and retired symbols;
- reused components and their new owners;
- results of old-symbol and dead-code searches;
- focused tests and full typecheck/lint outcomes;
- browser verification performed or not performed;
- documentation and wiki updates;
- unrelated working-tree changes preserved;
- any remaining ambiguity that could still allow two representations or two execution paths.
Completion criteria
The rebuild is complete only when all of the following are true:
- Interpretation selects exactly one terminal table or Wikipedia strategy before content retrieval or generation.
- A table strategy uses one bounded strict call, validates the whole result, and never switches to Wikipedia after failure.
- On the Wikipedia route, the application deterministically constructs the list search from the AI-interpreted core subject, and one real Wikipedia list page defines the complete item set. AI never originates a search query, item, page, link, URL, or Wikimedia filename; the application may predict one exact title only after one validated image agrees with a response-bearing canonical filename observed on another authoritative item page, and Wikimedia canonical resolution is authoritative.
- Prompt type is universal and response type is text.
- Text runs generate or format one bounded table, generate individual answer-hiding definitions, or map two selected source fields deterministically.
- Image items first follow the explicit direct-list-image or linked-detail-page branch; after one validated image agrees with a response-bearing canonical filename observed for another item, the current and remaining items may use the recorded deterministic filename-pattern path, with queued exceptions returning to individual resolution after the batch.
- Image candidate decisions use only supplied IDs and textual/structural evidence.
- Missing outputs remain visible for manual completion.
- Creator and Prompt Lab execute the same pipeline.
- The Prompt Lab exposes and versions every prompt, model/reasoning setting, stage object, branch, and final review result.
- The separate Discovery Lab and every old pipeline owner are gone.
- No compatibility path, provider fallback, obsolete prompt, stale schema, or contradictory documentation preserves the retired behavior.
- Required automated checks pass, and the final cleanup audit finds no confusing old implementation left behind.