The generator could already serve a second group set -- series.json's country series proves it -- but only one wired into series.json, reading upg100's bucketed clusters, upg100's legend tree for enumeration, and the shared records cache. A fork had no way in. The contract is now one folder. DATA_DIR points at it; clusters.json with a flat lists[] is the group set; records.json in the same folder means no API and no cache; selector-evaluator.js resolves from there, as it always did. normalize.js and legend-tree.js become optional -- absent, records are used as-is and the flat file IS the enumeration -- and the absence is logged rather than silent, because a silent fallback would let a typo'd normalize.js skip normalization on the real series. PACKET_OUT keeps a fork's output away from the real artifact directory, where toy packets would be counted as coverage. unlisted: true carries upg100's reachability idea across as data: the list is defined and selectable with ONLY=, and not generated by default. The bucketed shape keeps its legend-tree enumeration untouched, so the deaf collapse and the 28-zone arithmetic are byte-for-byte unchanged. The smoke test was written first and failed first, on all four counts. Its fixture is synthetic -- every slug and number invented -- and it asserts the unlisted list does NOT generate, which is as load-bearing as the two that do: an unlisted entry that generates anyway is the reachability bug inverted. One bug found in my own work while proving it: allZones became async, and the funnel's listCount read it from inside a try/catch that returns null on error -- so a use-before-init did not crash, it silently deleted the triangle from all 28 packets. Caught because a probe for the tip's "1 of 28" found nothing, not because anything failed. Resolved once, before the funnel is built; regenerated and verified -- funnel present, tip reads 1 of 28, 95 photos, 11 sheets.
9 lines
660 B
JSON
9 lines
660 B
JSON
{
|
|
"_synthetic": "Toy group set for check:group-set-standard. Every slug, name and number is invented — no real people-group data. The FLAT lists[] shape is the fork contract; unlisted:true keeps an entry out of generation.",
|
|
"source_total": 8,
|
|
"lists": [
|
|
{ "id": "toy-north", "label": "Toy North", "selector": { "type": "pg_slugs", "values": ["toy-alpha", "toy-bravo", "toy-charlie"] } },
|
|
{ "id": "toy-south", "label": "Toy South", "selector": { "type": "pg_slugs", "values": ["toy-delta", "toy-echo"] } },
|
|
{ "id": "toy-hidden", "label": "Toy Hidden", "unlisted": true, "selector": { "type": "pg_slugs", "values": ["toy-foxtrot"] } }
|
|
]
|
|
}
|