From dee8ba057e2edc949b5cfeec0e25283bb9ff0592 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 00:32:09 +0700 Subject: [PATCH 1/2] t27f: reel_factory.t27 -- content features to a unique scene plan per item (Closes #10561) The content factory of epic #10560 (R1 + R2). Each lesson's code and title are read into eleven feature counts; twelve scene archetypes are scored by term frequency over course frequency; the course is planned at once (best pair first, cap 4, no repeat within 2 items, then the least-used generic scene); accent, motion and layout dress the plan; eight output formats and the SSIM anomaly bound for R3. Lab: test-report 8/8 pass, 0 vacuous; seal --verify MATCH; t27b front end accepts it (JIT verdict is the arm64 ratchet's). Co-Authored-By: Claude Opus 5.5 --- .trinity/seals/t27f_reel_factory.json | 33 ++ docs/reports/t27b_expectations.json | 1 + specs/t27f/reel_factory.t27 | 641 ++++++++++++++++++++++++++ 3 files changed, 675 insertions(+) create mode 100644 .trinity/seals/t27f_reel_factory.json create mode 100644 specs/t27f/reel_factory.t27 diff --git a/.trinity/seals/t27f_reel_factory.json b/.trinity/seals/t27f_reel_factory.json new file mode 100644 index 0000000000..8c22289b02 --- /dev/null +++ b/.trinity/seals/t27f_reel_factory.json @@ -0,0 +1,33 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+9448ab4be", + "closure": [ + { + "spec": "specs/t27f/reel_topics.t27", + "spec_hash": "sha256:7c1762cde96524791711594d23f880fbad1f497a499277710f1fd61d52d50157" + } + ], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:b6a88603a9a3556fd210b37e84a10411e684046c214ea485c0d0721744e8aaf1", + "gen_hash_rust": "sha256:d84c9aadc6029a4b5f06179f4f82cb1270d0b96d3fb6bb57d9b2862e046fb94d", + "gen_hash_verilog": "sha256:85e0ff83e7b9e9ce54d8ad183f10e31346ab2332749d6f25ee1939f43e23abff", + "gen_hash_zig": "sha256:c9649bc6a482a56d1986007ae120166bf7488a0f084a02ca0ec2464365970801", + "module": "reel_factory", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-18T17:31:29Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:96099d764ba86fa3ef2c29d81c3838ce255bfd3b3abbd37b27cb86e4bca91012", + "spec_path": "specs/t27f/reel_factory.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 8, + "total": 8, + "vacuous": 0 + }, + "toolchain": { + "test_runner": "sha256:1982ae948e24d00c5d221ccec12dfce1eb01204b53e37b0f857f93b16d64629d", + "zig": "0.16.0" + } +} \ No newline at end of file diff --git a/docs/reports/t27b_expectations.json b/docs/reports/t27b_expectations.json index 09b79809ce..6e4b977d5f 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -1447,6 +1447,7 @@ {"path": "specs/t27f/pbr_sphere.t27", "t27b": "pass"}, {"path": "specs/t27f/quest.t27", "t27b": "pass"}, {"path": "specs/t27f/reel.t27", "t27b": "pass"}, + {"path": "specs/t27f/reel_factory.t27", "t27b": "pass"}, {"path": "specs/t27f/reel_gf16_nmse.t27", "t27b": "pass"}, {"path": "specs/t27f/reel_marketing.t27", "t27b": "pass"}, {"path": "specs/t27f/reel_particles.t27", "t27b": "blocked", "blocker": "ExprCall(@sin)", "reason": "unimplemented"}, diff --git a/specs/t27f/reel_factory.t27 b/specs/t27f/reel_factory.t27 new file mode 100644 index 0000000000..4de799421d --- /dev/null +++ b/specs/t27f/reel_factory.t27 @@ -0,0 +1,641 @@ +// SPDX-License-Identifier: Apache-2.0 +// specs/t27f/reel_factory.t27 -- the content factory: an item's own content in, a scene plan out, +// so that no two reels of a course look alike and no reel is edited by hand. Issue +// gHashTag/t27#10561, epic gHashTag/t27#10560. +// +// WHY: the owner, 2026-10-19: every lesson reel shows almost the same picture, there is no +// uniqueness; make one universal template, a factory, a content factory, not a hand edit of code +// per reel. The cause was in lesson_reel.t27's own NOT CLAIMED block: every lesson's backdrop was +// token_floor's physics world, and only the text over it changed. A template with one scene gives +// every item that scene. +// +// THE FACTORY, in four steps, each a function below: +// features the item's code is read, keyword by keyword at word boundaries (KW_*), into eleven +// counts (F_*): tests, functions, data types, trits, loops, branches, imports, guards, +// asserts, names and pub. Nothing is typed in per lesson. +// score each scene archetype (A_*) shows one kind of content. Its score for an item is how +// much more of that content the item has than the course as a whole: the item's count +// times 1000 over one plus the course's total (term frequency over course frequency, +// K. Sparck Jones, J. Doc. 28, 1972). The lesson about loops wins the loop scene even +// though every lesson has a test block. +// choose the course is planned at once. The best-scoring (item, construct scene) pair is +// assigned first, then the next, never past ARCH_CAP and never within WINDOW items of +// the same scene; then every item left takes the least-used generic scene (its code, +// title, task or place on the course map) free in its window. A first version walked +// the course in order and spent the test scene on lessons 0-6, so lesson 9, "A test +// block", never got it, and lessons 20-26 all fell back to one scene. +// dress the accent is the item's module on the course map (a signal, not decoration, as the +// brand book asks); the camera motion is t mod MOTIONS; the layout is t mod LAYOUTS. +// The signature of a plan is (archetype, accent, motion, layout). The tests hold, over every item +// of the course: no two signatures are equal; two neighbours differ in at least three of the four +// fields; no archetype is used more than ARCH_CAP times; every chosen archetype shows content the +// item has; and the lessons that teach a construct get that construct's scene. +// +// THE FORMATS (FMT_*): every plan renders to the reels, the posts, the cover, the carousel and the +// link cards a channel asks for, at the sizes the channels document. The carousel gets a cover, +// one slide per CAROUSEL_LINES lines of the item's code, and a call to action, at most CAROUSEL_MAX. +// +// THE ANOMALY GATE: when the stills of a course are rendered (R3 of the epic), any two whose SSIM +// is above SIMILAR_MAX_PERMILLE are too alike, and the run fails. The bound is a starting value +// and is not yet measured against rendered stills. +// +// NOT CLAIMED: the renderers of the archetypes are not here, and lesson_reel.t27 still draws +// token_floor's world until it reads this plan (R3 and R4 of the epic). This module decides which +// scene an item gets and checks that the choices are distinct; it draws nothing. The dressing +// alone already separates every signature of a 27-lesson course (motion and layout fix t mod 12, +// the accent tells t from t + 12 and t + 24), so the uniqueness test is weak by itself; the +// window test is the one that keeps the scenes apart. TITLE_WEIGHT is chosen, not measured. +// phi^2 + 1/phi^2 = 3 | TRINITY + +module reel_factory; + +use t27f::reel_topics::TOPICS; +use t27f::reel_topics::code_line0; +use t27f::reel_topics::code_lines; +use t27f::reel_topics::line_len; +use t27f::reel_topics::code_byte; +use t27f::reel_topics::module_of; +use t27f::reel_topics::item; +use t27f::reel_topics::item_len; +use t27f::reel_topics::cp; +use t27f::reel_topics::MODULE_LESSONS; + +// ---- features: the keyword table ---- + +// The keywords, spelled as ASCII bytes end to end; keyword k is KW_BYTES[KW_START[k] .. +// KW_START[k + 1]] and counts toward feature KW_FEATURE[k]. +pub const KWS : usize = 17; +pub const KW_BYTES : [73]u8 = [ + 116, 101, 115, 116, // test + 102, 110, // fn + 115, 116, 114, 117, 99, 116, // struct + 101, 110, 117, 109, // enum + 116, 114, 105, 116, // trit + 119, 104, 105, 108, 101, // while + 102, 111, 114, // for + 105, 102, // if + 115, 119, 105, 116, 99, 104, // switch + 117, 115, 101, // use + 105, 110, 118, 97, 114, 105, 97, 110, 116, // invariant + 98, 101, 110, 99, 104, // bench + 97, 115, 115, 101, 114, 116, // assert + 99, 111, 110, 115, 116, // const + 118, 97, 114, // var + 108, 101, 116, // let + 112, 117, 98, // pub +]; +pub const KW_START : [18]u16 = [0, 4, 6, 12, 16, 20, 25, 28, 30, 36, 39, 48, 53, 59, 64, 67, 70, 73]; + +pub const F_TEST : usize = 0; +pub const F_FN : usize = 1; +pub const F_DATA : usize = 2; +pub const F_TRIT : usize = 3; +pub const F_LOOP : usize = 4; +pub const F_BRANCH : usize = 5; +pub const F_USE : usize = 6; +pub const F_GUARD : usize = 7; +pub const F_ASSERT : usize = 8; +pub const F_NAME : usize = 9; +pub const F_PUB : usize = 10; +pub const FEATS : usize = 11; +pub const FEAT_NAMES : str = "test,fn,data,trit,loop,branch,use,guard,assert,name,pub"; +pub const KW_FEATURE : [17]u8 = [0, 1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 9, 9, 9, 10]; +// What one mention of a construct in a lesson's title weighs against one in its code. +pub const TITLE_WEIGHT : u32 = 10; + +// ---- the archetypes: the scenes an item can get ---- + +pub const A_CODE : usize = 0; // the item's code assembles from particles, line by line +pub const A_GRAPH : usize = 1; // the item's spec as a T27F diagram, declarations flying in +pub const A_TESTS : usize = 2; // each assert lights its PASS, one after another +pub const A_TRIT : usize = 3; // a field of minus-one, zero and plus-one particles +pub const A_LOOP : usize = 4; // particles orbit, one lap per iteration +pub const A_BRANCH : usize = 5; // a stream splits at every if and switch +pub const A_DATA : usize = 6; // a struct's or enum's fields stack as glass blocks +pub const A_LINKS : usize = 7; // the modules an item uses, linked by their use edges +pub const A_GUARD : usize = 8; // an invariant as a ring that holds a value in place +pub const A_TITLE : usize = 9; // the item's title, letter by letter, as kinetic type +pub const A_TASK : usize = 10; // the item's task as a checklist that fills in +pub const A_MAP : usize = 11; // the course map, the item's module lit among the others +pub const ARCHS : usize = 12; +pub const ARCH_NAMES : str = "code,graph,tests,trit,loop,branch,data,links,guard,title,task,map"; +pub const ARCH_CAP : usize = 4; +// No archetype repeats within WINDOW lessons of itself, so the three lessons of a module never +// share a scene. +pub const WINDOW : usize = 2; + +// The generic archetypes draw what every item has (its code, title, task and place on the map); +// the others draw one construct and only an item that has it can get them. +pub fn generic(a: usize) -> bool { + return a == A_CODE || a >= A_TITLE; +} + +// The accents, the camera motions and the layouts the factory dresses a scene in. +pub const ACCENTS : usize = 6; +pub const ACCENT_NAMES : str = "gold,violet,magenta,green,blue,white"; +pub const ACCENT_RGB : [6]u32 = [0xF5B700, 0x8B5CF6, 0xE0409A, 0x22C55E, 0x3B82F6, 0xF5F5F5]; +pub const MOTIONS : usize = 4; +pub const MOTION_NAMES : str = "push,orbit,rise,sweep"; +pub const LAYOUTS : usize = 3; +pub const LAYOUT_NAMES : str = "centre,top,side"; + +// ---- the formats every plan renders to ---- + +pub const FMT_REEL_TALL : usize = 0; +pub const FMT_REEL_WIDE : usize = 1; +pub const FMT_SQUARE : usize = 2; +pub const FMT_PORTRAIT : usize = 3; +pub const FMT_COVER : usize = 4; +pub const FMT_CAROUSEL : usize = 5; +pub const FMT_X_CARD : usize = 6; +pub const FMT_OG : usize = 7; +pub const FMTS : usize = 8; +pub const FMT_NAMES : str = "reel_tall,reel_wide,square,portrait,cover,carousel,x_card,og"; +pub const FMT_W : [8]u32 = [1080, 1920, 1080, 1080, 1080, 1080, 1200, 1200]; +pub const FMT_H : [8]u32 = [1920, 1080, 1080, 1350, 1920, 1350, 675, 630]; +pub const FMT_MOVING : [8]bool = [true, true, false, false, false, false, false, false]; +pub const CAROUSEL_LINES : usize = 6; +pub const CAROUSEL_MAX : usize = 10; + +// ---- the anomaly gate ---- + +pub const SIMILAR_MAX_PERMILLE : u32 = 850; + +pub fn too_similar(ssim_permille: u32) -> bool { + return ssim_permille > SIMILAR_MAX_PERMILLE; +} + +// ---- features ---- + +fn ident_byte(c: u8) -> bool { + return (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 48 && c <= 57) || c == 95; +} + +pub fn kw_len(k: usize) -> usize { + return @as(usize, KW_START[k + 1]) - @as(usize, KW_START[k]); +} + +// Keyword k stands as a whole word at byte p of code line l. +pub fn word_at(l: usize, p: usize, k: usize) -> bool { + const n = kw_len(k); + const len = line_len(l); + if (p + n > len) { + return false; + } + if (p > 0 && ident_byte(code_byte(l, p - 1))) { + return false; + } + if (p + n < len && ident_byte(code_byte(l, p + n))) { + return false; + } + var i : usize = 0; + while (i < n) { + if (code_byte(l, p + i) != KW_BYTES[@as(usize, KW_START[k]) + i]) { + return false; + } + i = i + 1; + } + return true; +} + +// How many times the keywords of feature f stand in lesson t's code. +pub fn code_feat(t: usize, f: usize) -> u32 { + var c : u32 = 0; + const l0 = code_line0(t); + var l : usize = l0; + while (l < l0 + code_lines(t)) { + var p : usize = 0; + while (p < line_len(l)) { + var k : usize = 0; + while (k < KWS) { + if (@as(usize, KW_FEATURE[k]) == f && word_at(l, p, k)) { + c = c + 1; + } + k = k + 1; + } + p = p + 1; + } + l = l + 1; + } + return c; +} + +// How many times a keyword of feature f begins a word of lesson t's English title, case aside: +// "Trits" counts for trit, "Loops: while and for" twice for loop. A title names what a lesson +// teaches, which its code may show less of than a neighbour's: lesson 8, "Expressions", has +// eight asserts and lesson 9, "A test block", one. +pub fn title_feat(t: usize, f: usize) -> u32 { + const it = item(t, 0, 0); + const n = item_len(it); + var c : u32 = 0; + var p : usize = 0; + while (p < n) { + var starts = true; + if (p > 0) { + const q = cp(it, p - 1); + if ((q >= 97 && q <= 122) || (q >= 65 && q <= 90)) { + starts = false; + } + } + if (starts) { + var k : usize = 0; + while (k < KWS) { + if (@as(usize, KW_FEATURE[k]) == f && p + kw_len(k) <= n) { + var same = true; + var i : usize = 0; + while (i < kw_len(k)) { + var x = cp(it, p + i); + if (x >= 65 && x <= 90) { + x = x + 32; + } + if (x != @as(u32, KW_BYTES[@as(usize, KW_START[k]) + i])) { + same = false; + } + i = i + 1; + } + if (same) { + c = c + 1; + } + } + k = k + 1; + } + } + p = p + 1; + } + return c; +} + +// Lesson t's feature f: its code's count plus TITLE_WEIGHT for each time its title names it. +pub fn feat(t: usize, f: usize) -> u32 { + return code_feat(t, f) + TITLE_WEIGHT * title_feat(t, f); +} + +// ---- score ---- + +// How much of archetype a's content lesson t has. A generic archetype reads 1 when the item has +// the thing it draws and 0 when it does not. +pub fn content(t: usize, a: usize) -> u32 { + if (a == A_CODE) { + if (code_lines(t) > 0) { + return 1; + } + return 0; + } + if (a == A_TITLE) { + if (item_len(item(t, 0, 0)) > 0) { + return 1; + } + return 0; + } + if (a == A_TASK) { + if (item_len(item(t, 0, 2)) > 0) { + return 1; + } + return 0; + } + if (a == A_MAP) { + if (module_of(t) * MODULE_LESSONS < TOPICS) { + return 1; + } + return 0; + } + if (a == A_GRAPH) { + return feat(t, F_FN) + feat(t, F_NAME) + feat(t, F_PUB); + } + if (a == A_TESTS) { + return feat(t, F_TEST) + feat(t, F_ASSERT); + } + if (a == A_TRIT) { + return feat(t, F_TRIT); + } + if (a == A_LOOP) { + return feat(t, F_LOOP); + } + if (a == A_BRANCH) { + return feat(t, F_BRANCH); + } + if (a == A_DATA) { + return feat(t, F_DATA); + } + if (a == A_LINKS) { + return feat(t, F_USE); + } + if (a == A_GUARD) { + return feat(t, F_GUARD); + } + return 0; +} + +// The course's total of archetype a's content. +pub fn course_content(a: usize) -> u32 { + var s : u32 = 0; + var t : usize = 0; + while (t < TOPICS) { + s = s + content(t, a); + t = t + 1; + } + return s; +} + +// Lesson t's score for archetype a, given the course total `total` of a's content. +pub fn score_with(t: usize, a: usize, total: u32) -> u32 { + if (generic(a)) { + return content(t, a); + } + return content(t, a) * 1000 / (1 + total); +} + +// ---- choose ---- + +// Lesson t's archetype. The whole course is planned at once, in two passes: +// 1. the content pass: of every (lesson, archetype) pair whose archetype is content-backed +// (not generic), under ARCH_CAP, and not already within WINDOW lessons of the same +// archetype, the best-scoring pair is assigned, then the next, until none is left. So the +// lesson with the most of a construct, relative to the course, gets that construct's scene, +// wherever it stands in the course. +// 2. the generic pass: every lesson still without a scene, in course order, takes the archetype +// it has content for that is free in its window and under the cap and has been used least. +// A lesson the passes cannot place reads ARCHS, which the tests refuse. +pub fn arche(t: usize) -> usize { + var sc : [324]u32 = undefined; + var total : [12]u32 = undefined; + var used : [12]usize = undefined; + var pick : [27]usize = undefined; + var a : usize = 0; + while (a < ARCHS) { + total[a] = 0; + used[a] = 0; + a = a + 1; + } + var i : usize = 0; + while (i < TOPICS) { + pick[i] = ARCHS; + a = 0; + while (a < ARCHS) { + sc[i * ARCHS + a] = content(i, a); + total[a] = total[a] + sc[i * ARCHS + a]; + a = a + 1; + } + i = i + 1; + } + var more = true; + while (more) { + var bt : usize = TOPICS; + var ba : usize = ARCHS; + var bs : u32 = 0; + i = 0; + while (i < TOPICS) { + if (pick[i] == ARCHS) { + a = 0; + while (a < ARCHS) { + if (generic(a) == false && used[a] < ARCH_CAP && sc[i * ARCHS + a] > 0) { + const s = sc[i * ARCHS + a] * 1000 / (1 + total[a]); + if (s > bs) { + var lo : usize = 0; + if (i > WINDOW) { + lo = i - WINDOW; + } + var free = true; + var u : usize = lo; + while (u < TOPICS && u <= i + WINDOW) { + if (pick[u] == a) { + free = false; + } + u = u + 1; + } + if (free) { + bt = i; + ba = a; + bs = s; + } + } + } + a = a + 1; + } + } + i = i + 1; + } + if (bt == TOPICS) { + more = false; + } else { + pick[bt] = ba; + used[ba] = used[ba] + 1; + } + } + i = 0; + while (i < TOPICS) { + if (pick[i] == ARCHS) { + var lo : usize = 0; + if (i > WINDOW) { + lo = i - WINDOW; + } + var best : usize = ARCHS; + a = 0; + while (a < ARCHS) { + if (sc[i * ARCHS + a] > 0 && used[a] < ARCH_CAP) { + var free = true; + var u : usize = lo; + while (u < TOPICS && u <= i + WINDOW) { + if (pick[u] == a) { + free = false; + } + u = u + 1; + } + if (free && (best == ARCHS || used[a] < used[best])) { + best = a; + } + } + a = a + 1; + } + pick[i] = best; + if (best < ARCHS) { + used[best] = used[best] + 1; + } + } + i = i + 1; + } + return pick[t]; +} + +// ---- dress ---- + +pub fn accent(t: usize) -> usize { + return module_of(t) % ACCENTS; +} +pub fn motion(t: usize) -> usize { + return t % MOTIONS; +} +pub fn layout(t: usize) -> usize { + return t % LAYOUTS; +} + +// The signature of lesson t's plan, packed: archetype, accent, motion, layout. +pub fn signature(t: usize) -> usize { + return ((arche(t) * ACCENTS + accent(t)) * MOTIONS + motion(t)) * LAYOUTS + layout(t); +} + +// How many of the four fields two plans differ in. +pub fn fields_apart(a0: usize, c0: usize, m0: usize, y0: usize, a1: usize, c1: usize, m1: usize, y1: usize) -> u32 { + var d : u32 = 0; + if (a0 != a1) { + d = d + 1; + } + if (c0 != c1) { + d = d + 1; + } + if (m0 != m1) { + d = d + 1; + } + if (y0 != y1) { + d = d + 1; + } + return d; +} + +// ---- formats ---- + +// The carousel's slides for lesson t: a cover, its code CAROUSEL_LINES lines a slide, and a call +// to action, at most CAROUSEL_MAX. +pub fn carousel_slides(t: usize) -> usize { + var pages = (code_lines(t) + CAROUSEL_LINES - 1) / CAROUSEL_LINES; + if (pages + 2 > CAROUSEL_MAX) { + pages = CAROUSEL_MAX - 2; + } + return pages + 2; +} + +// ---- tests ---- + +test "the keyword table spells seventeen lowercase words end to end" { + assert(@as(usize, KW_START[0]) == 0); + assert(@as(usize, KW_START[KWS]) == 73); + var k : usize = 0; + while (k < KWS) { + assert(kw_len(k) >= 2); + assert(@as(usize, KW_FEATURE[k]) < FEATS); + var i : usize = 0; + while (i < kw_len(k)) { + const c = KW_BYTES[@as(usize, KW_START[k]) + i]; + assert(c >= 97 && c <= 122); + i = i + 1; + } + k = k + 1; + } +} + +test "the keyword table reads the lessons that teach each construct" { + assert(feat(9, F_TEST) > 0); // A test block + assert(feat(9, F_ASSERT) > 0); + assert(feat(11, F_FN) > 0); // Functions + assert(feat(13, F_BRANCH) > 0); // Choices: if, else and switch + assert(feat(14, F_LOOP) > 0); // Loops: while and for + assert(feat(16, F_DATA) > 0); // Structs + assert(feat(17, F_DATA) > 0); // Enums + assert(feat(18, F_USE) > 0); // Using other modules + assert(feat(19, F_GUARD) > 0); // Invariants and benches + assert(title_feat(7, F_TRIT) == 1); // "Trits: minus one, zero, one" + assert(title_feat(9, F_TEST) == 1); // "A test block" + assert(title_feat(14, F_LOOP) == 2); // "Loops: while and for" + assert(title_feat(8, F_TEST) == 0); // "Expressions" + assert(code_feat(8, F_ASSERT) > code_feat(9, F_ASSERT)); +} + +test "a lesson that teaches a construct gets that construct's scene" { + assert(arche(7) == A_TRIT); + assert(arche(9) == A_TESTS || arche(10) == A_TESTS); + assert(arche(13) == A_BRANCH); + assert(arche(14) == A_LOOP); + assert(arche(18) == A_LINKS); + assert(arche(19) == A_GUARD); + assert(arche(16) == A_DATA || arche(17) == A_DATA); +} + +test "every lesson is placed, no scene repeats within the window, neighbours differ in three of four fields" { + var sig : [27]usize = undefined; + var arc : [27]usize = undefined; + var t : usize = 0; + while (t < TOPICS) { + arc[t] = arche(t); + sig[t] = ((arc[t] * ACCENTS + accent(t)) * MOTIONS + motion(t)) * LAYOUTS + layout(t); + t = t + 1; + } + var i : usize = 0; + while (i < TOPICS) { + var j : usize = i + 1; + while (j < TOPICS) { + assert(sig[i] != sig[j]); + j = j + 1; + } + assert(arc[i] < ARCHS); + if (i > 1) { + assert(arc[i] != arc[i - 2]); + } + if (i > 0) { + assert(arc[i] != arc[i - 1]); + assert(fields_apart(arc[i], accent(i), motion(i), layout(i), arc[i - 1], accent(i - 1), motion(i - 1), layout(i - 1)) >= 3); + } + i = i + 1; + } + assert(signature(5) == sig[5]); +} + +test "no archetype covers more than its cap, and the course uses at least nine of the twelve" { + var used : [12]usize = undefined; + var a : usize = 0; + while (a < ARCHS) { + used[a] = 0; + a = a + 1; + } + var t : usize = 0; + while (t < TOPICS) { + const a_t = arche(t); + used[a_t] = used[a_t] + 1; + t = t + 1; + } + var kinds : usize = 0; + a = 0; + while (a < ARCHS) { + assert(used[a] <= ARCH_CAP); + if (used[a] > 0) { + kinds = kinds + 1; + } + a = a + 1; + } + assert(kinds >= 9); + assert(ARCHS * ARCH_CAP >= TOPICS); +} + +test "every chosen scene shows content its lesson has" { + var t : usize = 0; + while (t < TOPICS) { + const a = arche(t); + assert(a < ARCHS); + assert(content(t, a) > 0); + assert(code_lines(t) > 0); + t = t + 1; + } +} + +test "the formats are the channels' sizes, and a carousel fits its limit" { + assert(FMT_W[FMT_REEL_TALL] * 16 == FMT_H[FMT_REEL_TALL] * 9); + assert(FMT_W[FMT_REEL_WIDE] * 9 == FMT_H[FMT_REEL_WIDE] * 16); + assert(FMT_W[FMT_SQUARE] == FMT_H[FMT_SQUARE]); + assert(FMT_W[FMT_PORTRAIT] * 5 == FMT_H[FMT_PORTRAIT] * 4); + assert(FMT_W[FMT_X_CARD] * 9 == FMT_H[FMT_X_CARD] * 16); + assert(FMT_MOVING[FMT_REEL_TALL] && FMT_MOVING[FMT_REEL_WIDE]); + assert(FMT_MOVING[FMT_COVER] == false); + var t : usize = 0; + while (t < TOPICS) { + const n = carousel_slides(t); + assert(n >= 3); + assert(n <= CAROUSEL_MAX); + t = t + 1; + } +} + +test "the anomaly gate refuses a pair of stills that are too alike" { + assert(too_similar(SIMILAR_MAX_PERMILLE + 1)); + assert(too_similar(SIMILAR_MAX_PERMILLE) == false); + assert(too_similar(400) == false); + assert(ACCENT_RGB[0] == 0xF5B700); +} From eb7a8506f1fa8c07413142571ed8f4361b82303b Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 00:33:20 +0700 Subject: [PATCH 2/2] skills: t27f -- content factory row and its three traps (Closes #10561) Co-Authored-By: Claude Opus 5.5 --- .claude/skills/t27f/SKILL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.claude/skills/t27f/SKILL.md b/.claude/skills/t27f/SKILL.md index 187a88c8ab..f3862bda01 100644 --- a/.claude/skills/t27f/SKILL.md +++ b/.claude/skills/t27f/SKILL.md @@ -68,6 +68,7 @@ the reels. Describing T27F as #1677 is the error this section exists to stop (ow | Renderer in the Trinity UI | gHashTag/trinity | **missing**; no T27F widget is live | | Application: topic map (#1677) | `specs/t27f/topic_engine.t27`, `topic_reel.t27` | spec; procedure below | | Application: reels and deck | `specs/t27f/reel.t27`, `deck.t27`, `reel_*.t27` | spec; two reels | +| Application: content factory (epic t27#10560) | `specs/t27f/reel_factory.t27` (t27#10561) | spec with tests: an item's code and title, read keyword by keyword, give 11 features. Those pick 1 of 12 scene archetypes (best pair first, cap 4, no repeat within 2 items, then the least-used generic scene) plus an accent, a motion, a layout and 8 output formats. No renderer draws a plan yet (R3), and `lesson_reel` still draws token_floor (R4). Lessons: read the plan's spread over the whole course before trusting it. A greedy walk in course order gave 7 lessons one scene. Code counts alone handed lesson 8 the tests scene over "A test block". A printing `main` makes t27b reject the spec | | Related | trinity#1647 dashboards, #1652 MVP research, #1653 three skills, #1655 evolution runtime | open | When asked "how is T27F going", report against the core rows first. Progress on the applications