From dee8ba057e2edc949b5cfeec0e25283bb9ff0592 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 00:32:09 +0700 Subject: [PATCH 1/4] 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/4] 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 From 99ca8d78a9d8b14760cc2fe573cfd92b7b6aae73 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 01:02:09 +0700 Subject: [PATCH 3/4] t27f: reel_beats.t27 -- every reel as open, main and close, no two the same sequence (Closes #10584) Each lesson reel of course 0 becomes three beats: main is the factory's arche(t), open the item's best other construct (generic fallback), close a rotating generic. Tests over all 27 lessons: every beat placed, three distinct scenes a reel, no two reels share the ordered pair (open, main), neighbours differ in every position, every beat shows content its item has. Measured: 21 of 27 lessons have content for graph and tests alone among the constructs, so unordered pairs (15 possible) cannot be unique for 27 reels; the rule is on ordered pairs (30). 19 of 27 opens are constructs. test-report on the Railway lab: 7/7 pass, 0 vacuous. t27b builds an aarch64 object. Seal saved and verified. Ledger row pass; cap unchanged. Co-Authored-By: Claude Opus 5.5 --- .trinity/seals/t27f_reel_beats.json | 37 +++++ docs/reports/t27b_expectations.json | 1 + specs/t27f/reel_beats.t27 | 244 ++++++++++++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 .trinity/seals/t27f_reel_beats.json create mode 100644 specs/t27f/reel_beats.t27 diff --git a/.trinity/seals/t27f_reel_beats.json b/.trinity/seals/t27f_reel_beats.json new file mode 100644 index 0000000000..8d003251d3 --- /dev/null +++ b/.trinity/seals/t27f_reel_beats.json @@ -0,0 +1,37 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+9448ab4be", + "closure": [ + { + "spec": "specs/t27f/reel_factory.t27", + "spec_hash": "sha256:96099d764ba86fa3ef2c29d81c3838ce255bfd3b3abbd37b27cb86e4bca91012" + }, + { + "spec": "specs/t27f/reel_topics.t27", + "spec_hash": "sha256:7c1762cde96524791711594d23f880fbad1f497a499277710f1fd61d52d50157" + } + ], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:d83963d6f15f810d29f87edeb1c98d40928612cc2fcc48cedcf3e9557df14e7e", + "gen_hash_rust": "sha256:041b2748f1e1199063b73fd00970dcc6db10602ce7f1ad934d879d86c0e13920", + "gen_hash_verilog": "sha256:4869ae2493cdc3f9f8c82dca42898a8a2366aef9a61ad190567626b8ee2e1fe3", + "gen_hash_zig": "sha256:d96bd594710b380e505389559632939ec5500b21b593bdd40d1fd3b7525e4d51", + "module": "reel_beats", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-18T18:01:36Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:5b30be8b6d549ec9c0fee0132877f143cd3af9d04e51568eaa51f2ac50a30d0c", + "spec_path": "specs/t27f/reel_beats.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 7, + "total": 7, + "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 6e4b977d5f..01e7d890f5 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_beats.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"}, diff --git a/specs/t27f/reel_beats.t27 b/specs/t27f/reel_beats.t27 new file mode 100644 index 0000000000..08f0dc7450 --- /dev/null +++ b/specs/t27f/reel_beats.t27 @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: Apache-2.0 +// specs/t27f/reel_beats.t27 -- every reel of a course as three beats, open, main and close, so +// that no two reels show the same scenes. Issue gHashTag/t27#10584, epic gHashTag/t27#10560. +// +// WHY: reel_factory.t27 gives each lesson one scene archetype, at most ARCH_CAP = 4 times a +// course, so up to four reels share their only scene and differ in accent, motion and layout +// alone. Its own NOT CLAIMED block says the signature test is weak by itself. Tools that fill one +// fixed structure with an item's text produce exactly the sameness the owner saw; the ones that +// look varied let the data choose the scene list (Motion Canvas and Revideo take a list of scenes +// per project). Here the data chooses three. +// +// THE BEATS, planned for the whole course at once, in course order: +// main the factory's scene, arche(t). Nothing here changes it. +// open the scene of the item's next construct: of the archetypes the item has content for, +// other than main, the best by reel_factory's term-frequency score, where any construct +// ranks above any generic scene. It may not repeat the previous reel's open, and the ordered +// pair (open, main) may not be one an earlier reel already has. +// close a generic scene (code, title, task or map), rotating from t mod GENERICS, other than +// main and open, and not the previous reel's close. +// A beat the plan cannot place reads ARCHS, which the tests refuse. +// +// The tests hold over every lesson of course 0: every beat placed; three distinct scenes a reel; +// no two reels open the same way into the same main, so no two show the same sequence; neighbours +// differ in every position; every beat shows content its item has, and every close is generic. +// +// NOT CLAIMED: +// - Not that an unordered pair of scenes is unique. Measured on course 0: 21 of 27 lessons have +// content for graph and tests alone among the constructs, so their scenes come from six archetypes, +// which make 15 unordered pairs for 27 reels. Ordered pairs (open, main) number 30, and the rule +// holds on those. For the same reason open falls back to a generic scene when main took the only +// construct the item has left, or the pair rule refused it. +// - The plan arrays are sized for course 0 (COURSE = 27, checked against TOPICS by a test). A +// course of another length needs the size changed with it. +// - Beat lengths in frames, and the transitions between beats, are not here. The renderers are R3 +// (#10571) and the reel that reads this plan is R4. +// - "Shows content the item has" is the factory's content() count being positive. It does not say +// the open is interesting; a lesson whose only second construct is one test block opens on it. +// phi^2 + 1/phi^2 = 3 | TRINITY + +module reel_beats; + +use t27f::reel_topics::TOPICS; +use t27f::reel_factory::A_CODE; +use t27f::reel_factory::A_TITLE; +use t27f::reel_factory::A_TASK; +use t27f::reel_factory::A_MAP; +use t27f::reel_factory::ARCHS; +use t27f::reel_factory::generic; +use t27f::reel_factory::content; +use t27f::reel_factory::course_content; +use t27f::reel_factory::score_with; +use t27f::reel_factory::arche; + +pub const COURSE : usize = 27; +pub const BEATS : usize = 3; +pub const GENERICS : usize = 4; +// The generic archetypes in close rotation order: code, title, task, map. +pub const GENERIC_ARCH : [4]usize = [0, 9, 10, 11]; + +// ---- the pair rule ---- + +// Whether a reel before t already opens on a into the main m. +pub fn pair_used(mn: [27]usize, op: [27]usize, t: usize, m: usize, a: usize) -> bool { + var s : usize = 0; + while (s < t) { + if (mn[s] == m && op[s] == a) { + return true; + } + s = s + 1; + } + return false; +} + +// How open ranks archetype a for lesson t: 0 when a is generic, otherwise one more than its +// factory score, so that any construct beats any generic scene. +pub fn open_rank(t: usize, a: usize, total: u32) -> u32 { + if (generic(a)) { + return 0; + } + return score_with(t, a, total) + 1; +} + +// ---- plan ---- + +// The beats of every lesson: op the open, mn the main, cl the close. +pub fn plan_beats(op: *[27]usize, mn: *[27]usize, cl: *[27]usize) -> void { + var total : [12]u32 = undefined; + var a : usize = 0; + while (a < ARCHS) { + total[a] = course_content(a); + a = a + 1; + } + var t : usize = 0; + while (t < COURSE) { + mn[t] = arche(t); + op[t] = ARCHS; + cl[t] = ARCHS; + t = t + 1; + } + t = 0; + while (t < COURSE) { + var best : usize = ARCHS; + var best_rank : u32 = 0; + a = 0; + while (a < ARCHS) { + var ok = a != mn[t] && content(t, a) > 0; + if (ok && t > 0 && a == op[t - 1]) { + ok = false; + } + if (ok && pair_used(mn.*, op.*, t, mn[t], a)) { + ok = false; + } + if (ok) { + const r = open_rank(t, a, total[a]); + if (best == ARCHS || r > best_rank) { + best = a; + best_rank = r; + } + } + a = a + 1; + } + op[t] = best; + var k : usize = 0; + while (k < GENERICS && cl[t] == ARCHS) { + const g = GENERIC_ARCH[(t + k) % GENERICS]; + var free = g != mn[t] && g != op[t] && content(t, g) > 0; + if (free && t > 0 && g == cl[t - 1]) { + free = false; + } + if (free) { + cl[t] = g; + } + k = k + 1; + } + t = t + 1; + } +} + +// ---- tests ---- + +test "the plan is sized for this course and its generic list is the factory's" { + assert(COURSE == TOPICS); + assert(GENERIC_ARCH[0] == A_CODE); + assert(GENERIC_ARCH[1] == A_TITLE); + assert(GENERIC_ARCH[2] == A_TASK); + assert(GENERIC_ARCH[3] == A_MAP); + var k : usize = 0; + while (k < GENERICS) { + assert(generic(GENERIC_ARCH[k])); + k = k + 1; + } +} + +test "the pair rule sees an earlier pair in its order and nothing at or after t" { + var mn : [27]usize = undefined; + var op : [27]usize = undefined; + var t : usize = 0; + while (t < 27) { + mn[t] = 0; + op[t] = 9; + t = t + 1; + } + mn[3] = 4; + op[3] = 2; + assert(pair_used(mn, op, 4, 4, 2)); + assert(pair_used(mn, op, 4, 2, 4) == false); + assert(pair_used(mn, op, 3, 4, 2) == false); + assert(pair_used(mn, op, 27, 4, 5) == false); + assert(open_rank(0, A_TITLE, 5) == 0); +} + +test "every beat of every reel is placed" { + var op : [27]usize = undefined; + var mn : [27]usize = undefined; + var cl : [27]usize = undefined; + plan_beats(&op, &mn, &cl); + var t : usize = 0; + while (t < COURSE) { + assert(op[t] < ARCHS); + assert(mn[t] < ARCHS); + assert(cl[t] < ARCHS); + t = t + 1; + } +} + +test "every reel shows three different scenes" { + var op : [27]usize = undefined; + var mn : [27]usize = undefined; + var cl : [27]usize = undefined; + plan_beats(&op, &mn, &cl); + var t : usize = 0; + while (t < COURSE) { + assert(op[t] != mn[t]); + assert(cl[t] != mn[t]); + assert(cl[t] != op[t]); + t = t + 1; + } +} + +test "no two reels open the same way into the same main, so no two show the same sequence" { + var op : [27]usize = undefined; + var mn : [27]usize = undefined; + var cl : [27]usize = undefined; + plan_beats(&op, &mn, &cl); + var s : usize = 0; + while (s < COURSE) { + var t : usize = s + 1; + while (t < COURSE) { + assert((mn[s] == mn[t] && op[s] == op[t]) == false); + assert((op[s] == op[t] && mn[s] == mn[t] && cl[s] == cl[t]) == false); + t = t + 1; + } + s = s + 1; + } +} + +test "two neighbouring reels differ in every beat" { + var op : [27]usize = undefined; + var mn : [27]usize = undefined; + var cl : [27]usize = undefined; + plan_beats(&op, &mn, &cl); + var t : usize = 1; + while (t < COURSE) { + assert(op[t] != op[t - 1]); + assert(mn[t] != mn[t - 1]); + assert(cl[t] != cl[t - 1]); + t = t + 1; + } +} + +test "every beat shows content its item has, and every close is generic" { + var op : [27]usize = undefined; + var mn : [27]usize = undefined; + var cl : [27]usize = undefined; + plan_beats(&op, &mn, &cl); + var t : usize = 0; + while (t < COURSE) { + assert(content(t, op[t]) > 0); + assert(content(t, mn[t]) > 0); + assert(content(t, cl[t]) > 0); + assert(generic(cl[t])); + t = t + 1; + } +} From ca1c2c5b9be03717374abc65bf8335b690a88765 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 19 Oct 2026 01:11:05 +0700 Subject: [PATCH 4/4] skills: t27f -- beats section: count the pool before promising uniqueness (Closes #10584) R7 experience. The unordered pair rule was infeasible on course 0: 15 pairs for 27 reels, measured from the content matrix. t27c gen imports std only in a module that has a test block. Printers stay on the lab. Co-Authored-By: Claude Opus 5.5 --- .claude/skills/t27f/SKILL.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.claude/skills/t27f/SKILL.md b/.claude/skills/t27f/SKILL.md index f3862bda01..f52737b3b6 100644 --- a/.claude/skills/t27f/SKILL.md +++ b/.claude/skills/t27f/SKILL.md @@ -194,6 +194,29 @@ approved)`. Keep drafts, verified results and published items under separate headings (`layer_of`). If the journey is saved, save it as a `.t27` data module, not JSON. Saving follows the user's instruction. +## Application: content factory, beats (t27#10584) + +`specs/t27f/reel_beats.t27` plans every reel of course 0 as three beats: open, main and close. +Main is `arche(t)` from `reel_factory.t27`. Open is the best other construct, with a generic +fallback. Close is a rotating generic. No two reels share the ordered pair (open, main), and +neighbouring reels differ in every beat. + +Before you change a uniqueness rule, measure what it can draw from: + +- **Count the pool before you promise uniqueness.** 21 of 27 course-0 lessons have content only + for graph and tests among the constructs. This is measured, not a detection bug: course 0's + snippets have no `while` or `if`. Six archetypes make only 15 unordered pairs for 27 reels, + so an unordered rule fails 4 of 7 tests. Ordered pairs (30) hold. Print the content matrix + (lesson by archetype `content()`) first. +- **A generated printer needs a test block.** `t27c gen` emits `const std = @import("std")` + only when the module has a test. Without one, `std.debug.print` fails in zig with "use of + undeclared identifier 'std'". Give a lab-only printer one trivial `test`. +- **Keep scratch printers on the lab.** Copy them into `specs/` for `t27c gen`, then `rm` them + in the same command. Never commit them. +- **Write PR bodies with the Write tool.** The Mac hook matches words in a + shell heredoc, such as a PR body that mentions tests. Write the body with the Write tool, then + pass `--body-file`. + ## What this skill does not claim The graph IR is a schema (`specs/t27f/spec_graph.t27`) and `specs/t27f/spec_graph_export.t27` turns source into it, but only exact declarations, spans and edges within the IR's capacity, with `specs/t27f/spec_graph_derive.t27` adding the derived and unknown part by stated rules, and no host calls either yet; no renderer draws a T27F view in the Trinity UI, no