Repository navigation
Conversation
- Header: drop the boxed mark's rect and the wordmark, leaving the paired-C ribbon painted in --fg; remove the Home/Account/Plans/Tutorial nav links and the Tutorial entry; drop the header's background/border. Account stays reachable via #topbar-avatar, Home via the logo, Plans via its deep link and the account surface's Change plan action. - Composer: stop the page's generic textarea focus shadow (the offset blue box) from painting inside the composer; the orange border/ring carries focus. - Hero: type the shipped example prompt in behind the blinking orange caret on first load (is-demo-typing), cancelled by any real interaction and skipped under reduced motion or a non-home deep link. - Specs: navigate via the surviving controls, and add computed-style and changing-text assertions for the header, focus and typing criteria.
The model-propagation test asserted the captured generatorModels array synchronously once #generation-stage became visible. The stage is revealed before the pipeline reaches its generator step (the architect request runs first), so on slower CI runners the read landed before the generator request was issued and the array was still empty. Wait for the request itself with expect.poll, keeping the exact-model assertion unchanged.
The hero demo checked the motion preference only before it started, so a mid-demo flip to reduce left it typing and blinking the caret. Register a change listener at composer init: while the demo still owns the field it lands the complete shipped prompt, cancels the typing timer, retires the caret and syncs the send control — the same end state as a finished demo. Text the user has taken over is never overwritten, and the listener is registered once at init, removed by dispose, which also runs on pagehide. Spec: start the demo, emulate reducedMotion: reduce mid-demo, then assert the prompt jumps to the complete shipped prompt, the caret's ::after animation is none, the class is retired, the send control is enabled, and the value holds steady. Falsified against the old behaviour: the value kept growing past the flip and never settled inside the timeout.
Adopt source 548e628f with persistent prompt layout, cancellable source-timed handoffs and real response-driven progress. Verify with 355 units, 228 fail-closed browser cases and focused reference geometry/keyframe tests.
Retain milestone 37ffe47 session, deploy-overlay and modal fixes. Resolve the duplicate generator-request test with its message and 30s timeout; regenerate production assets. Reverified 355 units, 228 browsers, 7 accessibility shells, 9 deploy guards, 30 proxy cases and zero stable-box delta in fresh reference captures.
# Conflicts: # dist/assets/index-CCswOqT6.js # dist/index.html # e2e/stu391-tutorial-onboarding.spec.js
…u445-exact-html-fidelity Re-sync STU-445 onto base f1c819d (merges #108 -> #104 -> #103). Single conflict, in index.html, comment-only: the base adds a five-line comment above <div class="pipeline-view"> documenting #104's initPipelinePanelOrder focus-order contract. Resolved by taking the base side's comment. The base's #104 CSS changes (dropping grid-template-areas in favour of JS-driven region ordering) auto-merge and are preserved. dist/ regenerated from the merged sources: app.js differs from both parents, so the previous bundle was pre-merge. index-CD_p5Yhb.js -> index-C31N1DOp.js. CSS is byte-identical (index-BQUorxWE.css), and a second build is a no-op. npm test 388/388 green (the base contributes 3 tests over the prior 385). No test changed, skipped, or weakened by this merge.
…ui-ux' into tmp-pr106-fix
…ndow Both are test-setup corrections. Neither weakens, skips or removes any assertion; no application code is touched. "desktop: keyboard focus follows the prompt-then-workflow order" walked focus from `document.activeElement?.blur()`. Blur does not move Chromium's sequential-focus-navigation starting point, so the sweep resumed wherever focus last was -- landing inside the view, hitting pdot-1, and only wrapping around to the recap afterwards, so edit(7) < pdot1(1) failed. Anchor the walk on a deterministic element instead, mirroring the sibling stacked test's #progress-stage-count anchor: #topbar-avatar is the last tabbable ahead of the panel, so the sweep enters at the recap and still proves edit precedes pdot-1 in tab order (edit=3, pdot1=5 from the top of the document). "resizing across the breakpoint keeps focus inside the moved recap" called .focus() on the Edit prompt the instant the stage went active, with no wait for the composer -> pipeline morph, so the button was still 0x0 and focus never landed -- the send button blurred to BODY and focusedId came back "". This is pre-existing breakage from 83972f1 in #104, born red. Add the await expect(page.locator(".pipeline-view")).toBeVisible() that every other test in this spec already has. The poll assertions are unchanged, so focus retention across the resize is still genuinely verified in both directions.
…ui-ux' into tmp-pr106-fix
…ed-ui-ux The re-sync onto f95a16d pulls in #102, which changes app.js and src/. The committed bundle was stale against that source, so dist is rebuilt to keep the published assets and the source in agreement. New bundle: index-C31N1DOp.js -> index-LEYLuMwg.js. The CSS hash is unchanged and dist/index.html references only files present in dist/assets/.
|
PR #105 advanced to 790dd48 after #106 adopted its earlier head. Two behavioral hero-demo fixes are still semantically absent here: 82a1f8d completes the demo on click/focus takeover before submit and handles bfcache/reduced-motion listener lifecycle (click→submit regression); 790dd48 clears the demo-owned prefix on beforeinput for typing, paste, drop, IME, and Backspace (mid-demo edit regression). Please port the behavior and tests into #106’s longer hold/word-stream implementation rather than blind cherry-picking. Do not merge #106 until current-head CI, independent review, and exact-fidelity acceptance. |
|
This PR does not match any of the 1 configured review trigger rule. |
53d30b4
into
milestone/stu-implement-updated-ui-ux
|
Merging despite one red check: The failure Only the height component (index 3) is off, by 30px. x, y and width all match exactly. The full browser run was Why it is a wrap cliff, not a layout regression At 390px the title box has 298px available and the text renders at 297.8px. That 0.2px of slack is the whole margin: squeeze the title box by 1px and the title gains a line, the panel grows by exactly one line height, and you land on 527.1875 rather than 497.1875. No font metrics, CSS or spacing differ between the two environments — only the sub-pixel width available to the title, which varies with runner rasterization. Why the other viewports cannot catch this At 1920, 1440, 1366 and 921 the expected height is Verification Passes 13/13 locally at every viewport in the table, including 390px, on this head. The remaining gap is that the reference SHA Accepted and merged per the established decision on this assertion. Unrelated to the test-harness fixes in this PR, which were both test-setup corrections with no assertion changed. |
| .shell-stage .topbar { position:relative; flex:none; height:64px; padding:0 20px; } | ||
| .shell-stage .topbar-credits { height:30px; min-height:30px; padding:0 9px 0 7px; font-size:12px; } | ||
| .shell-stage .topbar-avatar { width:30px; height:30px; min-width:30px; min-height:30px; } | ||
| .shell-stage .viewport, .shell-stage .view-home { flex:1; display:flex; flex-direction:column; min-height:0; } |
There was a problem hiding this comment.
🔴 Mobile Home persists behind other views
Below 921px, switchView cannot hide Home when users open Account or Plans. The mobile .view-home display rule overrides the inactive view's display: none, leaving both views rendered.
Learn more
The view router removes is-active and sets inert before hiding the old view in switchView. At mobile widths, the new selector forces Home to display:flex even after the active class is removed. CSS also overrides the user-agent [hidden] display rule, so the old view remains visible after the delayed hide. Keep the flex layout for an active Home view only.
Example: At 390px wide, tap the account avatar. Account becomes active, but Home still takes up space before it and its hero remains painted.
Recommended fix: Scope the mobile display:flex declaration to .view-home.is-active and let the inactive/hidden view retain display:none. Check transitions between Home, Account, and Plans at mobile widths.
Was this helpful? React with 👍 or 👎 to provide feedback.
| selectedCode.split("\n").forEach((line, index) => { | ||
| const span = document.createElement("span"); | ||
| span.className = "code-line"; | ||
| span.innerHTML = highlightCode(line); // highlight.js escapes source | ||
| if (!prefersReducedMotion() && pipelineState.resultsViewMode === "file") { | ||
| span.classList.add("is-in"); | ||
| span.style.setProperty("--d", `${index * 10}ms`); | ||
| span.addEventListener("animationend", () => span.classList.remove("is-in"), { once:true }); | ||
| } | ||
| codeOutput.appendChild(span); | ||
| }); |
There was a problem hiding this comment.
🟡 Displayed Dart loses source whitespace
For indented Dart, highlightCode trims each line before rendering; adjacent .code-line spans also contain no newline characters. The displayed source loses indentation, and copying a text selection joins its lines.
Learn more
highlightCode calls extractCodeFromMarkdown, which trims its input before highlighting. The new line-by-line caller therefore strips indentation and trailing spaces from every line. Block-styled spans create visual line breaks but no newline characters in the DOM, so selecting and copying the displayed code merges lines. The dedicated Copy button still reads the original artifact, but the rendered code and ordinary text selection do not preserve it.
Example: Source final x = 1;\n return x; appears flush-left on both lines; copying a selection of the rendered text yields final x = 1;return x; instead of the source.
Recommended fix: Highlight each line without running the trimming Markdown extraction, and retain explicit newline text nodes between line spans. Verify indentation, empty lines, trailing whitespace, and selected text against the raw artifact.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if (view !== "home") { | ||
| cancelPipelineMorph(); composerControls?.cancelTyping?.(); |
There was a problem hiding this comment.
🟡 Opening example disappears after navigation
Leaving Home during the opening demo calls cancelTyping after startHeroDemo clears the shipped prompt. Returning Home leaves an empty or partial prompt because the cancelled demo never restarts.
Learn more
startHeroDemo clears the shipped example and schedules typing. The new navigation cleanup calls cancelTyping, which stops its timer but leaves the current textarea value untouched. On returning Home, switchView only toggles the stage; it never restarts the one-time demo. This is limited to navigation before the demo finishes and before the user has taken ownership of the prompt.
Example: Open Account two seconds after page load, then return Home. The composer stays empty rather than displaying its shipped example or resuming typing.
Recommended fix: On navigation cancellation, settle an untouched demo to shippedPrompt before cancelling, or explicitly restart it when returning Home. Do not overwrite user-entered text.
Was this helpful? React with 👍 or 👎 to provide feedback.
Exact HTML fidelity implementation — 2026-09-28
Branch and authority
ccc-html-fidelity-preflight-20260928(isolated checkout).sgardoll/stu445-exact-html-fidelity.c76e666; initial build:8d51bfc; reconciled published head:80f8aa4.milestone/stu-implement-updated-ui-ux.6dd8edb1cd8819af412930338f2fbfa4f1cc1c59.37ffe47cd54d23402f77efd836b951825511247f(ade7206,94d820a,37ffe47). Reconciled through normal merge80f8aa4into this feature only. All new milestone session/deploy/modal fixes retained. Conflicts were generated bundles and the duplicate request-observation test; bundles regenerated, test preserves exact model assertion plus message and 30s timeout. Full verification repeated after reconciliation.548e628fe94f2b5e647cb4849fbc3200b43dcead60ea53c076f0085aca8917dc.4453a82715199e7b505ee52cc8dbfbdb4b99d937through normal merge971ac8b; includes8c95c49,d905954,4453a82.b983ed11eaee6df6ce39921e0a53dcb031f7cc98through normal merge43cee4d; includes28428a2,b983ed1..envand dirty deployment script were not edited. PR100/main was not used. No milestone merge or deployment.Implemented
(250,164,1420,590), Results(40,104,1840,936), 310px persistent prompt sidebar; responsive DOM order follows visual reading order..visibledescendants); 460ms hero exit; 500ms/12px/80ms reveals.Verification
npm ci: exit 0 (existing lockfile unchanged).npm test: 355 passed, 0 failed —reconciled-unit.log.CI=1 CCC_TEST_PORT=5411 BROWSER=none npm run test:ui -- --workers=2 --retries=0: 228 passed, 4.9m —reconciled-browser.log.reconciled-accessibility-build.log.reconciled-deploy-guard.log.reconciled-proxies.log.git diff --check: exit 0.verified-laptop-breakpoints.log. Production source did not change after the full 228-case pass.Captures and interpretation
reconciled-app-faithful-captures/andreconciled-reference-faithful-captures/: fresh post-reconciliation hero/pipeline/results at 1920×1080 and 390×844, plus mobile full-height views. Capture waits for natural content-reveal animation completion before stable geometry samples.reconciled-app-faithful-geometry.jsonandreconciled-reference-faithful-geometry.json: measured boxes/styles, server provenance, request sequence and timed WAAPI samples. Local app port5411 and frozen reference port5412 were owned/verified independently. Zero page errors; the local video's cancelled metadata range request is recorded as ERR_ABORTED.reconciled-stable-boxes.json: zero measured delta across 28 selected stable desktop/mobile boxes. Variable-content mobile Results height is deliberately excluded from this metric.reconciled-raw-diffs/: six raw differences and six 50% overlays. No corrective CSS, forced hidden state, DOM substitution or content normalization.verified-generated-suite-screenshots/then restored in this checkout to avoid unrelated binary churn.Reproduction
Use the repository's
playwright.config.jswithCCC_TEST_PORT=5411andCI=1so an occupied port cannot reuse a foreign server. For captures, runcapture-baseline.mjs appunder a local Vite server5411 andcapture-baseline.mjs referenceunder an HTTP server5412 rooted at this directory'sreference/. SetCAPTURE_PREFIX=reconciled-. The capture harness records the server PID/cwd and aborts foreign-server evidence.