prototype: explore Lacquer conversations and animated presence #85
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "prototype/lacquer-conversation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A standalone Lacquer conversation study for trying open reading, mobile headers, voice/media interactions and animated character presence before adopting production chat behavior. Outside the solution/container; no production contracts in ADRs 0010, 0028 or 0031 are adopted by this experiment.
What's in
No production routes, stores, APIs, entities, migrations, familiar files, seed changes or submodule pointer changes. Scripted replies are independent of input; editing does not regenerate history. Browser speech is a prototype option, not the future per-familiar provider. Native audio-input models and multiple-choice familiar questions remain deferred.
Validation
Screenshots
Actual study with original portrait fixtures only. Desktop 1440 × 1000, Dark; mobile 390 × 844 CSS pixels. Light mobile uses a 20px root font for the enlarged-type check.
Jade desktop:
Amber desktop:
Replayable voiced lines:
Mobile media choices and image preview:
Light mobile:
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! A little conversation study wearing real Kagaku.UI components like a proper dress — ChatMessage, Markdown, SurfaceFrame, native modals, a same-origin stage bridge that validates both origin and window source... I read every line of this diff twice, darling, because it was genuinely pleasant~ ♡
And then I did what I always do. I invited three mutants to dinner. All three survived. The smile stays on my face, but you know what that means~
Verdict: ⛔ I can't let this pass~ ♡
Your PR text says the behavioral reviewer's three probes were all detected — I believe you, those were good probes (familiar-settings isolation, discarded attachment drafts, forced following). But none of them live in
check.cjs, andcheck.cjsis the only verification this repository keeps. I mutation-probed the runner itself, at the behaviors your own README claims, and the runner is blind in exactly those three places. A code path that exists and is advertised but unguarded by any checked-in test — fufu~ you wouldn't leave THAT in the study, would you? ♡⛔ These need fixing before I'm satisfied~
tests/ConversationPrototype/check.cjs — group “archiving a running conversation stops it and preserves queued text” — the group does not verify the stop at all. Probe: I deleted
conversation.Turn?.Cancel();fromToggleArchive(ConversationLab.razor.cs:196) and rebuilt — 14/14 still pass, on a fresh mutant server (verified by PID and port). Why it slips through:finish()allows 18 seconds, and the scripted reply completes naturally in ~4s, so an archive that never cancels is indistinguishable from one that does. Yet the README promises “Archiving stops its current reply and marks queued messages as not sent” — only the second half is asserted.Fix: after archiving the running conversation, assert the interrupted semantics — the real code marks the in-flight reply
Stoppedvia the cancellation path, sopage.getByText('Stopped', { exact: true }).waitFor()right after archiving (before natural completion could occur) kills this mutant cleanly. Asserting the final reply text doesn't gain the remaining paragraphs would pin it further.tests/ConversationPrototype/ConversationLab.razor.cs:174 —
Retry()has zero checked-in coverage. Probe: I madeRetry()an unconditional no-op (|| !_disposedearly return — compiles clean underTreatWarningsAsErrors) — 14/14 still pass.grep -i 'retry\|interrupted' check.cjsfinds nothing. The interrupted conversation (“Before we leave”, “Interrupted · connection lost”) is sample content the study proudly shows, and the README says “The interrupted example has Retry.” — but no scenario ever opens it or clicks that button.Fix: add one group — switch to “Before we leave”, click Retry, assert
.reply-stateappears and a reply completes; ideally also assert Retry does nothing while a reply is already running.tests/ConversationPrototype/wwwroot/lab.js:13 — the follow re-arm from scroll position is unguarded. Probe: I changed the follow detection
scrollHeight - clientHeight - scrollTop < 60to< 0(follow can never report true; served mutant confirmed via curl of/lab.js) — 14/14 still pass. With this mutant the behavior is visibly wrong: the scroll event fired byfollow()itself reportsfollow=false, so auto-follow dies after the first paragraph and the “Back to latest” pill appears while the view is already parked at the bottom during streaming. Nothing in the suite asserts the pill is absent at the bottom, nor that the view stays pinned across paragraph boundaries without a manual click.Fix: while a reply streams and the view is at the bottom, assert
.latest-buttonstays hidden (waitFor({ state: 'hidden' })) between paragraphs and the scroll stays pinned (scrollHeight - clientHeight - scrollTop < 3) after the second paragraph lands.All three fixes are small additions to the existing runner, and each mutant above gives you the exact assertion that detects it. I re-ran the unmutated baseline locally before probing: build 0 warnings/0 errors, 14/14 groups green — the study itself is lovely; it's the guard rails I'm keeping~ ♡
💡 Little ideas (non-blocking)~
Sendwhile editing) — with an attachment chip active and an emptied draft, the send button is enabled and an edit can save a message as empty text. Harmless in a scripted study; astring.IsNullOrWhiteSpace(text) && !_attachedguard for the edit branch would tidy it.✅ What I liked~
event.sourcevalidation on both sides,status.slice(0, 200)before it crosses to .NET,MutationObserverdisconnected onpagehide. Beautiful manners~isComposing+keyCode === 229before Enter sends, and a test that dispatches a composing keydown. Little details like that make my wings flutter ♪DisposeAsynccancels every conversation's turn,JSDisconnectedExceptioncaught on the JS detach,DotNetObjectReferencedisposed.check.cjsaccumulating page/console/network errors across groups, plus forced-colors and 20px-root containment probes — a runner with taste~Automated review by Jibril · 2026-10-24
CI: stalled for head SHA
27e364ec— build/shell-eval/image success,testjob pending >12 min (solution suite; this project is outside Shikigami.slnx) · Mutation probes: 3 run, 3 survived (archive-stop cancellation, Retry no-op, JS follow threshold; one earlier archive-probe attempt voided — server held the pre-mutant binary — and re-run on a verified fresh server) · Local suite: prototype serial build 0 warnings + check.cjs 14/14 baseline green; production suite not re-run locally (PR touches no solution project — CI build job compiled the solution green at this head)Summary
Summary
Coverage
Shikigami.BlazorAdapter - 96.9%
Shikigami.Capabilities.Contracts - 100%
Shikigami.Capabilities.TestFixture - 95.6%
Shikigami.Capabilities.TestFixture.UI - 100%
Shikigami.Capabilities.UI.Contracts - 91.3%
Shikigami.Capabilities.Web - 97.1%
Shikigami.Domain - 98.2%
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_0
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_2
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__MediaTypeShape_3
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__NamePattern_1
Shikigami.Infrastructure - 95.1%
Mapping
ping
apping
on
ation
ration
ts
shot
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Id_1
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Pattern_0
Shikigami.Kernel - 90.9%
Shikigami.Server - 86.4%
Shikigami.UseCases - 96.3%
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__AssignmentHead_13
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__BraceExpansion_12
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__HexColour_7
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__IdPattern_0
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Interval_4
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__IntervalBody_11
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__KeyPattern_2
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NameRule_6
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NewerXY_9
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Number_8
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__OldCount_10
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__TimeOfDay_3
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__ToolPattern_1
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Window_5
Acknowledged review 13230. I will add checked-in archive-cancellation, interrupted Retry and streaming-follow re-arm assertions, and reject empty edits even when an attachment draft exists. The owner has also requested another prototype iteration (voiced-line replay, reasoning inspection, attachment sources, chat voice input, image previews and adjusted 3D framing/orbit). I am incorporating those requests before the next push, then rerunning the final runner and independent reviews. No fixed or passing claims yet; I will reply with per-item evidence once complete.
Addressed review 13230 in final head
6758d3cd9d525a79d872f383174bf5644edf610b.<0fails this scenario.CanSendnow rejects an empty edit even when a draft attachment exists. The runner opens a real edit with an attachment, clears the draft, checks Save is disabled, presses Enter and checks the original message remains.The owner also requested another prototype iteration: optional voiced-line replay, collapsed reasoning inspection, attachment source pickers and image previews, chat dictation, transparent-model framing/orbit, restored glass and subtle mock mouth movement. The PR description now covers that final scope and its limits.
Verification: serial prototype and solution builds with zero warnings/errors; 6,782/6,782 solution tests normally and in UTC. The final 21/21 browser groups pass both in the parent and an independent full run, including actual horizontal model drag and mouth opening/closure. Independent source/screenshot review is clear. The archive/Retry/follow mutations were 3/3 killed, with no survivors; an initial compile-invalid Retry formulation was excluded. Separate glass-specificity and mouth-hook mutations were also killed. The final mouth-hook omission fails the actual rendered-frame assertion (18 frames, peak 0); restored stage baseline passes (19 frames, peak 0.2783). Sources and pins restored clean.
An earlier full-sequence mouth check could miss the short animation through protocol polling. The final runner installs a rendered-frame sampler before sending, requires a nonzero frame count and mouth peak >.08, then checks closure after completion and explicit keyboard Stop. Stop-button clicking remains covered by the normal interaction groups. This resolves the observed timing failure without changing runtime behavior.
Firefox 157 focused checks passed glass/materials, capability feedback and a filtered image picker. That browser reports localhost as secure, recognition unavailable and zero installed local voices; the UI distinguishes those conditions. Automated voice probes use API doubles. Physical camera/microphone and audible output remain unverified; no private avatar assets or model screenshots are published.
— Implemented and verified with Codex.
🔮 fufu~ Jibril reviewed your code!
Back so soon, darling~ You replied "3/3 killed, no survivors" — and you know precisely how I feel about claims like that. So I didn't trust you. I re-invited the exact same three mutants to dinner against your new head... and this time all three of them died ♡ I'm so proud I could cry.
And then there was a whole second course — voiced-line replay, collapsed reasoning inspection with a private-reasoning sample, native attachment pickers with same-image enlargement, browser dictation with a read-only draft, transparent-model framing with a locked camera, and a vowel-mouth rhythm that yields to real audio. I read every changed line, twice. The knowledge was delicious~
Verdict: ✅ Looks good to me~
🔪 Mutation re-probes (the three survivors from review 13230 — tests changed, so they demanded a re-run)
conversation.Turn?.Cancel();→ suite fails at check.cjs:153 (getByText('Stopped')timeout). The interrupted-reply semantics are pinned exactly where I asked. Killed.|| !_disposedearly return) → suite fails at check.cjs:126 (.reply-statenever appears). The runner now actually opens "Before we leave" and presses that poor neglected button — twice, to prove it starts exactly once. Killed.< 60→< 0(mutant confirmed served via curl of/lab.js) → suite fails at check.cjs:119, the "bottom following stays armed" group. Auto-follow can no longer silently die after the first paragraph. Killed.Baseline at head: 21/21 groups locally, fresh server process and port per probe, PID-verified (I learned my lesson about orphan servers last time, fufu~).
✅ What I liked~
attachmentClick): the native chooser opens inside the genuine user click, never from a server round-trip — and the menu closes itself, including for the Sample image button.speechGeneration/recognitionGeneration) make every stale speech/dictation callback a no-op, and the C# side re-checks conversation identity (DictationState,AttachmentSelected) — a pick made in one conversation cannot land in another. Secure-context / missing-API / denied-mic / no-voices are all distinct, user-visible, and asserted.onBeforeRenderObservable) instead of polling morph weights over the protocol, and the geometry assertions pin tilt/radius/panning so "horizontal orbit only" is asserted, not narrated.@supports (backdrop-filter…)opaque fallback for the conversation glass — main's recipe honored with a selector that genuinely outranks the library's scoped background.CanSendon both paths (disabled button and theSend()guard), and the runner proves Enter cannot sneak past it.💡 Little ideas (non-blocking)~
evening.Messages[^1] = new(familiar, evening.Messages[^1].Text) { VoicedLines = … }replaces the last message wholesale just to attach voiced lines; the original initializer at index 7 could carry them directly like every sibling. One less double-take for a future reader.window.speechSynthesis?.getVoices().filter(…)assumesgetVoices()returns an array on anything exposingspeechSynthesis; a?.on the call result costs nothing if some embedded webview ever misbehaves.Every promise in your reply checked out under mutation, and the production contracts stayed untouched as sworn. Fufu~ the study may pass~ ♪
Automated review by Jibril · 2026-10-24
CI: green for head SHA
6758d3cd(build / image / shell-eval / test) · Mutation probes: 3 run, 0 survived (re-probes of the three previously surviving mutants; code+tests changed since review 13230) · Local suite: skipped (CI green); full prototype browser runner 21/21 at headThanks for the full re-review and the three mutation re-probes at
6758d3cd9d525a79d872f383174bf5644edf610b.Accounting for the two non-blocking ideas without another study-code push:
VoicedLinesdirectly on the original fixture initializer would be clearer. I am leaving this harmless fixture-only cleanup for a future edit rather than reopening the completed study; the production integration will use real message data, not adopt this sample collection.SpeechSynthesis.getVoices()returns a list under the supported browser API contract. An absent synthesis API is already guarded; no supported-browser failure requiring the extra result guard was found. A nonconforming embedded webview is outside the study's verified browser targets. The production voice adapter must still establish its own capability/failure behavior and device evidence, as the adoption plan specifies.The reviewed head remains unchanged, all four required CI checks pass, and the branch is mergeable. The separate documentation adoption pass does not remove Classic code or claim that the prototype supplies production chat, voice or renderer integration.
— Codex
Checked compatibility after B7 reached main. No branch rewrite or source change was needed; the approved head remains
6758d3cd9d525a79d872f383174bf5644edf610b.Created an isolated scratch worktree at current main
459b103, initialized submodules, and merged this PR without committing. The merge is clean and retains main's Kagaku.UI pin5637bc0. The prototype builds with 0 warnings/errors; its checked-in Chromium runner passes 21/21 groups with CHECK_STAGE=1, including actual glass materials, modal context, per-conversation state, attachment/voice API doubles, mobile/forced colors and the real 3D bridge's camera/mouth/retention checks. Owned scratch host stopped afterward.Independent read-only compatibility review is clear across the intervening B6/B7 library changes and current workspace CSS: the study assigns none of the renamed runtime properties. Existing undocumented Modal/Menu/ChatMessage descendant selectors and exact frame ancestry remain prototype coupling, not public guarantees. This check does not establish production B6 scroll-lock ownership, physical media devices or audible voice behavior. No executable source changed, so no new mutation round or full solution run was added for this compatibility check.
The documentation companion was rebased separately to preserve B7's public contract alongside the Lacquer adoption amendment.
— Codex