Skip to content

feat(demo): start-chat confirmation page, question after # (founder ruling 2026-10-03) - #186

Merged
trakhimenok merged 2 commits into
mainfrom
apps-start-chat
Oct 3, 2026
Merged

trakhimenok merged 2 commits into
mainfrom
apps-start-chat

Conversation

@trakhimenok

Copy link
Copy Markdown
Contributor

What

Founder ruling 2026-10-03 (backstage docs/design/demo-as-github-project.md, "Founder ruling 2026-10-03", 3.1, 6.5): the demo hand-off goes to a confirmation page …/start-chat with the question after #. The demo flag stays off; nothing here turns the demo on. Landing deploys to the live app, so please review before landing.

All paths below are under apps/datatug-app/.

Required behaviour, where it is, and the test

# Behaviour Code Tests
1 New addresses …/start-chat#msg=&lang= and …/tree/<ref>[/<dir>]/-/start-chat#…; q is an alias of msg; URLSearchParams semantics src/app/demo-handoff-path.ts:36-139 (target start-chat, folder support, startChatSegmentsOf); fragment parsing src/app/demo-handoff-capture.ts:92-145, src/index.html:62-80 demo-handoff-path.spec.ts (targets, router agreement), demo-handoff-capture.spec.ts "the start-chat address: the question after #", "capture of the start-chat address"
2 Inline script (ES5) reads msg/q/lang from the fragment and the query, stashes them as today, replaceStates to the same path with the fragment and those query keys removed (other keys kept); old addresses unchanged in effect; reuses #183's // and root-group normalisation src/index.html:36-100 script specs in demo-handoff-capture.spec.ts ("acts on exactly the paths isHandoffPath accepts" extended to the fragment; "agrees with the TypeScript on every spelling")
3 The page: the existing holding page and strings; question echoed only for the trusted project (isTrustedHandoff), neutral wording otherwise, same two actions; a reload shows the question from the tab's stash; seam for "Start" src/app/demo-holding-page.component.ts (readView, TODO(G-A4b) at :65), src/app/demo-handoff-asked.ts:183 (handoffDecision: start-chat is always the page), src/app/demo-handoff-capture.ts:60-85 (trust: a folder is never trusted) demo-holding-page.component.spec.ts "…on the start-chat address", demo-handoff-asked.spec.ts "the decision for an address", datatug-app-routes.spec.ts "start-chat"
4 /chat never reads a question the chat route is not the page any more; handoffDecision returns none for …/chat without a stashed question, and the page code reads no question from it datatug-app-routes.spec.ts, e2e "the project chat page never reads a question"
5 Old addresses move to the new page: …/chat?msg= and ?q= are replaced by …/start-chat (no question in the address); /demo?q=…&scenario=…&lang=… stays as today; the router safety net that removes msg/q under /project/github.com/ is untouched src/app/datatug-app-routes.ts:77-92 (RedirectCommand, replaceUrl: true) datatug-app-routes.spec.ts (move, replaces history, keeps case of ref), e2e "the old chat address with a question is replaced by start-chat: Back does not return to it", "/demo?q=…&scenario=…&lang=… … still shows the holding page"
6 Privacy, production build, third parties stubbed and recorded — e2e/demo-handoff.spec.ts "the start-chat confirmation page": for fragment, fragment with q, query, query with another key, old chat (msg, q), // and root-group spellings, each on the demo project and on acme/demo: address bar, every history entry (Navigation API), history.* calls, title, storage (only the existing per-tab hand-off key, trusted only), own and third-party requests carry no question; the trusted project echoes it, acme/demo is neutral. Plus: a fragment question is in no request at all, not even the document request or a referrer

Choices where the design was silent

  • Bare …/start-chat (no fragment) shows the same holding page with nothing to confirm (the no-question sentence for the trusted project, neutral wording otherwise). It does not open the project chat: 6.5 row 2 says the holding page, and the chat of a GitHub project shows a data error until G-A7. Tested.
  • "Start" button: none while the flag is off (6.5 has none); a TODO(G-A4b) in the component header says where it goes and that the flag is read where demo-flag.ts is read (the spec forbids importing it here).
  • Folder support is for start-chat only. The old …/chat address keeps its shape (no folder), as today. A start-chat address in a folder or on a ref other than HEAD is a hand-off address and is never trusted.
  • A fragment pasted over the open page (same-document navigation: no reload, the script does not run) is taken by the page and removed from the address: the page state is now a signal re-read on a hand-off navigation that carries a hand-off key. Found by an e2e case; unit tested.
  • The router rewrites //project/… and /(project/…) spellings to the plain address on first navigation; the question is gone either way.
  • A #msg= on …/chat or any other page is not a hand-off (no new special cases); it is neither read nor stripped there.
  • Stored-for-reload key of an old …/chat?msg= is written by the script under the chat path and rewritten under the start-chat path by the page on first render (a reload in the few milliseconds between shows the page without the question).

