discoman
  • Joined on 2026-02-10
discoman pushed to main at discoman/python-tdd 2026-05-13 02:50:22 +00:00
eccb84f92b applet feed unification — My Buds + My Notes drop the [Feature forthcoming] / empty placeholders for live top-3 feeds, mirroring the long-standing My Posts pattern; all five in-grid list applets (My Posts / My Buds / My Notes / My Scrolls / My Games) now route their <ul> through a single shared partial _applet-grid-list.html (newly extracted) so item rendering + empty-state row + scroll-buffer all live in one place — _applet-list-shell.html (the dedicated billbuds/billposts page shell) now internally includes the same grid-list partial for its inner <ul>, so the dedicated-page and in-grid lists share the same skeleton; new per-applet item partials _my_buds_applet_item.html (mirrors _my_buds_item.html w. data-bud-id + display_name), _my_notes_item.html (links to billboard:my_notes; uses display_name), _my_posts_applet_item.html (Post link + title), _my_scrolls_item.html (Room link to billboard:scroll), _my_games_item.html (Room link to epic:gatekeeper); view-side _billboard_context gains _recent_buds(user) — sorts the User.buds auto-through table by -id so newest-added-first w.o. an explicit through model w. timestamps (manage [r.to_user for r in rows]) — + _recent_notes(user) (user.notes.order_by('-earned_at')[:limit]); same two helpers threaded into new_post's GET-with-form-errors branch (line 270-274) so the rerender keeps the new applet content visible; 7 ITs added to BillboardViewTest covering recent_buds ordering / cap / empty + recent_notes ordering / cap / cross-user isolation / empty; SCSS — .applet-list / .applet-list-entry / .applet-list-buffer lifted from .applet-list-page .applet-scroll scope to top level so they apply in both surfaces; in-grid applets get display: flex; flex-direction: column; .applet-list { flex: 1 } so the list scrolls within the applet box; #id_applet_my_games ul-centring + .scroll-list + #id_applet_notes h2 { writing-mode: vertical-rl ... } overrides removed (centring was an empty-state-only behaviour, scroll-list + vertical-rl redundant w. the new shared rule + the %applet-box > h2 rule); My Games items now left-aligned by default; empty-state row recovers the centred-italic-dim treatment via .applet-list-entry--empty { flex: 1; display: flex; align-items: center; justify-content: center; opacity: 0.6; font-style: italic } + .applet-list:has(> .applet-list-entry--empty) { display: flex; flex-direction: column } — so "No buds yet" / "No notes yet" / "No games yet" / "No scrolls yet" / "No posts yet" all centre in their applet aperture, reverting to the left-aligned stack the moment a real item lands; Most Recent Scroll's outer empty <p><small>No recent activity.</small></p> adopts the same .applet-list-entry .applet-list-entry--empty classes (section is already flex-column from existing rule) so it picks up the unified centred-italic-dim treatment
discoman pushed to main at discoman/python-tdd 2026-05-13 02:26:27 +00:00
6a7464ee4b post.html: gear-btn + #id_post_menu (NVM / DEL / BYE) mirror room.html's #id_room_menu — all Posts get the gear w. NVM (→ billboard:my_posts); user-Posts (kind=USER_POST / SHARE_INVITE) additionally surface DEL for the author (POST → billboard:delete_post → hard-deletes the Post; cascades Lines via FK + clears shared_with M2M) and BYE for invitees (POST → billboard:abandon_post → removes request.user from post.shared_with; owner + other invitees keep the thread); admin-Posts (kind=NOTE_UNLOCK) intentionally render gear w. NVM only since the system thread isn't user-owned (defence-in-depth: both delete_post + abandon_post no-op on NOTE_UNLOCK so a forged POST can't bypass the menu's branch); _post_gear.html partial gates DEL/BYE on viewer_is_owner (set by view_post since the buds sprint) + post.kind, then includes the shared apps/applets/_partials/_gear.html btn; styling rides the existing applets.scss page-level pattern — .post-page joins .billboard-page / .room-page / .dashboard-page / .wallet-page / .gameboard-page / .billscroll-page in the > .gear-btn { position: fixed; bottom: 4.2rem; right: 0.5rem } rule (and the landscape footer-sidebar centred variant), #id_post_menu joins the %applet-menu extension list + the page-level fixed-menu rule (bottom: 6.6rem; right: 1rem); 5 FTs in test_bill_post_gear.py (owner DEL flow, invitee BYE flow, 3 menu-shape assertions for owner/invitee/admin) + 11 ITs across DeletePostViewTest + AbandonPostViewTest (302 redirect target, side effect, GET-is-no-op, non-owner / non-invitee / NOTE_UNLOCK protection) — TDD
c64d7b9534 my_posts: owner-posts pane title @<handle>'s PostsPosts by Me — symmetrises w. the right pane's Posts by Others (both panes now read as point-of-view labels rather than one identity-stamped + one generic), and drops the @<handle> reveal from a screen the owner alone visits (handle is already in the navbar avatar tooltip); handle = owner.username or owner.email derivation goes w. it since nothing else in the view referenced it
Compare 2 commits »
discoman pushed to main at discoman/python-tdd 2026-05-13 00:44:18 +00:00
4b47dabaf0 woodpecker main.yaml: serialise test-FTs-room behind test-FTs-non-room — both FT steps share the workspace AND fall back to SQLite (only test-UTs-n-ITs sets DATABASE_URL to the postgres service), so running them concurrently collided on src/test_db.sqlite3: the second-to-start container hit a half-created DB and the runner's Type 'yes' to delete the existing test database prompt EOFed under non-interactive CI stdin (pipeline run #296); fix flips test-FTs-room.depends_on from test-two-browser-FTstest-FTs-non-room so the heavy room cluster strictly follows the non-room bucket; section comment rewritten from "Parallel FT split" → "FT split (sequential for now)" w. the run #296 EOFError documented + two re-parallelisation paths spelled out for later (per-step distinct sqlite paths via DATABASE_URL=sqlite:////tmp/test_db_<bucket>.sqlite3 OR per-step distinct postgres DBs); the two stale "parallel" mentions (collectstatic note in test-two-browser-FTs + inline comment in test-FTs-room) also updated; screendumps + build-and-push depends_on unchanged — Woodpecker resolves the transitive ordering fine
discoman pushed to main at discoman/python-tdd 2026-05-13 00:10:33 +00:00
a21e6aa251 requirements: align dev w. prod — add celery, psycopg2-binary, redis to requirements.dev.txt (missing from the CI dev image's pre-installed set, which means the CI fallback pip install -r requirements.dev.txt step would not satisfy these prod runtime deps if the image lagged); bump requests 2.31.0 → 2.32.5 in requirements.txt to align w. the dev pin (eliminates the version-drift wedge where CI's dev-only install would silently downgrade-or-upgrade vs prod's pin)
discoman pushed to main at discoman/python-tdd 2026-05-13 00:06:37 +00:00
f9c05a3eba functional_tests + CI: rename pass + structural consolidations + parallel test-FTs split — every FT file now starts with one of 6 prefixes (test_admin_* / test_bill_* / test_core_* / test_dash_* / test_game_room_* / test_trinket_*) plus the 4 page-roots test_billboard / test_dashboard / test_gameboard / test_jasmine, so the partition is unambiguous and stable for tooling (the previous mix of test_applet_*, test_room_*, test_component_*, ad-hoc names had no consistent grouping); session-side: merged test_gatekeeper_bud_btn.py into test_bud_btn.py (then user renamed to test_core_bud_btn.py) — both files drove the same #id_bud_btn UI in two contexts (post-share + gatekeeper invite) and shared the bud-btn.js skeleton, so consolidation was overdue; split test_component_cards_tarot.py into test_admin_tarot.py (just TarotAdminTest, sitting next to test_admin / test_admin_post_readonly) + 3 classes (TarotDeckTest / GameKitDeckSelectionTest / GameKitPageTest) appended to test_game_room_tray.py; updated stale test_bud_btn.py references in the test_core_bud_btn.py docstring + test_admin_post_readonly.py comment to point at the new filename; user-driven renames (22 files): test_applet_my_notes/posts → test_bill_my_*, test_applet_new_post[_line_validation] → test_bill_new_post[_line_validation], test_applet_my_sky → test_dash_my_sky, test_applet_palette → test_dash_palette, test_wallet → test_dash_wallet, test_login → test_core_login, test_navbar → test_core_navbar, test_sharing → test_core_sharing, test_layout_and_styling → test_core_styling, test_my_buds → test_bill_my_buds, test_bud_btn → test_core_bud_btn, test_deck_contribution → test_game_room_deck_contrib, test_game_invite → test_game_room_invite, test_room_gatekeeper → test_game_room_gatekeeper, test_room_role_select → test_game_room_select_role, test_room_sea_select → test_game_room_select_sea, test_room_sig_select → test_game_room_select_sig, test_room_sky_select → test_game_room_select_sky, test_room_tray → test_game_room_tray, test_component_tray_tooltip → test_game_room_tray_tooltip; the post_page.py / room_page.py helper modules from the May-12 sprint absorbed the cross-file FT imports that would otherwise have cascade-broken on these renames
discoman pushed to main at discoman/python-tdd 2026-05-12 23:37:00 +00:00
af1a90e76b woodpecker main.yaml: A+B combined CI dependency speedup — test-UTs-n-ITs swaps image from python:3.13-slim to gitea.earthmanrpg.me/discoman/python-tdd-ci:latest (same image as the two FT steps) so all 3 steps inherit the requirements.dev.txt deps Dockerfile.ci already pre-installs; all 3 steps switch pip install -r requirements.txtpip install -r requirements.dev.txt so the install collapses to ~5-10s of "already satisfied" verification per step (vs ~30-60s of unpinned PyPI resolver+download against requirements.txt); ~3-5 min saved per pipeline run; drift safety net preserved — pip still installs deltas if requirements.dev.txt is ahead of the image, so a stale image doesn't break CI, it just runs slower until the image is rebuilt + pushed
8240de6b45 functional_tests/room_page.py: extract shared FT helpers into a dedicated module so renaming a test_X.py file doesn't cascade-break sibling imports — _fill_room_via_orm (was in test_room_role_select, imported by test_room_tray + test_deck_contribution + test_game_invite + test_room_gatekeeper + test_room_sig_select), _assign_all_roles (was in test_room_sig_select, imported by test_room_tray + test_deck_contribution), and _equip_earthman_deck (duplicated verbatim in test_room_role_select + test_component_tray_tooltip — the test_component_tray_tooltip copy of _fill_room_via_orm was also a near-duplicate, missing only the gamers-return both call sites discarded anyway); SIG_SEAT_ORDER constant moves along since _assign_all_roles depends on it; mirrors the existing post_page.py pattern; underscored helper names kept so the "test infrastructure, not API" signal survives the relocation; dropped now-unused per-file imports (DeckVariant from test_room_role_select; Note/DeckVariant/TableSeat/TarotCard from test_room_sig_select; GateSlot from test_component_tray_tooltip); regression gate: GatekeeperTest (8 FTs) green via the new helper home; smoke-imports green across all 8 touched modules
Compare 2 commits »
discoman pushed to main at discoman/python-tdd 2026-05-12 22:01:42 +00:00
b97c4a0508 woodpecker main.yaml: workspace-shared pip cache via PIP_CACHE_DIR: .pip-cache on all 3 test steps (test-UTs-n-ITs / test-two-browser-FTs / test-FTs) — each step currently re-downloads the entire requirements.txt wheel set independently; Woodpecker mounts the workspace across steps in one run, so the wheels populated by step 1 are reused by steps 2-3, saving ~1-2 min of pip-install wall-clock per run (only download time — install still happens fresh per container); pyswiss.yaml untouched (separate pipeline, separate workspace, separate requirements); cache is per-run only — cross-run persistence would need a Woodpecker volume plugin
3932b17256 aperture architecture: lift the page-locking foundation (html/body/.container overflow:hidden + flex-column + min-height:0; .row flex-shrink:0) from 5 per-page SCSS files into _base.scss — was opt-in per page via body.page-billboard / page-dashboard / page-gameboard / page-sky / page-wallet etc., with 5 near-identical html:has(body.page-X) { overflow: hidden } + body.page-X { … } blocks duplicating the same rules; any page that forgot to set page_class in its view context (e.g. epic.tarot_deck — never set) rendered without the aperture, letting applet borders + titles clip past the fixed navbar/footer sidebars at narrower viewports; foundation now universal, page-specific overrides stay scoped — gameboard keeps .container { overflow: clip } (Firefox seat-tooltip scroll-anchoring quirk) + billboard/dashboard/gameboard keep .row { margin-bottom: -1rem } (h2-row tightening); page_class context vars + body class hooks preserved (FTs at test_bud_btn.py:370 / :379 still assert on them); regression gate: 60 layout-sensitive FTs (billboard, my_buds, bud_btn, applet_my_posts, dashboard, wallet, gameboard, layout_and_styling, jasmine) + 43 room FTs (gatekeeper_bud_btn, room_gatekeeper, room_sky_select, sharing) all green
17c4518944 my_buds: dismiss "No buds yet" empty-state row async on first-bud add — _appendBudEntry queried .bud-entry--empty but _applet-list-shell renders it w. the family-agnostic .applet-list-entry--empty class; the selector never matched, so first-bud appends landed alongside the empty row instead of replacing it; existing test_add_bud_via_bud_btn_appends_entry extended to also assert the empty row dismisses post-add (caught the bug — TDD)
Compare 3 commits »
discoman pushed to main at discoman/python-tdd 2026-05-12 20:42:42 +00:00
be919c7aff bud panels duplicate-add guard: server-side already_present flag + client-side error Brief w. FYI flash highlight on the existing entry — for each of the three #id_bud_btn panels (My Buds / post-share / gatekeeper-invite), the JSON response from add_bud / share_post / invite_gamer now carries {already_present, recipient_display, recipient_user_id}; bud-btn.js branches on already_present → calls new Brief.showDuplicateBanner({display_name, target_selector}) instead of the normal onSuccess append; banner title reads @<username> is already present, NVM dismisses, FYI dismisses AND eases in the .bud-duplicate-flash class (color: var(--terUser); text-shadow: 0 0 .5em var(--ninUser); transition: 600ms) onto the existing element (.bud-entry .bud-name / .post-recipient[data-user-id=…] / .gate-slot.filled[data-user-id=…]); gatekeeper "already present" = recipient is either GateSlot.FILLED + gamer OR has TableSeat OR has a pending RoomInvite (highlight target only set when seated — pending invites have no visible slot); .post-recipient chips + .gate-slot.filled cells gain data-user-id so the FYI selector can find them; my_buds.html now loads note.js via the {% block scripts %} pattern (Brief module is required by the duplicate banner path); bonus: latent test_jasmine.py bug fixed — "0 failures" in result.text matched "10 failures" / "20 failures" / etc, silently passing up to 99 failed specs; replaced w. re.search(r"(?<!\d)0 failures\b", …) (caught my new red specs, would've caught any prior Jasmine regression); 18 new ITs + 10 new Jasmine specs + 3 new FTs (one per panel) — TDD
264ed5968e bud panels DRY refactor: extract shared skeleton into bud-btn.js — the three #id_bud_btn partials (_bud_panel post-share, _bud_invite_panel gatekeeper, _bud_add_panel My Buds) duplicated ~70% of their JS (csrf/open/close, btn click, Escape, click-outside w. optional suggestions excl., Enter handler, OK POST + JSON routing); collapse into bindBudBtn({submitUrl, autocompleteUrl?, onSuccess(data)}) so each panel keeps only its markup + an onSuccess callback (post-share: _appendLine + _appendRecipientChip + Brief.showBanner; gatekeeper: Brief.showBanner only; my-buds: _appendBudEntry); autocomplete binding folded into bud-btn.js (drives bindBudAutocomplete when autocompleteUrl is passed) so callers stop repeating the bindBudAutocomplete(...) boilerplate; dead data-share-url/data-invite-url/data-add-url attrs dropped since bindBudBtn takes the URL directly; behavior-preserving — all 21 existing FTs (test_my_buds + test_bud_btn) + 49 ITs (test_buds + test_share_post + test_brief) green
7015ddd534 my_buds: strip bud-autocomplete bindings from _bud_add_panel.html — the autocomplete pool is request.user.buds (per search_buds view), so on the page where you ADD new buds the suggestions are the precise set you can't usefully re-add; post-share + gatekeeper-invite panels keep the binding (re-sharing w. an existing bud is a real flow); test_autocomplete_suggests_buds_by_username_prefix → test_no_autocomplete_suggestions_on_my_buds_page (asserts #id_bud_suggestions absent — deterministic, no debounce-window race); dead id_bud_suggestions click-outside guard + unused {% load static %} dropped — TDD
880408285a post.html line timestamps mirror scroll's relative_ts buckets: swap date:'g:i A' for the existing lyric_extras.relative_ts filter so same-day Lines render as 11:46 p.m., then collapse to weekday (Sat) past 24h, 07 Mar past a week, 07 Mar 2025 past a year — DRYs onto the single filter scroll already uses (no duplicated bucketing logic); same-day rendering shifts from 11:46 PM to 11:46 p.m. as a side effect of reusing the lowercase g:i a format relative_ts already standardised on — TDD
Compare 4 commits »
discoman pushed to main at discoman/python-tdd 2026-05-09 18:02:17 +00:00
df99cad984 mobile h2 + sky wheel landscape fit: per-letter flex spread (justify-content: space-between via base.html JS letter-splitter) replaces text-justify: inter-character — iOS Safari + Firefox silently fall back to inter-word for Latin text, leaving letters clustered at the slot start; flex layout works everywhere; viewport-fluid font clamp(1.3rem, 5vw, 2rem) portrait + clamp(1.2rem, 4.4vh, 2.75rem) landscape so glyphs scale w. viewport instead of a fixed-rem ceiling that overflowed the 45/55 slot at the rem-clamp floor; portrait <500px gets padding-inline 0.4em→0.6em on the word-spans so H-B don't run together at the cramped font-size; .sky-page post-save scroll-snap sections pinned to height: 100% (was: min-height: 100%) + .sky-svg max-height: 100% so the wheel fits exactly one aperture on landscape mobile (was: 480px max blew past ~350px aperture, leaving an intermediate scroll position)
discoman pushed to main at discoman/python-tdd 2026-05-09 05:14:52 +00:00
22d0507c3f post.html header prose branches on viewer-vs-owner: invitees see "shared with me, @viewer the {title}" + "created by @owner the {title}" instead of the owner-centric "just me / shared between" lines; owner view unchanged — TDD
419e022140 gatekeeper invite ports to #id_bud_btn slide-out: drop the inline #id_invite_email form, add bud-invite panel for room owner during gate phase, async POST to invite_gamer w. autocomplete + symmetric buds auto-add + slide-down Brief banner — TDD
4010e452a6 recentered copyright on landscape
72fefe2fc7 landscape footer rearrange: #id_bud_btn moves to top of right sidebar (upper-right corner of footer); ©2026 Dis Co. text becomes a single-line vertical strip at the very right edge of the viewport (mirror of portrait's "after the icons" position); bud-panel + bud-suggestions follow the bud-btn to the top w. transform-origin: right center
47871b5b4a align #id_kit_btn / #id_gear_btn / #id_bud_btn under the unified centre formula — drop the legacy right: 2.5rem ≥1800px override on kit-btn that left it outboard of gear-btn after the rem-fluid sidebar refactor
Compare 7 commits »
discoman pushed to main at discoman/python-tdd 2026-05-09 03:58:28 +00:00
c426ca69fa Note.grant_if_new admin prose: 'comes with the customary title of' → 'bestows the honorary title of'; 'additional benefits' → 'additional corporate benefits'
e0ace01670 post.html attribution palette: usernames render w. @-prefix (bare emails left as-is); .post-attribution spans wrap username+title combos for the --quaUser colour key — line author col, self/shared header lines, Note.grant_if_new prose
eb0369f0b7 buds Phase 2: top-3 username|email autocomplete on #id_recipient (post share + my_buds add); implicit symmetric auto-add on share_post (sharer ↔ recipient buds graph); recipient field accepts username OR email — TDD
11ff109d1e my_posts: titles → @{handle}'s Posts + Posts by Others (view-side string build); applet-list link colour --terUser w. hover/active shifting to --ninUser + --terUser glow halo
246e45e55d buds rename + applet-list shell — Buddies → Buds everywhere (model field, slug, URL, view, DOM, CSS); my_buds.html + my_posts.html share new _applet-list-shell.html partial — vertical-title applet-scroll card; my_posts hosts two side-by-side in landscape, stacked in portrait — TDD
Compare 6 commits »
discoman pushed to main at discoman/python-tdd 2026-05-09 02:04:32 +00:00
b3eb14140c admin Posts (NOTE_UNLOCK): readonly input + 'No response needed' placeholder + secUser focus glow + buddy btn suppressed + view POST 403 + Line.admin_solicited listener nukes errant writes; share Lines: drop ts suffix, author = sharer (adman fallback for anon legacy), silent no-op on re-share — TDD
6f76f6c176 post aperture refactor (May-8b): Post.title field; Line.author PROTECT FK + created_at; Note.grant_if_new admin-vs-Look! format dispatch w. note-ref anchor; bottom-anchored aperture w. shared-between header + per-Line user/timestamp; dotted-? Brief square; reserved adman seed — TDD
ba5f6556c0 buddy btn sprint: banner-anchor + window.Brief fix lands the last red FT — 16/16 buddy + 12 share/jasmine/my_notes + 818 IT regression — TDD
e465b6a3b3 buddy btn sprint scaffolding: TDD spec + partial template + SCSS + page_class — 15/16 FTs green, 1 captured-red for post-compaction handoff
Compare 4 commits »
discoman pushed to main at discoman/python-tdd 2026-05-08 22:27:16 +00:00
7b2780e642 test_applet_new_post: bump current-url regex /dashboard/post/ → /billboard/post/
14bab444ff brief sprint C3.b+c+d+e: share-post Line+Brief async, magic-link / invalid-link banners use Brief styling, .alert-* retired — TDD
fa53bf561a brief sprint C3.a: Note unlock spawns Line + Brief on the user's per-category Post; banner JS consumes the new brief payload (FYI → post detail, square → my-notes) — TDD
7f9ff36d1d brief sprint C2: introduce billboard.Brief notification model + view_post marks-read on GET — TDD
Compare 4 commits »
discoman pushed to main at discoman/python-tdd 2026-05-08 21:29:52 +00:00
d192b1522d brief sprint C1: relocate Post + Line from dashboard → billboard (no behavior change) — TDD
discoman pushed to main at discoman/python-tdd 2026-05-08 20:18:41 +00:00
f659a64b91 some tweaks to portrait media query .btn-primary responsive sizing
a319318740 sky/sea modal titles: PICK SKY/SEA → SKY/SEA SELECT (titles only — table-hex .btn-primary instances stay PICK SKY/SEA where SELECT wouldn't fit)
d58fd1db15 small changes to .sky-field styling
846f9ff461 PICK SKY DEL: server purge of seat Character + race guards stop the btn from re-injecting; readonly opacity bump (0.6 → 0.85) — TDD
Compare 4 commits »
discoman pushed to main at discoman/python-tdd 2026-05-08 19:28:32 +00:00
1111df8465 sky form TZ: render-readonly + drop #id_nf_tz_hint; placeholder absorbs the auto-detected hint copy — TDD
8a8d1536b1 PICK SKY DEL btn: JS-inject after wheel paints so a blank modal carries no DEL action — TDD
301b4e8201 applet-box: hide inner-applet scrollbars so they match the page-aperture treatment
097a5dd437 my-sky applet DEL btn: shift left by half the applet's padding asymmetry so it re-aligns w. the SVG center
e9bceaab62 sky wheel: ubiquitous DEL btn — applet & PICK SKY parity w. Dashsky; PICK SKY clears client-only state (no User-model touch) — TDD
Compare 14 commits »
discoman pushed to main at discoman/python-tdd 2026-05-05 05:59:04 +00:00
cc2a3f3526 rename natus → sky across the codebase — natal chart abstraction is now sky throughout, since chart inputs aren't birthday-gated
19b7828ea9 ignore .vscode/ in git & docker contexts; workspace tasks/settings are local-only (Windows paths + per-machine venv layout)
Compare 2 commits »
discoman pushed to main at discoman/python-tdd 2026-05-04 06:25:15 +00:00
a97cd8dcff test_clicking_pick_sea_btn_opens_sea_overlay: poll click+sea-open assertion to absorb DOM-vs-script race on slow CI — TDD
discoman pushed to main at discoman/python-tdd 2026-05-04 05:58:49 +00:00
c9563308d8 SAVE SKY provenance + sky→hex (not sky→sea) transition — TDD
5413e63585 billboard Most Recent Scroll: fix SQLite NULL drop on SIG_READY exclude; pronouns flow FT; Blades middle reversal Nervous → Fickle — TDD
29493c4f74 pronouns: per-user pronouns ideology + Pronouns applet on Game Kit; provenance prose uses actor.pronouns at render time — TDD
599d40decd auth urls: mount apps.lyric.urls under /dashboard/ to mirror gameboard/epic & billboard/drama convention
2dc68c41a7 billboard applets: drop billboard- prefix from partials & ids; Most Recent → Most Recent Scroll; room_scroll → scroll — TDD
Compare 5 commits »
discoman pushed to main at discoman/python-tdd 2026-05-04 02:28:55 +00:00
b1a11504f5 game kit + role icons + tarot fan: in-use mini-portal label, FLIP cue polarity reset, role icon redraws
f78177778f SIG SELECT exit: 2s hang after tray closes; suppress waiting msg if PICK SKY already up — TDD
480cb4aed6 tray: Tray.placeSig analogue of placeCard for SIG SELECT exit; rename arc-in → fade-in — TDD
9b93b9d31b tray tooltips: tilt persists while portal is open; PRV|NXT pinned to corners — TDD
b29bcf5c38 tray sig-card tooltip: portal w. PRV|NXT pager — TDD
Compare 7 commits »