Skip to content

feat: visual indicator for stateless-mode PRs#545

Merged
pedropaulovc merged 9 commits into
mainfrom
feat/stateless-mode-indicator
Jun 5, 2026
Merged

feat: visual indicator for stateless-mode PRs#545
pedropaulovc merged 9 commits into
mainfrom
feat/stateless-mode-indicator

Conversation

@pedropaulovc

@pedropaulovc pedropaulovc commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a StatelessModeIndicator pill next to the iteration tabs so reviewers can see at a glance when a PR's iteration data is in stateless mode (the GitHub Timeline-API fallback) rather than the full GitHub-Action artifact mode.
  • Two variants: a neutral "Stateless" info pill when the repo has no CodjiFlo artifact, and an actionable "Sign in for full tracking" pill (wired to the OAuth flow) when data exists but the viewer is signed out.
  • Narrows the store's statelessReason from a free-text string to a typed StatelessReason = 'unauthenticated' | 'no-artifact' enum, and maps that enum to human-readable copy at each presentation point (tooltip + the existing fallback console warning).

Details

  • StatelessModeIndicator is built from react-aria Button + Tooltip, lucide icons, with an aria-label so state isn't conveyed by colour alone. Rendered as a sibling of <IterationSelector /> in both .diff-header-iterations blocks; returns null in stateful mode.
  • A second consumer of statelessReason (useIterationAwareFiles fallback warning) is updated to map the enum to a human sentence, preserving the Issue Add logging when GitHub API is used as fallback in iteration mode #186 warning contract.

Test Plan

  • npm run test:all green: lint, typecheck, spec:validate (11), vitest+coverage (1544), E2E (124), storybook (31)
  • New unit tests (component), 5 integration tests (full state matrix incl. negative cases), 3 E2E tests (no-artifact info pill, unauthenticated action pill, sign-in click triggers the real GitHub OAuth redirect)
  • Manual headed Playwright check: info pill renders cleanly in the diff header on a real stateless PR; live console confirms the mapped human-readable fallback warning

🤖 Generated with Claude Code


🔍 Review in CodjiFlo

pedropaulovc and others added 9 commits June 4, 2026 16:45
Indicator pill next to iteration tabs surfacing stateless mode, with an
actionable sign-in variant when the cause is an anonymous session.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the free-text statelessReason string with a typed
StatelessReason union ('unauthenticated' | 'no-artifact') in both the
canonical types.ts and the store's local IterationState copy.
loadIterations now sets enum values instead of sentences.

Validated red->green: typecheck flagged the old string assignments as
errors against the new union before they were converted; the new
useIterationStore test asserting 'unauthenticated' fails when the
assertion is flipped to 'no-artifact', proving it discriminates the
artifact-present-but-signed-out branch from the no-artifact branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Renders null in stateful mode, a neutral info pill ("Stateless") for the
no-artifact reason, and an actionable sign-in pill for unauthenticated —
the latter wired to useOAuthFlow's initiateOAuth. Both variants are
focusable react-aria Buttons with an aria-label (state is never conveyed
by colour alone) and a TooltipTrigger explaining the cause.

Subscribes to mode + statelessReason via store selectors so the pill
reacts to live store transitions, not just prop rerenders. Exported from
the component and feature barrels.

Validated red->green: the unit test (StatelessModeIndicator.test.tsx) and
the tester's integration test both failed with "cannot resolve
./StatelessModeIndicator" before the component existed; all 9 pass after.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds .stateless-indicator base + --info (badge-merged) and --action
(error-fg, hover/focus brightness + focus outline) variants, plus the
tooltip surface. The tooltip reuses the proven .field-tip token set
(contextmenu-bg/main-fg/combobox-border) rather than the plan's
translucent --menu-hover/--watermark-text, which would have rendered a
near-transparent, low-contrast surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render <StatelessModeIndicator /> as a sibling of <IterationSelector />
in both .diff-header-iterations blocks (description view + sticky file
header). Add an 8px gap to .diff-header-iterations so the pill is spaced
from the iteration tabs. In stateful mode the indicator returns null, so
the container's :empty hide rule is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Covers the stateless-reason matrix end-to-end via real user journeys:
- no-artifact (signed in, default mock PR): neutral info pill, /stateless/i +
  class stateless-indicator--info, asserted NOT the action variant.
