Skip to content

Promote dev to master: landing motion/Escape/Ask AI fixes, SEO pages, retryUpload (Sentry replay stays at 10%) - #561

Open
AminDhouib wants to merge 348 commits into
masterfrom
dev
Open

AminDhouib wants to merge 348 commits into
masterfrom
dev

Conversation

@AminDhouib

@AminDhouib AminDhouib commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Promotes dev to master. Head 6d995bae, 154 commits ahead of master 6232b101 (55 on the first-parent line). Updated 2026-10-21: the original title said Sentry replay drops to 5%. That was reverted in #565, so the old description no longer matched the code.

Session replay (what the code does)

  • Sentry replay samples 10% of sessions (apps/landing/src/lib/analytics/replay.ts:17, SENTRY_REPLAY_SAMPLE_RATE = 0.1). It briefly ran at 5% in fix(landing): sample Sentry session replay at 5% while its ingest is rate-limited #560, then went back to 10% in fix(landing): sample Sentry session replay at 10% again #565 once the self-hosted relay quota was raised.
  • On-error replay stays at 100% (replay.ts:20), and PostHog replay stays at 10% (replay.ts:10, applied in posthog-provider.tsx:74). Master already samples PostHog at 10%, so neither rate changes net.
  • Masking is unchanged: master already has the Sentry replay integration with maskAllText/maskAllInputs/blockAllMedia and the shared mask/block selectors, plus PostHog maskAllInputs. The net replay changes are small: the single REPLAY_SESSION_SAMPLE_RATE is split into POSTHOG_REPLAY_SAMPLE_RATE and SENTRY_REPLAY_SAMPLE_RATE (both 0.1, no behavior change), data-ph-mask is added to the Ask AI transcript list in DocsAskAi.tsx (fix(landing): mask the Ask AI transcript in replays, pin PostHog replay init #562), and new tests pin the settings.
  • Known gap, not a regression: the privacy page (apps/landing/src/app/privacy/page.tsx:41) mentions usage data "via cookies and similar technologies" but doesn't name session replay. That was already true on master, which records PostHog replays. Follow-up to be filed separately.

Also ships

Checks

Master protection needs 1 approving review. @BSalaeddin, this is waiting on you. It will be merged with a plain merge, never --admin.

@codesandbox

codesandbox Bot commented Oct 15, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web Editor • VS Code • Insiders

Open Preview

@AminDhouib
AminDhouib requested a review from BSalaeddin October 15, 2026 06:25
@AminDhouib

Copy link
Copy Markdown
Member Author

@BSalaeddin could you review this? It promotes dev to master so prod picks up Sentry session replay at 5% (PostHog stays at 10%), plus the session replay (#556) and sign-up attribution (#557) work already on dev. All required checks are green. Master needs one approving review and the author can't approve their own PR, so this is waiting on you. I'll merge with the normal merge button after you approve.

@AminDhouib

Copy link
Copy Markdown
Member Author

Update: dev moved on since the review request, so this promotion now also carries #562 (a test pinning the PostHog replay settings, plus masking of the Ask-AI transcript in replays) and #563 (a prod bug fix: the homepage Notify-me modal never opened because window.gtag is undefined without a GA ID). Both merged into dev with green CI. A review whenever you have a moment would be appreciated; I'll merge with the normal button once it's approved and CI is green.

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: dev now also includes #564 (build/CI-only: turbo ordering fix for #402 plus a test:scripts guard), so this promotion picks it up too. No app or package runtime changes in it.

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: dev now also includes #565, which puts Sentry session replay back to 10% (the self-hosted relay quota is fixed). Prod already runs 10%, so with #565 in, this promotion leaves the Sentry rate unchanged instead of lowering it to 5%.

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #588 (T-2848) merged into dev at ec42f9d, so this promotion now also carries it.

  • /docs now starts PostHog and Sentry after page load + idle (2 s cap) or on the first input, the same way / and the framework pages already do since perf(landing): halve the home page first-load JS (zod off the client, PostHog after load, LazyMotion) #450.
  • APP_VERSION and buildFeedbackProperties moved to a server-only contract.server.ts, so package.json no longer ships to the client. This adds the server-only dependency to landing.
  • Sampling rates, masking, the proxy path and event names are unchanged.
  • Tradeoff: on /docs, errors thrown before Sentry starts and the first seconds of replay are not captured. The home page already behaves this way.

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #589 merged into dev (ed9d16a). It changes apps/mastra only: the docs Ask AI search ranking (search-docs.ts: stopwords, length normalisation, title/path boosts, quickstart intent) and the docs-agent prompt plus maxSteps: 8. That fixes Ask AI ending with no answer after 5 search steps (T-3644). It doesn't touch the model, retries or proxy config.

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #590 merged into dev (fd99ff2). Follow-up to #589, apps/mastra search-docs.ts only: the install-intent boost now scales with how much of the query the page's title/path covers, so 'getting started with server mode' finds server-mode-setup. Generic upload/file terms no longer boost comparison pages, and package-manager words are excluded. Includes a stemmer fix ('files' and 'core' no longer collapse). No model, retry or proxy changes (T-3644).

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #535 merged into dev (6d6c0ff), contributed by @jayasuryapazhani, fixes #392. @useupup/react useUpload() and UploaderRef.useUpload() now expose retryUpload(fileId?), forwarding the controller command that already existed (controller → orchestrator → core.retry). It adds a real-core ref test plus a hook forward test, a ref-api docs entry, and a react+preact patch changeset. The runtime export list is unchanged. Other frameworks have no ref accessor, so there's nothing to port.

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #591 merged into dev (4de151f). It is a docs-only follow-up to #535 and changes one line in apps/landing/content/docs/api-reference/upupuploader/ref-api.mdx. That line now describes what retryUpload(fileId?) actually does: with an ID it re-attempts that file whatever its status, and without one it re-attempts every file that failed or hasn't uploaded yet. A call during a running upload joins that run, and the promise rejects after destroy(). No code changes and no changeset (T-3797).

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #592 merged into dev (6581bca). It touches apps/landing only, and docs/. It adds landing motion tokens: --motion-dur-fast/base/slow/panel (120/180/240/150 ms) and ease-out/in curves, wired into Tailwind as duration-*, ease-motion-* and four transform/opacity-only animate-motion-* keyframes. A global prefers-reduced-motion CSS net zeroes animation and transition durations and delays on every landing element; spinners and the embedded .upup-scope uploader are excluded because the uploader keeps its own data-motion gate. MotionConfig reducedMotion="user" covers framer-motion. Unused fadeIn/fadeInUp/bounce-slow/scale-in utilities are removed, and docs/motion-audit.md lands with it. Nothing visible changes yet. Lighthouse mobile median-of-3 is identical before and after (LCP/CLS). No package changes (T-3821).

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #593 is merged to dev (e18ca12). It is landing-site motion only (Ask AI drawer, transcript arrival, docs search, copy-button icon fade) and touches no @useupup/* package. Once this promotion lands, it ships with it. Review: one REQUEST CHANGES round (drawer focus on open), then APPROVE. Status Check and E2E Status Check are green.

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #594 merged to dev (33d4e1d), the motion pass forms/buttons spot (T-3821).

  • The support form submit has a press scale and a label cross-fade, and its width stays at 148 px while sending.
  • The notice now sits in sibling status and alert live regions, with no idle gap.
  • The copy-icon swap is shared across AgentSetupPill, CodeCardControls and DocsCopyPage, with an sr-only status.
  • Everything is landing-only, CSS motion tokens plus reduced-motion fallbacks. CLS is unchanged (0.003 desktop, 0.040 at 360 px).

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #595 merged to dev, the motion pass mobile nav spot (T-3821), which is the last of the spot PRs.

  • The mobile menu's inner div enters with an 8px rise and fade. The backdrop-blur container is not animated, and the exit is instant.
  • The Menu/X icon fades in place in a fixed 20px box, only after the first toggle, so there is no page-load fade. The 44px target and the aria contract are unchanged.
  • Under reduced motion both are instant. CLS is 0 and scrollWidth is 360 at 360 px. Landing-only.

@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #596 merged to dev (367d69b). fix(landing): the global reduced-motion net now forces transition-duration: 0s instead of 0.01ms, so a just-opened Ask AI drawer is not held hidden for a frame and the composer gets focus under reduced motion. Landing-only CSS + a unit pin + one docs e2e; no package changes.

Tailwind's preflight sets list-style: none on every list, so numbered steps and bullet lists in assistant answers rendered with no numbers or bullets. Give .upup-ie-ai-md ol/ul decimal/disc markers. Found and verified in a headed live check at 360 px against the dev Mastra server.
feat(interactive-example): stream playground assistant answers with whole-unit markdown and ease-in
@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: #597 merged to dev (3c3be8d). The playground assistant now streams answers via agent.stream(). Markdown renders in whole units only (links, URLs, code, tables, list items are buffered until complete). New text eases in at 180–200 ms, opacity/transform only, and appears instantly under reduced motion. The composer and Send keep keyboard focus mid-stream (aria-disabled instead of disabled). List markers are restored. Adds docs/ai-chat-ux-audit.md. Scope: packages/interactive-example only. No model, Mastra or server changes. Rides this PR to master.

…s in the assistant chat

Each assistant turn now carries a plain-word step trail built from the
Mastra stream's tool-call / tool-result / tool-error chunks. It is a
collapsed disclosure button (aria-expanded/aria-controls) that names the
running step, and announces once politely when the turn ends. Steps still
running at turn end read 'Stopped before it finished'.

The streamed markdown renderer gains thematic breaks (---, ***, ___) as
<hr>, holding a partial rule back until it is complete.
Sendly is the one email tool across Devino apps, so the /support email leg
drops both the UseSend REST transport and the nodemailer SMTP fallback for a
single Sendly call: POST https://api.sendly.now/api/v1/emails with a Bearer
key (a sending-only key is enough) and the feedbackId as Idempotency-Key, so a
retried submission never mails twice.

Sendly renders `body` as an HTML template, so the plain-text submission is
HTML-escaped, braces are entity-encoded (user text can never become template
syntax) and newlines become <br>.

Env: SENDLY_API_KEY replaces USESEND_API_URL, USESEND_API_KEY and SMTP_URL in
env.ts, .env.example and the site compose. Unset still reports
'not_configured'. nodemailer and @types/nodemailer are removed.
…rts like one

A still-streaming line such as `___ x` or `--- a` was released as `___ `
(cut after its space), which parses as a thematic break on its own. The
chat mounted an <hr> and then swapped it for a paragraph once the line
went on. The released part of the open line is now held back whenever it
would read as a rule by itself.

RED before the fix (vitest, src/tests/markdownStream.test.ts):
  x notRules: every split index yields only whole units of the final render
    partial unit at split 81: "...- - a\n--- "
  x notRules: parses and streams exactly like its LF twin
  x never shows the start of a text line as a rule
    AssertionError: expected '___ ' to be ''
  Tests  3 failed | 89 passed (92)
…ule-like line end

3715c19 only guarded the partial-last-line branch. A finished line whose
inline opener is still open (`___ **bold`, "--- `code") reached the final
hold unguarded and released `___ `, a rule on its own. The guard now lives
in hold(), which cuts every paragraph release, so both paths share it.

RED on 3715c19 (vitest, src/tests/markdownStream.test.ts):
  x never shows a rule-like line start held by an open inline unit
    AssertionError: expected '___ ' to be ''
  Tests  1 failed | 92 passed (93)
docs(changeset): correct release notes before the next publish
# Conflicts:
#	.github/workflows/main.yml
#	apps/landing/src/generated/page-lastmod.json
#	apps/mastra/src/mastra/agents/docs-agent.ts
#	apps/mastra/src/mastra/tools/search-docs.test.ts
#	apps/mastra/src/mastra/tools/search-docs.ts
#	package.json
chore: sync master into dev before #561 promotion
Amin ruled the next release is MINOR (3.4.0). The nine @useupup/* packages
are a changesets fixed group, so one minor entry moves the whole group.

- retry-upload-ref-api: new public API, retryUpload on the uploader ref.
- server-drive-row-and-disconnect: new /logout route and the public
  addTransferredFile/checkTransferredFile.
- server-oauth-callback-failure-status: status change, 424 vs 502.
- server-transfer-type-part-length: tokens without ps now 403 malformed.
- oauth-callback-binding: /cb now 403 without the nonce cookie.
- server-sec-lows-6186: a non-integer size is now rejected.

Only frontmatter bump levels changed; body text is untouched.
Tracks T-10049, T-6185.
chore(release): mark behavior-changing changesets minor (3.4.0)
…llowup

chore(release): mark drive request-validation changesets minor
The docs FAQ 'Where do I ask something that is not answered here?' entry
(prose and the frontmatter/JSON-LD answer) pointed at the support form
without the reply-time promise carried by the other support surfaces.
…-7972)

Review minors of #658. Soften the releaseStream comment: the awaited cancel()
was the only in-code suspect for the live hang, not a proven tee mechanism.
Add tests: stream.cancel() throwing synchronously still answers 415; a body
already locked when the transfer fails still answers 500 with nothing stored
and no unhandled rejection from the release.
feat(landing): promise a reply within 1 business day in the docs FAQ
test(server): pin releaseStream sync-throw and locked-stream paths (T-7972)
…el test (T-10845)

The first test in uploader-panel.spec.ts paid the cold cost of the whole standalone component tree and timed out at the 5 s default on a loaded CI runner. A beforeAll with its own 30 s hook timeout now pays it once; the global testTimeout is unchanged.
…p comment (T-10845)

upup-uploader.component.spec.ts showed the same cold-start shape: its first test took 4264 ms of the 5 s limit in the original failing job. Apply the same beforeAll warm-up, and reword the uploader-panel comment to name the real cost (Angular JIT compile of the standalone tree, first DI and render).
Comments only: teardown is a DestroyRef.onDestroy callback registered in ngOnInit (no ngOnDestroy), and the test never timed out, so say cold-compile cost rather than flake.
…-test

test(angular): warm the TestBed compile before the first uploader-panel test (T-10845)
fix(deps): patch body-parser and re2js advisories (Oct 2026)
… AI search-loop cap (#678)

Closes two coverage gaps for the master->dev sync (T-10094, T-5788). See PR body.
test(landing,mastra): pin served sitemap lastmod/comments and Ask AI search-loop cap (#678)
#677, #679 and #680 hand-edited .changeset/*.md frontmatter and nothing in
PR CI validated it; a typo'd package or bump only failed at `changeset
version` on master. scripts/ci/changeset-frontmatter.test.mjs exports a pure
validateChangeset() (fixture-tested: good, bad name, bad bump, duplicate key,
empty body, CRLF, ignore list, major marker) plus one test over every
`git ls-files .changeset` file against real workspace package names.
`major` requires a `<!-- major-allow: reason -->` line.

RED (".changeset/server-low-hardening.md" key changed to @useupup/serverr):
  not ok - every tracked changeset has valid frontmatter
  + '.changeset/server-low-hardening.md: unknown workspace package: @useupup/serverr'
  - []
GREEN (reverted): 11 tests, 11 pass, 0 fail.
Review fixes for the changeset frontmatter guard. The hand-rolled regex
accepted YAML the real parser rejects (unquoted @ keys, no space after the
colon) and rejected legal empty changesets. validateChangeset now delegates to
@changesets/parse and workspace discovery to @manypkg/get-packages, both
resolved through @changesets/cli (not resolvable from the root under pnpm
strict). Empty changesets and `none` bumps pass; a summary is required only
when releases exist; a major needs a major-allow marker plus a real summary.
Documented in .changeset/README.md and CLAUDE.md.

RED (.changeset/server-low-hardening.md key changed to @useupup/serverr):
  not ok - every tracked changeset has valid frontmatter
  + '.changeset/server-low-hardening.md: unknown workspace package: @useupup/serverr'
GREEN (reverted): 16 tests, 16 pass, 0 fail.
…er-guard

test(ci): validate changeset frontmatter in test:scripts
The org's GitHub artifact storage is hard-blocked until the billing cycle
resets, so every actions/upload-artifact step is rejected. Swap all eight
uploads (e2e.yml 3, nightly.yml 5) for DevinoSolutions/artifact/upload
(v1.2.1, SHA-pinned), which stores on Devino MinIO via the job's OIDC token.

- job-level permissions (id-token: write, contents: read) on the six
  uploading jobs
- every upload step also guarded against fork PRs (no OIDC token)
- CLAUDE.md and docs/testing.md updated (T-14188)
Review follow-ups on the Devino MinIO artifact move:
- Workflow-level permissions in e2e.yml, nightly.yml and main.yml drop
  id-token: write (a leftover from #366). The MinIO policy is keyed on the
  org owner id, so any job able to mint an OIDC token could read/write the
  whole gh-artifacts bucket; now only the six uploading jobs can.
- Pin DevinoSolutions/artifact/upload to v1.2.2 (67676f30): retries OIDC/STS
  and Cloudflare 520-524 transport errors.
- Docs: the job summary prints the s3:// location (not a link), and
  retention-days 2 is stored for 3 days (the action rounds up).

This reverses 8966013's "Devino artifact store is for private repos only"
ruling: the org's GitHub artifact storage is hard-blocked until the billing
cycle resets (Amin, relayed via T-13799).
…inio

ci: store workflow artifacts on Devino MinIO instead of GitHub
@AminDhouib

Copy link
Copy Markdown
Member Author

Scope note: this promotion now also carries #689 (CI only, no product code). Workflow artifacts move from GitHub storage to Devino MinIO via DevinoSolutions/artifact/upload, and only the uploading jobs can mint an OIDC token. Checks re-run on the new head.

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.

3 participants