Repository navigation
Conversation
…whole course on one page (#1703) Owner, 2026-10-19: "make every course free! our task is to grow the language"; "advertise TRI CLAW in the course footer"; "make the page with the course's topic fit on one page ... and make it a widget of widgets". A. Every course free - specs/ladder/course-access.t27: gHashTag/t27 VERSION 3 byte for byte (t27#10799, merge 242ce553); courseAccess.logic.ts rebuilt from it with 999 scripts/t27-logic.mjs (spec-sha256 edd87ade), courseAccess.gen.ts with t27c gen-ts. - courseLadder.ts: a stored course's step is the spec's step_of for its rung, never the step stored with it, so a course opened on a paid rung under VERSION 2 does not close when the club ends (the spec's own instruction to hosts). Test with a mutant that reads the stored step. - The lock, the gate, the club teaser and the rouble/TON pay forms are gone from Course.tsx, with their words, CSS and the checkout client. B. TRI CLAW, three paths, in the footer of every course page - Words and addresses in specs/ladder/course-ladder.t27 (+ RU bundle): own key -> t.me/<bot>?start=app_keys, the club -> ?start=app_club, the GitHub App -> its post while CLAW_APP_PUBLIC is false. The bot is the rules' BOT; no price in the words. C/D. The whole course on one page, the course deck, the layout numbers - specs/view/course-view.t27 (+ generator, RU bundle, tests): reading width per language from a measured character width, breakpoints, the frame budget (3 live, mount 600 px, unmount 2000 px), finger, focus, contrast. Course.css may name only its breakpoints. - scripts/course-onepage.mjs: <share path>all/ per course and language, lazy frames through public/widgets/frame-pool.js, contents column or sheet with progress dots, #lesson-<n>, share, print CSS. - specs/widgets/course-deck.t27 + public/widgets/course-deck: one widget for every course (?course=), nine module tabs, three lesson frames each; gallery entry before the wars pin; opened as "also" by t27-basics' last lesson so the courses still cover the gallery. - Lesson: text and widget side by side from 1150 px, stacked below with the widget right after the task; prev/next under the thumb; 44 px targets; visible focus; reduced motion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ScHVrGSr6zZUdwkdC8DR9k
…ards and the deck page (#1703) Written by scripts/course-pages.mjs, scripts/widget-pages-from-spec.mjs, scripts/widgets-from-spec.mjs and scripts/course-from-spec.mjs from the specs of the previous commit; nothing here is edited by hand. - 22 new pages: learn/<course>/all/ and ru/learn/<course>/all/ (learn/all/ for the first course), each with its own 1200x630 card and ?v= stamp, and in learn/sitemap.xml with its hreflang pair. - Every course and lesson page: the one-page entry and the TRI CLAW block. - widgets/course-deck/: its page and courses/<id>.json (12 files). - widgets/gallery.t27: the course deck before the wars pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ScHVrGSr6zZUdwkdC8DR9k
…hat is also a widget (#1703) The course PR carries its post (specs/policy/course_post.t27): EN body and RU ruBody, registered in index.ts and posts.ts. Its figure is drawn by the compiled step_of of course-access.t27 VERSION 2 (8e535bc) and VERSION 3 (this branch), rungs 0 to 10. The numbers in it are this branch's measurements (3 live frames at most, layout shift 0, 0.43/0.53 em per character) and the spec's constants. It names what the change does not do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ScHVrGSr6zZUdwkdC8DR9k
X Brain Health CheckScore: 100.0/100 X Brain is above merge threshold |
…e is free, the deck refuses an unknown course, the view spec holds what it claims (#1703) - Navigation: the Courses note is the ladder spec's SAY_PROMO_TITLE and its Russian ("Every course is free, no sign-up"), not the old "any three free" literal. - specs/catalog/onboarding.t27 COURSE_NOTE (it feeds /llms.txt and /agents.t27): every course is free, the one-page address; regenerated with onboarding-from-spec.mjs, check:onboarding green. - course-deck: ?course=<unknown> shows SAY_NOT_FOUND instead of t27 basics (pick.js, a pure function; test in course-pages.test.mjs; checked in Chromium for en and ru). - course-view.t27: FOCUS_OFFSET_PX and SETTLE_MS (the frame pool's look after a scroll, now a required parameter of frame-pool.js) join the spec, the deck's K_FOCUS_RING_PX/K_FOCUS_OFFSET_PX/K_SETTLE_MS are held equal to them, the one page's progress bar takes --course-read, and CONTRAST_MIN_X10 is dropped: contrast is measured on the rendered pages, not held by the spec. The generator header and the post now say the spec holds the layout numbers this change decides, not every number. - TRI CLAW's GitHub line says "built to check" in both languages. - CI: Course pages, Course ladder and Course view are their own steps (if: !cancelled()), so the red test:course #29 no longer hides them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ScHVrGSr6zZUdwkdC8DR9k
…ery page's footer (#1703) checks (pure gates) on cb598ae failed at "The HUD can be read while the map is lit" (check:queen-contrast): Footer.tsx imported claw.css and courseView.generated.css, so src/App.tsx (the landing and the board) reached two stylesheets the gate had never measured. The block is only drawn on course pages, so it moves to components/ClawPromo.tsx, which imports both sheets; Footer takes an `aside` node and imports neither. Course.tsx and Courses.tsx pass <ClawPromo />. The gate's REACHED list is unchanged: App.tsx again reaches exactly what it did on main. check:queen-contrast, check:queen-fallback-parity and every other step of the pure-gates job pass locally; only Course (test:course #29) is red, as on main. Chromium: one TRI CLAW block on #/courses and on a lesson, none on #/ or #/blog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ScHVrGSr6zZUdwkdC8DR9k
🧪 Brain Stress Test ResultsTests: 261/261 passed, 0 leaked |
|
Generated by Claude Code |
Closes #1703.
Owner, 2026-10-19: «сделай курсы бесплатно всех! наша задача язык раскачать!!», «в курса футере рекламируй подписку на TRI CLAW» (free with your own API key, more keys can be added; whoever does not want the hassle pays us; and the footer links to installing the TRI CLAW GitHub App), and «сделай чтобы страница с темой курса вместилась в одну страницу … и сделай эту страницу также виджетом, который содержит другие виджеты».
One PR, five commits: the source (A–D), the regenerated static pages and cards, the blog post a course PR carries, and two commits of fixes from the review of this PR (below).
A. Every course free
specs/ladder/course-access.t27is gHashTag/t27specs/automation/course-access.t27VERSION 3 byte for byte (t27#10799, merge 242ce553).src/lib/courseAccess.logic.tswas rebuilt the way it was made, with 999scripts/t27-logic.mjs(t27c from t27 master, Zig 0.16): 9 fns lowered,spec-sha256: edd87ade…= the vendored file.courseAccess.gen.tsist27c gen-tsoutput.step_ofis FREE for every rung.courseStateno longer judges a stored course by the step stored with it: its step isstepOf(rung), the spec's own fn (VERSION 3 tells hosts to do exactly this). A course stored on a paid rung under VERSION 2 stays open when the club ends. Test:scripts/course-ladder-from-spec.test.mjsbundles the realcourseLadder.tsover a fake store; the mutant that reads the stored step turns it red.LadderGate,ClubTeaser,PayForm,TonWait, the checkout client (checkoutOffer,startCheckout,startTonCheckout,readOrder),freeLeft,startLink, the promo/placement plumbing nothing reads any more, 40 words and their RU, and their CSS. The only key machinery kept is the onemay_reportneeds.course-ladder.t27words now say every course is free (SAY_LADDER, catalog, advert), RU bundle in step (every key, same digits).B. TRI CLAW in the course footer, three paths
Words and addresses in
specs/ladder/course-ladder.t27+i18n/course-ladder.ru.json; the generator joins the rules'BOT(t27ai_bot) into the links, so nothing restates the handle.https://t.me/t27ai_bot?start=app_keyshttps://t.me/t27ai_bot?start=app_club(no price in the words; the bot shows it)https://t27.ai/blog/tri-claw-an-agent-you-can-audit/keysroute, which another bee adds in gHashTag/999-multibots-telegraf in parallel. Until it ships,?start=app_keysopens the bot.tri-clawis confirmed by t27docs/claw/README.md(github.com/settings/apps/tri-claw) andspecs/claw/github_surface.t27. I could not confirm that it is public: from this sessiongithub.com/apps/tri-clawandapi.github.com/apps/tri-clawanswer 403,docs/clawhas noapp-manifest.yml,RELEASE.mddefers the Marketplace listing, andgithub_surface.t27measures the App on the gHashTag account only. So, as instructed, the third button opens the TRI CLAW post.CLAW_APP_PUBLIC : bool = falsein the spec picks it; flipping it (and its spec test) to true switches the button tohttps://github.com/apps/tri-clawwith the "Install TRI CLAW on your repository" words, already in both languages. A test holds both states.ClawPromo,src/styles/claw.css) shows on every course page, lesson page and the catalog in the app, and on every static course, lesson and one-page view (the same sheet, inlined).C. The whole course on one page, and a widget of widgets
scripts/course-onepage.mjs, called bycourse-pages.mjs, writes<share path>all/for every course and language:t27.ai/learn/all/(t27 basics),t27.ai/learn/<course>/all/,ru/before each. 22 pages, each with its own 1200×630 card (?v=stamp), canonical, hreflang pair, JSON-LD and a sitemap entry. It carries the intro, then every module, then each lesson's title, goal, text, task and widget.public/widgets/frame-pool.js(one implementation for the page and the deck). A frame mounts when its slot is withinMOUNT_MARGIN_PX600 of the viewport, at mostLIVE_FRAMES_MAX3 are live (the farthest gives way), a frame further thanUNMOUNT_MARGIN_PX2000 is taken down. Each slot holds the frame's height before it loads.← · Contents 08/27 · →that opens a sheet with the same list. Deep links#lesson-<n>, share for the page (native share, copy, X, Telegram, LinkedIn, utm-tagged byshareTags.ts) and per lesson (its own static page), mark-as-done in the same browser key as the app, print CSS.specs/widgets/course-deck.t27+public/widgets/course-deck/, data incourses/<id>.jsonwritten bycourse-pages.mjs. Nine module tabs, the module's three lessons as a scroll-snap row, each card nesting its lesson widget through the same frame pool (K_LIVE_FRAMES_MAX3 = one module). One generic widget (?course=<id>&module=<n>&lang=ru) instead of eleven: the eleven would differ only in data, and a twelfth course would need a twelfth widget, spec, card and gallery entry; this one needs nothing. Its K_ numbers are the view spec's, held equal bycourse-view-from-spec.mjs; no K_ holds a spec fn result, nologic.js,widget-logic --checkunaffected.the_course_deck_closes_the_course_shelves_before_the_arena.course-from-specrequires the courses to cover the whole gallery, so t27-basics lesson 27 ("Where next") opens the deck as its "also" widget, the one-word spec change that makes this a course PR (hence the post).#lesson-<n>), every static course and lesson page.D. UI/UX, the layout numbers in
specs/view/course-view.t2768chwould have been ~95 characters: achis a zero, and Outfit's zero is 0.66 em. Measured in Chromium over three courses at 18 px: an average character is 0.427–0.432 em in English (Outfit) and 0.531–0.532 em in Russian (system fallback). SoREAD_EM_X10_EN301 and_RU372 (30.1 em / 37.2 em ≈ 70 characters); the spec's tests hold both inside 65–75 characters, and:lang(ru)picks the wider one.SIDE_BY_SIDE_MIN_PX1150 (tested: two gutters + gap + the Russian column +WIDGET_MIN_PX400 fit); below it text, task, then the widget, then the mark. Contents column from 1440.NARROW_MAX_PX= the site'sPHONE_MAX600 andTOUCH_TARGET_PX= the site'sTOUCH_TARGET_MIN_PX44 (cross-checked against the vendoredspecs/ui/viewport.t27).Course.cssmay name only the spec's breakpoints (900/520 became 1149/600; a stray width fails the check).THUMB_BAR_PX56. 44 px targets for chips, buttons, crumbs links, notes links. Reserved frame height.:focus-visibleringFOCUS_RING_PX2.prefers-reduced-motiondrops transitions and smooth scroll. Greys under 4.5:1 (#6f6f6f,#5a5a5a) raised to#a6a6a6/#8a8a8a.Fixes from the review (commits f6705ac and 301e5f1)
SAY_PROMO_TITLE/ its Russian ("Every course is free, no sign-up"), no longer the "any three free" literal (checked in Chromium, en and ru).specs/catalog/onboarding.t27COURSE_NOTE(feeds/llms.txtand/agents.t27) now says every course is free and names the one-page address; regenerated withonboarding-from-spec.mjs,check:onboardingandtest:onboarding-specgreen.SAY_NOT_FOUNDfor?course=<unknown>instead of t27 basics:public/widgets/course-deck/pick.js(pure), tested incourse-pages.test.mjs, checked in Chromium (?course=nope→ "This course is not in the catalog." / «Такого курса нет в каталоге.», 0 frames).course-view.t27:FOCUS_OFFSET_PX2 andSETTLE_MS120 (the pool's look after scrolling stops, now a required parameter offrame-pool.js) are spec constants with tests; the deck'sK_FOCUS_RING_PX,K_FOCUS_OFFSET_PX,K_SETTLE_MSare held equal to them; the one page's progress bar takes--course-readinstead of 760 px.CONTRAST_MIN_X10is dropped: contrast is measured on the rendered pages (table below), not held by the spec. The generator header and the post now say the spec holds the layout numbers this change decides; type sizes, paddings and colours stay in the stylesheets.Course pages,Course ladderandCourse vieware separate steps withif: ${{ !cancelled() }}, so the redtest:courseАнализ проекта для ученых #29 no longer hides them.checks (pure gates)on cb598ae failed at "The HUD can be read while the map is lit" becauseFooter.tsximportedclaw.cssandcourseView.generated.css, sosrc/App.tsx(landing and board) reached two sheets the gate never measured. Root cause fixed rather than the list widened: the block moved tocomponents/ClawPromo.tsx(which imports both sheets),Footertakes anasidenode and imports neither, andCourse.tsx/Courses.tsxpass<ClawPromo />. App.tsx reaches exactly what it did on main. Every step of the pure-gates job now passes locally exceptCourse(Анализ проекта для ученых #29, as on main); Chromium shows one TRI CLAW block on#/coursesand on a lesson, none on#/or#/blog.Playwright (Chromium 1194; 390×844 touch, 1280×800), re-run on 301e5f1
…/all/#lesson-8lands with the lesson 12 px from the top and its frame live. The contents sheet lists 27 lessons with 27 dots; tapping lesson 20 closes it, the bar reads 20/27; marking it done fills its dot and the counter reads "1 of 27 done". At 1440 the contents column is 240 px, sticky, and marks the lesson in view; the bar is gone.prefers-reduced-motion: reduce→scroll-behavior: auto. Tab focus draws a 2 px solid ring.<link rel=preload>it is 0.learn/relu/) scrolls 25 px sideways at 390 px on main as well as here; the cause is not found.Screenshots (session scratchpad
onepage/shots/):onepage-neural-networks-390-top.png(the intro, the "free" pill, the bottom bar),onepage-neural-networks-390-lesson8.png(lesson 8 stacked: goal, text, task, the widget right after),onepage-neural-networks-1280-lesson8.png(side by side),onepage-1440.png(the contents column with dots),onepage-390-contents.png(the contents sheet),lesson-390-footer.pngandlesson-1280-ru-footer.png(the TRI CLAW block, three paths),lesson-390.png(compact crumbs, thumb bar),deck-390.png/deck-1280.png(the deck embed, module tabs, live lesson widgets),blog-390.png(the post's figure).Checks (apps/website, local, on 301e5f1)
npm run build✓ (the 8 JSON files the prebuild rewrites restored) · a secondgen:course-pagesleaves no diff.website-checks.ymlrunsCourse(check:course, test:course), thenCourse pages,Course ladderandCourse viewas their own steps;course-view-from-spec.mjsis also inprebuild.{ "version": 1, "head_sha": "301e5f187013001174ba0d84d0d5fe1ba5ac3e2c", "summary": "Every t27.ai course is free (course-access.t27 VERSION 3); each course has a whole-course-on-one-page view and a course-deck widget that loads at most 3 lesson widgets at once; TRI CLAW has three paths in the course footer.", "changes": [ "specs/ladder/course-access.t27: gHashTag/t27 VERSION 3 byte for byte; src/lib/courseAccess.logic.ts rebuilt with 999 scripts/t27-logic.mjs (9 fns, spec-sha256 edd87ade), courseAccess.gen.ts with t27c gen-ts.", "src/lib/courseLadder.ts: a stored course's step is step_of for its rung, not the stored step, so a course opened on a paid rung under VERSION 2 does not close when the club ends; the checkout client, notePromo and startLink are gone.", "src/pages/Course.tsx, Courses.tsx, CourseShelf.tsx: no lock, gate, club teaser or rouble/TON pay form; their words, CSS and tests removed.", "specs/ladder/course-ladder.t27 + i18n/course-ladder.ru.json: words say every course is free; TRI CLAW words and addresses (app_keys, app_club, the App behind CLAW_APP_PUBLIC); the generator joins the rules' BOT into the t.me links.", "components/Footer.tsx ClawPromo + src/styles/claw.css: the TRI CLAW block on every course, lesson and catalog page; the same sheet is inlined into every static course page.", "specs/view/course-view.t27 + scripts/course-view-from-spec.mjs: reading width per language from a measured character width, breakpoints, frame budget, finger and focus; Course.css may name only these breakpoints.", "scripts/course-onepage.mjs + public/widgets/frame-pool.js: <share path>all/ per course and language with its card, lazy frames, contents column or sheet with progress dots, deep links, share and print CSS.", "specs/widgets/course-deck.t27 + public/widgets/course-deck: one widget for every course, in the gallery before the wars pin; opened as 'also' by t27-basics lesson 27.", "Lesson UX: side by side from 1150 px, stacked below with the widget right after the task; a thumb bar; 44 px targets; focus ring; reduced motion.", "src/data/blog: the course PR's post, EN and RU, with a figure drawn by the compiled step_of of VERSION 2 and 3.", "Review fixes: the nav note and llms.txt COURSE_NOTE say every course is free from their specs; the deck shows SAY_NOT_FOUND for an unknown ?course=; FOCUS_OFFSET_PX and SETTLE_MS join course-view.t27 and CONTRAST_MIN_X10 leaves it; CI runs the course pages, ladder and view gates as separate steps.", "The TRI CLAW block moved from Footer.tsx to components/ClawPromo.tsx, passed in by the course pages, so the landing and the board no longer load claw.css and courseView.generated.css (check:queen-contrast red on cb598aeb, green now)." ], "tests": [ { "command": "cd apps/website && npm run check:course", "status": "passed", "result": "course-from-spec: 11 courses build clean; the gallery is covered (course-deck is an 'also' widget of t27-basics lesson 27)", "evidence": "local run on 301e5f18, log final-check:course.log in the session scratchpad" }, { "command": "cd apps/website && npm run test:course", "status": "failed", "result": "41 pass, 1 fail: #29 'the scan reads lesson specs before its wipe and settles them after it', the same test that is red on main", "evidence": "local run, log final-test:course.log; #29 is a known red on main, not touched here" }, { "command": "cd apps/website && npm run check:course-ladder && npm run test:course-ladder", "status": "passed", "result": "rules sha edd87ade1cc3 = the vendored VERSION 3; 26 words in 2 languages; 10/10 tests, including the re-rung test (a mutant that reads the stored step fails it)", "evidence": "local run; mutation run by hand: courseState with opened[at].step instead of stepOf(rungOf(at)) turns test 9 red" }, { "command": "cd apps/website && npm run check:course-view && npm run test:course-view", "status": "passed", "result": "27 numbers, 13 words; spec tests 8 blocks / 28 asserts hold; 6/6 tests incl. negative controls on the breakpoint, the reading width, the frame budget, the deck K_ numbers, the viewport finger and Course.css @media widths", "evidence": "local run, logs last-check:course-view.log, last-test:course-view.log" }, { "command": "cd apps/website && npm run gen:course-pages && npm run check:course-pages", "status": "passed", "result": "638 pages (22 of them whole courses on one page), 638 cards, 12 course-deck files, sitemap; 18/18 page tests incl. the deck's not-found pick; a second gen:course-pages leaves no diff", "evidence": "local run; cards drawn with Playwright Chromium 1194 behind a --no-sandbox wrapper" }, { "command": "cd apps/website && npm run check:widget-logic && npm run test:widget-logic", "status": "passed", "result": "111 widgets run their spec's own logic; the deck has no logic.js and no K_ holding a spec fn result", "evidence": "local run in the worktree on 301e5f18; output kept in the session scratchpad logs" }, { "command": "cd apps/website && npm run check:widget-pages && npm run test:widget-pages", "status": "passed", "result": "194 tool pages up to date, course-deck included (2 of its 3 test blocks are invariants of its own)", "evidence": "local run in the worktree on 301e5f18; output kept in the session scratchpad logs" }, { "command": "cd apps/website && npm run check:widgets && npm run test:widgets-spec", "status": "passed", "result": "307 widgets in 3 categories; spec tests 15 blocks / 69 asserts hold, the new block pins course-deck at 298 between hive-cell and wars", "evidence": "local run in the worktree on 301e5f18; output kept in the session scratchpad logs" }, { "command": "cd apps/website && npm run check:og-preview", "status": "passed", "result": "og-preview contract ok; CourseShare is unchanged", "evidence": "local run in the worktree on 301e5f18; output kept in the session scratchpad logs" }, { "command": "cd apps/website && npm run check:queen-fallback-parity", "status": "passed", "result": "no var() fallback disagrees with its token (claw.css and courseView.generated.css use none)", "evidence": "local run in the worktree on 301e5f18; output kept in the session scratchpad logs" }, { "command": "cd apps/website && npm run typecheck:ratchet", "status": "passed", "result": "179 errors across 26 files; baseline 179 across 26; no file gained type errors", "evidence": "local run in the worktree on 301e5f18; output kept in the session scratchpad logs" }, { "command": "cd apps/website && npm run build", "status": "passed", "result": "prebuild and vite build green; the 8 tracked JSON files the prebuild rewrites were restored with git checkout --", "evidence": "local run, logs final-build.log and vite3.log" }, { "command": "node measure.mjs (Playwright Chromium 1194; 390x844 touch and 1280x800)", "status": "passed", "result": "one-page view of neural-networks (en) and t27-basics (ru): 0 errors, 0 px sideways, 0 targets under 44 px, live frames at most 3 over 48-90 scroll steps, layout shift 0, worst text contrast 8.37:1; lesson page: 0 errors, CLS 0, frame height reserved, worst contrast 5.92:1; deck embed: 3 live frames, 3 after switching to module 5", "evidence": "session scratchpad onepage/measure.json and onepage/shots/*.png" }, { "command": "cd apps/website && npm run check:onboarding && npm run test:onboarding-spec", "status": "passed", "result": "public/agents.t27 and public/llms.txt regenerated from the new COURSE_NOTE, 25494 bytes each; spec tests 10 blocks / 55 asserts hold; 4/4 tests", "evidence": "local run in the worktree on 301e5f18; output kept in the session scratchpad logs" }, { "command": "cd apps/website && npm run check:queen-contrast && npm run check:queen-fallback-parity, then every run: step of the checks-pure job", "status": "passed", "result": "queen-contrast: 24 pairs, worst 5.39:1, 38 stylesheets walked from QueenUniverse.tsx + App.tsx; fallback parity clean; the other 58 steps of the pure-gates job pass too, except Course (test:course #29, red on main too)", "evidence": "local run in the worktree on 301e5f18; CI on cb598aeb had failed at this step, logs in the session scratchpad" }, { "command": "cd apps/website && npm run test:agents-specs", "status": "not_run", "result": "not run on this branch; the two failing agents-from-specs tests are known reds on main and this PR does not touch that generator", "evidence": "No log: the command was not run on this branch; scripts/agents-from-specs.mjs is unchanged in this diff" } ], "limitations": [ "The free TRI CLAW path opens t.me/t27ai_bot?start=app_keys; the keys route is added to the app in gHashTag/999-multibots-telegraf in parallel and is not verified here.", "The TRI CLAW GitHub App could not be checked as public from this session (github.com and api.github.com/apps are closed to it); docs/claw has no app-manifest.yml and defers the Marketplace listing, so the footer links the TRI CLAW post until CLAW_APP_PUBLIC is set true.", "Measured in Playwright Chromium only, not on a real phone or in Safari; the frame budget is measured as iframe counts, not as memory.", "A static lesson page (learn/<lesson>/) scrolls 25 px sideways at 390 px in Chromium on main and on this branch; the cause was not found and is not addressed here.", "test:course #29 stays red as on main." ], "tags": [ "t27", "Courses", "UX", "TRICLAW" ], "blog": { "title": "Every course is free now, and each one fits on one page that is also a widget", "summary": "step_of in course-access.t27 VERSION 3 returns FREE for every rung, and a whole-course page keeps at most 3 of its 27 lesson widgets live while it scrolls.", "outline": [ "The courses asked for the club from the fourth course on, and a course the reader cannot open is a reader the language does not get; the owner made every course free on 2026-10-19, and the rule changed first in the gHashTag/t27 spec, VERSION 3.", "The site runs step_of compiled from that spec, and re-asks it for every stored course, so a course opened on the old club rung stays open after the club ends; each course got one page with all 27 lessons, whose widget frames mount near the screen, 3 at most, 600 px ahead and 2000 px behind, measured at 390 and 1280 px with no sideways scroll and no layout shift.", "The same course is one embeddable widget of widgets; the footer offers TRI CLAW three ways; the keys screen ships in the app separately, the GitHub App link waits until it is open to other repositories, and the static lesson page's 25 px sideways scroll is still unexplained." ], "reproduce": [ "cd apps/website && npm run check:course-view && npm run test:course-ladder", "cd apps/website && npm run gen:course-pages && npm run check:course-pages" ] } }🤖 Generated with Claude Code
https://claude.ai/code/session_01ScHVrGSr6zZUdwkdC8DR9k