- unauthenticated (signed out + a CodjiFlo artifact-reference PR comment whose
  artifact download is rejected): sign-in action pill, /sign in/i + class
  stateless-indicator--action, asserted NOT the info variant.
- pressing the sign-in pill initiates the GitHub OAuth flow (intercepts the
  github.com/login/oauth/authorize redirect to prove initiateOAuth fired from a
  real click).

Both reasons are reached through real input paths (mock GitHub API + real
navigation), not test-only state. RED was confirmed before the component
existed (getByTestId('stateless-indicator') not found); GREEN after the
component + DiffView wiring landed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The new unauthenticated stateless test depends on a signed-out auth
store. Reset useAuthStore.token to null in the top-level beforeEach so
that dependency is explicit and cannot bleed into order-dependent
sibling tests (per code review). The per-test setState is now redundant
and removed; the comment points at the beforeEach guarantee.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Task-1 enum change had a second consumer the plan missed:
useIterationAwareFiles' stateless fallback console.warn interpolated
statelessReason raw, so it went from a sentence to the terse enum token
("no-artifact"). That broke the Issue #186 E2E, which asserts the
warning carries a human-meaningful reason (.toContain("CodjiFlo
artifact")).

Keep the enum canonical in the store; map it to human-readable copy at
the emission point via STATELESS_REASON_DESCRIPTION (mirrors how
StatelessModeIndicator maps the enum to tooltip copy). Update the hook's
integration test to drive enum values and assert the mapped sentence,
and type the mock store's statelessReason as StatelessReason | null so an
invalid value would fail typecheck.

Verified: full `npm run test:all` is green — lint, typecheck,
spec:validate (11), vitest coverage (1544), E2E (124, incl. #186),
storybook (31). Grep of src confirms this was the last raw consumer of
statelessReason; the only other reader is StatelessModeIndicator, which
already branches on the enum.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pedropaulovc pedropaulovc enabled auto-merge June 5, 2026 00:21
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

CodjiFlo Iteration Tracking

Iterations captured: 1
Last updated: 2026-06-05T00:21:27.000Z
Artifact: 7426067167
Run ID: 26987622912


What is this?

This comment is automatically updated by the CodjiFlo GitHub Action to enable force-push resilient code review with iteration tracking.

The artifact referenced above contains iteration data that the CodjiFlo frontend uses to:

  • Track code changes across force-pushes
  • Enable comment persistence across code modifications
  • Allow comparison between any two iterations

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
codjiflo 5d56d0f Commit Preview URL

Branch Preview URL
Jun 05 2026, 12:22 AM

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 77.45% (🎯 70%)
⬆️ +0.12%
3250 / 4196
🔵 Statements 76.17% (🎯 70%)
⬆️ +0.12%
3409 / 4475
🔵 Functions 75.55% (🎯 70%)
⬆️ +0.11%
686 / 908
🟡 Branches 71.66% (🎯 70%)
⬆️ +0.19%
1922 / 2682
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/features/diff/components/DiffView.tsx 79.77%
🟰 ±0%
66.66%
🟰 ±0%
70.58%
🟰 ±0%
84.14%
🟰 ±0%
73-84, 97-99, 164, 353-354
src/features/diff/hooks/useIterationAwareFiles.ts 90.9%
⬆️ +0.18%
88.57%
🟰 ±0%
100%
🟰 ±0%
93.25%
⬆️ +0.15%
112, 135, 146, 238-243
src/features/iterations/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/features/iterations/components/StatelessModeIndicator.tsx 100% 100% 100% 100%
src/features/iterations/stores/useIterationStore.ts 86.84%
⬆️ +1.76%
72.46%
⬆️ +5.80%
91.66%
🟰 ±0%
88.18%
⬆️ +1.82%
322, 325, 344, 348, 361-377, 386, 398, 406
Generated in workflow #1350 for commit 5d56d0f by the Vitest Coverage Report Action

@pedropaulovc pedropaulovc merged commit 527a406 into main Jun 5, 2026
11 checks passed
@pedropaulovc pedropaulovc deleted the feat/stateless-mode-indicator branch June 5, 2026 00:23
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