Repository navigation
feat(analytics): a colleague's first open of a patch is a business event - #915
Merged
Merged
Conversation
Owner
Author
|
GPT 6.1 Sol (xhigh) reviewed this. Two should-fixes, both fixed in f860a0e, and the branch is rebased onto #916's latest commit:
|
allisonmahmood
force-pushed
the
feat/colleague-first-open
branch
from
October 23, 2026 23:08
3e38cf6 to
f860a0e
Compare
allisonmahmood
force-pushed
the
feat/final-step-panel
branch
from
October 24, 2026 00:45
5756507 to
72daafa
Compare
Activation is a patch someone else at the company opens within 7 days of the person joining, welcome page aside. Patchy recorded each member's opens for their own Home, but nothing said "a colleague opened your patch for the first time", so the metric couldn't be read in PostHog. Patches.recordOpen now answers whether its upsert inserted (`xmax = 0`), so exactly one open is ever a member's first, even when opens race. When it is, and the opener isn't the owner, serving reports `patch.first_opened` with the patch, its tier, its owner and whether it is the owner's welcome page. The open and its report are one uninterruptible step, so a reader who leaves mid-open can't leave a first open recorded and never reported. Public patches record no member's opens, so they never count; the catalogue, OPERATIONS and the new product.md analytics section say so and record the activation query. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ays cancellable From review: making the whole open uninterruptible kept a disconnected reader's statement waiting on locks, which could exhaust the pool and hold up shutdown. The open now runs through withReportedCommit: the insert and its lock waits stay cancellable, and only the commit and its report are protected. product.md also says plainly that request diagnostics already carry viewer and patch ids for every open. Co-Authored-By: Claude Opus 5.5 <[email protected]>
allisonmahmood
force-pushed
the
feat/colleague-first-open
branch
from
October 24, 2026 01:19
f860a0e to
07bc0ba
Compare
1 of 2 tasks
allisonmahmood
added a commit
that referenced
this pull request
Oct 24, 2026
## What changed This PR adds release 18's What's new entry, written from `b23e6ad`. It covers everything merged since release 17's `through` (`5dd94f3`), and it sets the `patchy` release to `0.18.0` in `packages/patchy/package.json` and `CURRENT_RELEASE`. With this release, onboarding ends in a Final step on Home that follows the person's agent through setup and lets them confirm it right there (#906). | Change | PRs | | --- | --- | | New: A Final step to connect your AI agent | #916, #917 | | New: Confirm your computer without leaving Home | #918 | | Improved: Setting up ends with your first page | #914 | | Improved: The logo takes you Home | #913 | | Behind the scenes: the first time someone opens a colleague's tool is counted, for activation | #915 | One merged PR gets no line: #905 is release 17's own entry. ## Look at - **The entry**, at the top of `releases` in `packages/core/src/whatsNew.ts`. Its labels are the pages' own: Final step, Later, Not me, Home, Patches. - **Rollback safety, from the live commit `a049a3c` to `b23e6ad`.** - No PR in the range is labelled `one-way`, and every PR answers both Release impact questions with "Yes". - Migrations 0026 and 0027 are additive: the `setup_prompt_sign_ins` and `setup_links` tables, and a nullable `device_logins.setup_link_id` with `ON DELETE SET NULL`. Release 17 never reads them. - `rollback-rehearsal` exercised both migrations on the landed heads: - #916: `Exercised rollback paths passed: a049a3c → 6037d86 → a049a3c → 6037d86, in 234s.` - #917: `Exercised rollback paths passed: a049a3c → d03a5bf → a049a3c → d03a5bf, in 217s.` - #918 and #915 change no migration or handler descriptor, so they had nothing to rehearse. - A rollback takes the Final step panel and setup links away. Home goes back to the old guide, and a CLI at `0.18.0` stays usable against release 17: `--setup` is only sent when `/llms.txt` prints it, and release 17's `/llms.txt` doesn't. ## How it was verified - `pnpm typecheck` and `pnpm lint` pass, and so do `packages/core`, `packages/api`, `packages/portal` and the skill lock test (245 tests), including `whatsNew.test.ts`, `schemas.test.ts` and `WhatsNewPages.test.ts`. - The live commit was pinned from `/healthz/deep`: `a049a3c`, release 17. The Deploy run updated last succeeded, and none is unfinished. - Each PR in the range was read, including its Release impact answers. All six landed with the reviewed trees: each squash left `main`'s tree identical to its PR's reviewed head. ## Release impact - [ ] **Breaking** — requires action from anyone already running this - [x] **Not breaking** — no action required This PR changes only the changelog text and the `patchy` version. As with every release, a CLI installed before this deploy is told to upgrade. - **What does a revert leave behind?** Nothing. People whose seen marker reached 18 would just see no new release. - **Does the release before it still work with that?** Yes. If this release misbehaves, roll back to `a049a3cf544ae89691eec547dea46773febfdf05` (release 17). Made by Claude Opus 5.5 in Claude Code, running in T3 Code. Co-authored-by: Claude Opus 5.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #909's branch for its welcome-page predicate; merges with the onboarding stack.
What changed
Activation is now decided: a patch someone else at the company opens within 7 days of the person joining, with the welcome page excluded. Patchy already recorded each member's opens for their own Home, but nothing reported "a colleague opened your patch for the first time", so the metric couldn't be read in PostHog. Now a member's first open of a colleague's company patch reports
patch.first_opened, anddocs/product.md› Analytics records the activation query and its public-patch gap.Closes #912. Part of #906.
Patches.recordOpennow returns whether its upsert inserted (RETURNING xmax = 0, which works on any Postgres version). A member's first record of a patch is reported once, even when opens race. A stale version or an off patch records nothing and returns false.Pages.ts) reportspatch.first_openedwhen that open was a first and the opener isn't the owner. The event carriespatchId,tier,ownerUserIdandwelcomePage(feat(ui): Final step, a panel over Home until your agent is connected #909'sisWelcomePage), and its principal is the opener. It carries no page content. The open and its report are one uninterruptible step. sql-pg gives an interrupted statement 10 ms before cancelling it, so a reader who leaves mid-open could otherwise commit a first open that never reports; the next open isn't first, so that event would be lost for good.trackonly queues, so the page doesn't wait on PostHog, and an event failure never fails the page.Analytics.ts) records this as the one exception to "serving isn't a business event", and says why. The Analytics and Patches glossaries,GLOSSARY-MAP.mdand OPERATIONS' business-event list follow.Look at
1. First-open detection under a race. The test holds an uncommitted insert of the same
patch_opensrow and waits until threerecordOpencalls are blocked on it inpg_stat_activity. Then it rolls the insert back. Exactly one call must report the insert. Before (oldrecordOpen, same tests):After:
The race test passed in each of 5 consecutive runs.
2. What emits and what doesn't (
Pages.test.ts). These run against a real socket:~v/1after v2 is out: no event;{ patchId, ownerUserId, tier: 0, welcomePage: false };welcomepage:welcomePage: true.3. A reader who leaves mid-open still counts. The test makes recording the open take a second and interrupts the request during it. It then requires both the
patch_opensrow and the event. WithoutEffect.uninterruptiblethe run fails withAssertionError: expected +0 to equal 1, because the cancelled open records nothing. With it, the run passes.How it was verified
pnpm exec vitest run packages/patches/src/Patches.test.ts packages/serving/src/Pages.test.ts packages/analytics: 96 passed.packages/portal/src/PortalPages.test.ts: 84 passed. It callsrecordOpenand ignores the new result.pnpm typecheck(src and tests) andpnpm lint: clean. Prettier ran on every changed file.pnpm verify, e2e or the browser suites, because this machine is shared.user.joinedandpatch.first_opened, keyed byownerUserId. I haven't run it in PostHog: the event only exists once this ships.Release impact
This adds one event and changes an internal return type. There's no schema change, migration, CLI or API change.
patch.first_openedevents already sent to PostHog.patch_opensrows are written exactly as before.Made by Claude Opus 5.5 in Claude Code, running in T3 Code.
🤖 Generated with Claude Code