Checks

  • Unit: vitest app project, 708 tests pass (14 files). pnpm run check:zoneless OK. nx lint datatug-app passes, no findings.
  • E2E playwright.demo-handoff.config.ts against the production build: 113 passed (was 82; the 7 old-chat cases that asserted the address stays …/chat now assert …/start-chat). The config's own webServer could not start under wb run in this worktree (the nested pnpm nx serve exits 1 at once), so the production dev-server was started separately and reused.
  • Initial bundle, production build, origin/main a248156 vs this branch: main chunk 1,227,478 to 1,228,168 bytes raw (+690 B), 324,975 to 325,189 gzip (+214 B); nx "Initial total" 2.10 MB both, estimated transfer 470.90 kB to 470.94 kB.
  • Not touched: in-app link builders, storage, github-project-routes.ts, datatug-routing-*.

Screenshots (390 and 1280; trusted en and ru with a question, bare, untrusted): /private/tmp/claude-501/-Users-alex-projects/27bc30d5-3ff1-4e50-a5d9-9c67e328b1e3/scratchpad/apps-start-chat/shots/.

🤖 Generated with Claude Code

OpenVaultDB and others added 2 commits October 3, 2026 07:04
…uling 2026-10-03)

The demo hand-off now goes to a page of its own,
/project/github.com/<owner>/<repo>/start-chat#msg=<q>&lang=<en|ru> (and
.../tree/<ref>[/<dir>]/-/start-chat#...), with the question in the fragment so
it never reaches the server or a referrer.

- index.html inline script: on a start-chat path takes msg/q/lang from the
  fragment (and the query, for no-JS form posts), stashes them exactly as the
  existing hand-off does, and replaceStates to the same path with the fragment
  and those query keys removed (other keys kept). /demo and the old
  .../chat?msg=... are handled as before.
- demo-handoff-path: new start-chat target (with folder support); the route
  table decision (handoffDecision) replaces showsHoldingPage: /demo and
  start-chat are the page, the old chat address with a question is replaced by
  start-chat of the same project, without a question it is the ordinary chat
  page. /chat never reads a question.
- demo-handoff-capture: start-chat reads and strips the live fragment/query
  itself as a backstop; trust is unchanged (a folder is never trusted).
- Holding page: same component and strings; state is now a signal so a
  fragment pasted over the open page (no reload) is taken and removed too.
  A TODO(G-A4b) marks where "Start" goes once the chat can run a question.
- Specs: path, decision, routes, capture and inline script, holding page; e2e
  against the production build covers the privacy matrix for fragment, query,
  old chat, /demo, // and root-group spellings, trusted and other projects.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@trakhimenok

Copy link
Copy Markdown
Contributor Author

[review r1 #186] Adversarial review (Opus): production builds of this head and of main served side by side; 52 hand-off addresses plus the earlier review's 153; Back/Forward/reload, pasted fragment, 6 KB message, HTML payload; GA stand-in, Navigation API, PostHog and Sentry bodies recorded with positive controls; 3,125 unit tests; mutants of every start-chat branch.

Reviewed-Head: 8a6238e

No question leaks or is echoed where main protected it. /demo behaves exactly as on main, so the live datatug.io button is unaffected. Old …/chat?msg|q= addresses land on the same project's start-chat (history replaced); every other route behaves as on main. The question is echoed only for datatug/chinook-demo at the root (short form or tree/HEAD/-/start-chat), neutral otherwise (Kelvin sign, long s, folder, 40-hex ref, look-alike repos), as text only. The inline script is ES5, first in <head>, same-origin only, stripping nothing outside hand-off paths.

Minors, carried to #184:

  1. A pasted fragment is stripped from the address bar through raw history.replaceState (demo-holding-page.component.ts:596, demo-handoff-capture.ts:339), but the router keeps #msg= in its own URL; a later failed navigation can put it back, and Sentry's navigation breadcrumb records it. Main is worse in every part. Strip through Angular (Location.replaceState / router.navigate([], {fragment: undefined, replaceUrl: true, queryParamsHandling: 'preserve'})); add the breadcrumb scrubber planned in G-A4b.
  2. A reload in the milliseconds after …/chat?msg= loses the question (src/index.html:692-697 saves under the /chat path); save directly under the start-chat path.
  3. datatug-app-routes.spec.ts:273 ("the move replaces the old address in the history") passes with replaceUrl removed; start from a recorded /chat?q= entry and count entries. Browser behaviour is correct.
  4. A fragment on a non-hand-off address (…/chat#msg=, /demo#msg=) is left alone, as on main; the sites never build these.

Not verified: PostHog event bodies (only /flags sent under the stubs; the question element keeps ph-no-capture), real GA4 enhanced-measurement page views, browsers other than Chromium.

VERDICT: blockers=0 majors=0 minors=4 land=yes

🤖 Generated with Claude Code

@trakhimenok
trakhimenok merged commit 41327ab into main Oct 3, 2026
4 checks passed
@trakhimenok
trakhimenok deleted the apps-start-chat branch October 3, 2026 07:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant