Skip to content

fix(auth): say the workspace was created, gutter-aligned, during email sign-in - #74

Merged
justinhelmer merged 1 commit into
mainfrom
fix/signup-workspace-outcome
Aug 25, 2026
Merged

fix(auth): say the workspace was created, gutter-aligned, during email sign-in#74
justinhelmer merged 1 commit into
mainfrom
fix/signup-workspace-outcome

Conversation

@justinhelmer

@justinhelmer justinhelmer commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

After email sign-in the CLI printed a raw Using workspace My Workspace (ws_…) line that broke the prompt layout and implied the workspace already existed. It now prints an aligned line that says the workspace was just created for them.

What & why

First-time users never asked for a workspace, so "Using workspace X (ws_…)" is confusing — and because it was a bare process.stderr.write, it sat outside the clack gutter that the rest of the sign-in flow uses (see before screenshot). This is the CLI half of the install-output cleanup; the installer half is polylanedotcom#190. The two are independent (no stack).

Changes

  • src/commands/auth/login.tsselectWorkspace takes an announce(ws) callback for the single-workspace outcome; the default keeps the existing plain stderr line, so API-key and OAuth login are byte-identical. WorkspaceItem is exported.
  • src/utils/prompt.ts — new step() wrapper over p.log.step (the ◇ gutter line).
  • src/commands/auth/signup.tsworkspaceOutcome(ws, landing) words the line by landing kind and persistDefaultWorkspace now receives the landing. createdCreated your first workspace (called "X"), and set it as your default.; joinedJoined the "X" workspace, and set it as your default.; otherwise Using workspace "X" as your default.
  • test/signup.test.ts — unit tests for each wording, a flow test on the created landing asserting the new line appears and the raw un-aligned line does not, and assertions on the joined and re-auth (existing) flow tests for their wordings.

Decisions

  • Raw ws_… id dropped from the sign-in line: it's noise mid-flow and polylane workspace list still shows it. Login paths outside clack keep the id.
  • Callback rather than a landing param on selectWorkspace: avoids a type import cycle (Landing lives in signup.ts, which imports login.ts) and keeps the renderer choice with the caller.

Validation

  • created / joined / existing wordings — workspaceOutcome unit tests
  • Email verify path prints the aligned created line, not the raw one — flow test says the workspace was created for a first-time user…
  • joined and re-auth flows print their own wording (and re-auth never says "created") — assertions in the existing flow tests
  • Re-auth path still persists workspace_id — existing test
  • npm run typecheck, npm run lint, npm test (all pass) locally; CI on this PR
  • Human-gated: run the installer against a fresh account and eyeball the gutter alignment (needs a 0.2.25 release to reach the installer)

Before (from the report):

◇  Enter the 6-digit code sent to jhelmer25+installtest1@gmail.com
│  794641
Using workspace My Workspace (ws_039e01695001wrhhj20kohxfnefh5ywg)
│
└  Signed in as jhelmer25+installtest1@gmail.com.

After (rendered locally with clack):

◇  Enter the 6-digit code sent to jhelmer25+installtest1@gmail.com
│  794641
│
◇  Created your first workspace (called "My Workspace"), and set it as your default.
│
└  Signed in as jhelmer25+installtest1@gmail.com.

🤖 Generated with Claude Code

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM: workspace-outcome wording is correctly wired per landing kind, the diff matches the PR's stated diffstat and head SHA exactly, and typecheck/lint/test are clean when reproduced locally.

Verification

  • Head SHA confirmed: 8d453f9d33515a2eb1bab5cc165dd223b769d914 (checked out locally, git rev-parse HEAD matches exactly).
  • Merge-base with main is 34cdb27dbc550b95df40f134bf38c4b06cc6d71e, matching the PR API's reported base SHA; git diff --stat against that merge-base reproduces the PR's own diffstat (4 files, +77/-9).
  • npm run codegen && npm run typecheck: clean, 0 errors.
  • npm run lint: clean, 0 problems.
  • npm run test: 371/371 passing, 0 failures on Node 22.22.2. Note: the PR body claims 376 pass — I could not reproduce that number (371 = the count on this checkout including all 4 new tests this PR adds), so it looks like a stale/typo'd figure rather than a real discrepancy, but flagging since it doesn't match as stated.
  • CI on the head commit: all 3 Node matrix check-runs (20.x / 22.x / 24.x) completed successfully.
  • Author justinhelmer is a human GitHub account (type: User per the API), not a bot identity — no self-approval concern.

Landing-kind coverageworkspaceOutcome (src/commands/auth/signup.ts:185) has 3 branches: created, joined, and a default that covers existing / verify_email / verify_to_join / workspace_full / invite_at_capacity / none / undefined.

  • created: unit-tested directly (test/signup.test.ts:419) and exercised end-to-end (test/signup.test.ts:334-357), asserting both the new line's exact text and the absence of the old raw un-aligned line.
  • joined: unit-tested directly (test/signup.test.ts:422); the end-to-end joined test (test/signup.test.ts:360-386) only asserts the pre-existing nextSteps wording, not the new workspaceOutcome/step line's text.
  • default/fallback: unit-tested directly for both existing and undefined landing (test/signup.test.ts:424-427); the password re-auth flow (describe('auth signup existing-account re-auth'), test/signup.test.ts:213-282) runs this exact code path but doesn't assert on the new wording's text.

Neither gap is blocking: the announce wiring ((ws) => step(workspaceOutcome(ws, landing)) in signup.ts:202) is a single call site already proven end-to-end by the created flow test, and every switch branch of workspaceOutcome is directly unit-tested — so the untested combinations are "known-good function, unasserted integration," not unverified logic. A follow-up assertion on the joined/default lines in their existing flow tests would close the loop cheaply.

Nits

  • workspaceOutcome interpolates ws.name inside literal double quotes (signup.ts:188-192) with no escaping — a workspace name containing a " (e.g. My "Cool" Workspace) would render a visually broken/ambiguous line. Low risk and display-only, and the pre-existing default announce in login.ts:78 and workspaceStep in signup.ts:87-109 already have the same unescaped-interpolation pattern, so this isn't a regression — just worth a follow-up if workspace names are fully free-form.
  • The new step line uses ws.name ("Acme") while the adjacent "Next steps" note uses landing.workspaceSlug ("acme") for the same workspace. Pre-existing inconsistency (not introduced here), just now sitting closer together in the output.

The callback-over-landing-param design (avoiding the Landing type-import cycle) is reasonable and clearly explained in the PR body; selectWorkspace's default announce keeps the API-key/OAuth paths byte-identical as claimed.


Generated by Claude Code

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto-approved: Claude reviewed this PR and posted an LGTM verdict (see its review). A repo admin enabled this via the auto-approve workflow.


Generated by Claude Code

…l sign-in

The single-workspace outcome after email sign-in was a raw stderr line
("Using workspace My Workspace (ws_…)") that broke the clack prompt gutter
and read as if the workspace pre-existed. selectWorkspace now takes an
announce callback; the signup flow renders a clack step line worded by the
landing kind: created → "Created your first workspace (called "X"), and set
it as your default."; joined / existing keep their own phrasing. API-key and
OAuth login paths are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@justinhelmer
justinhelmer force-pushed the fix/signup-workspace-outcome branch from 8d453f9 to ade7089 Compare August 25, 2026 17:29
@justinhelmer

Copy link
Copy Markdown
Contributor Author

Addressed the review at ade7089:

  • Test-coverage gaps — the joined flow test now asserts Joined the "Acme" workspace, and set it as your default., and the re-auth flow test asserts Using workspace "Acme" as your default. and that "Created your first workspace" is not printed.
  • Test count — dropped the number from the PR body; it varies with the generated client on the checkout, so "all pass" is the honest claim.
  • " in workspace names (nit) — intentionally left: display-only, and the same unescaped pattern already exists in login.ts and workspaceStep. Tracking as a follow-up rather than escaping one of three sites in isolation.
  • name vs slug next to each other (nit) — pre-existing in nextSteps; out of scope here (and the installer runs with hints off, so the two lines don't co-occur there). Follow-up material.

@justinhelmer
justinhelmer merged commit 6efc4c2 into main Aug 25, 2026
3 checks passed
@justinhelmer
justinhelmer deleted the fix/signup-workspace-outcome branch August 25, 2026 17:31

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM: Round 2 re-review at ade7089372a22d07d043a8cfeaeeb6bfa4cab2fd.

  • SHA/diff: head SHA matches the PR API exactly. Diff against the true merge-base (34cdb27, since main has advanced past the PR's actual branch point) is 4 files / +81 / -10, matching the PR API's additions/deletions/changed_files exactly.
  • Coverage gap closed: the joined and re-auth (existing) flow tests now assert the new wording directly, not just workspaceOutcome in isolation:
    • test/signup.test.ts:272 — re-auth flow test asserts output.includes('Using workspace "Acme" as your default.') and that 'Created your first workspace' is absent.
    • test/signup.test.ts:387joined-landing flow test asserts output.includes('Joined the "Acme" workspace, and set it as your default.').
  • PR body: no longer claims a specific test-count figure; now says "all pass" without a number.
  • Local checks (fresh run): npm run typecheck clean, npm run lint clean, npm test → 371/371 pass, 0 fail, 0 skipped.
  • CI: all 3 checks green on this head SHA (checks / Test & typecheck on Node 20.x, 22.x, 24.x — all completed/success).
  • Nits from round 1: both confirmed addressed via reply, not code change — author's comment on this PR: unescaped " in workspace names is "intentionally left: display-only, and the same unescaped pattern already exists in login.ts and workspaceStep... tracking as a follow-up"; the name-vs-slug inconsistency is "pre-existing in nextSteps; out of scope here... follow-up material." Reasonable to leave as follow-ups.

No blockers remain.


Generated by Claude Code

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto-approved: Claude reviewed this PR and posted an LGTM verdict (see its review). A repo admin enabled this via the auto-approve workflow.


Generated by Claude Code

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