Skip to content

Commit 3c30eae

Browse files
committed
fix(electron): eliminate linux flickering via fast render profile + paint timing
Root cause: Electron on Linux was using the 'default' CSS render profile, which keeps backdrop-filters, transitions, and animations active. Tauri's Linux build uses the 'fast' profile that disables these — but the profile detection only checked for __TAURI_INTERNALS__. 1. layout.tsx: detect Electron runtime (window.electronAPI) and apply the 'fast' render profile on Linux+Electron. This disables: - backdrop-filter (compositor-intensive) - CSS transitions on all interactive elements - box-shadow and pulse animations - scroll-behavior: auto instead of smooth 2. main.ts: add paintWhenInitiallyHidden: false and use did-finish-load instead of ready-to-show on Linux. The ready-to-show event can fire before the compositor has stabilized on Linux, causing a flash of partially-rendered content.
1 parent 027ca88 commit 3c30eae

154 files changed

Lines changed: 15596 additions & 12 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.omo/boulder.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{
2+
"active_plan": "/Users/sriharsha/Developer/openlinear/.sisyphus/plans/openlinear-80-percent.md",
3+
"started_at": "2026-05-01T02:55:00.000Z",
4+
"session_ids": [
5+
"ses_220ad9b78ffeOgu93ZgpAjy9By",
6+
"ses_21fb4c421ffeO8ja0mRhs26Spm",
7+
"ses_21fb47f24ffeIHX7l4owEPpkh0",
8+
"ses_21fb41eb2ffetNWEzukaKSaAnh",
9+
"ses_21fb3d16cffe3po6ihSusknR6Q",
10+
"ses_21fb384b0ffeodCEE8aP2DX2hM",
11+
"ses_21f91cc30ffen5zUsaYTRR2HPb",
12+
"ses_21f917275ffeNbzF5wrSVcWV7l",
13+
"ses_21f911881ffe9NzF3NjF5uzXzT",
14+
"ses_21f90c412ffeolTftDWrS8OWar",
15+
"ses_21f90925cffe2MPLh8UB9g9M5F",
16+
"ses_21f339e0bffe4bbGF6L1hH6hQ2",
17+
"ses_21f33694bffeskAphs3VQi6z46",
18+
"ses_21f333ffaffeTBRU5LhWGj8bJh",
19+
"ses_21f331d27ffebZQa7xZmpLEWEX",
20+
"ses_21f32fa57ffegZeIuzQ24y8gIh",
21+
"ses_21f3284dfffeIDXyoST1AQqyo4"
22+
],
23+
"plan_name": "openlinear-80-percent",
24+
"agent": "atlas",
25+
"session_origins": {
26+
"ses_220ad9b78ffeOgu93ZgpAjy9By": "direct",
27+
"ses_21fb4c421ffeO8ja0mRhs26Spm": "appended",
28+
"ses_21fb47f24ffeIHX7l4owEPpkh0": "appended",
29+
"ses_21fb41eb2ffetNWEzukaKSaAnh": "appended",
30+
"ses_21fb3d16cffe3po6ihSusknR6Q": "appended",
31+
"ses_21fb384b0ffeodCEE8aP2DX2hM": "appended",
32+
"ses_21f91cc30ffen5zUsaYTRR2HPb": "appended",
33+
"ses_21f917275ffeNbzF5wrSVcWV7l": "appended",
34+
"ses_21f911881ffe9NzF3NjF5uzXzT": "appended",
35+
"ses_21f90c412ffeolTftDWrS8OWar": "appended",
36+
"ses_21f90925cffe2MPLh8UB9g9M5F": "appended",
37+
"ses_21f339e0bffe4bbGF6L1hH6hQ2": "appended",
38+
"ses_21f33694bffeskAphs3VQi6z46": "appended",
39+
"ses_21f333ffaffeTBRU5LhWGj8bJh": "appended",
40+
"ses_21f331d27ffebZQa7xZmpLEWEX": "appended",
41+
"ses_21f32fa57ffegZeIuzQ24y8gIh": "appended",
42+
"ses_21f3284dfffeIDXyoST1AQqyo4": "appended"
43+
},
44+
"task_sessions": {
45+
"todo:1": {
46+
"task_key": "todo:1",
47+
"task_label": "1",
48+
"task_title": "**Schema migration: add Comment, AgentRun, Notification, ActivityLog + assigneeId/creatorId/parentId on Task + indexes + uniques**",
49+
"session_id": "ses_21fa9e8b0ffehy2nrVGOdMVxvB",
50+
"agent": "Sisyphus-Junior",
51+
"category": "deep",
52+
"updated_at": "2026-04-30T22:04:09.181Z"
53+
},
54+
"todo:8": {
55+
"task_key": "todo:8",
56+
"task_label": "8",
57+
"task_title": "**SSE per-user filtering + auth on /api/events + reconnect with jitter**",
58+
"session_id": "ses_21f91cc30ffen5zUsaYTRR2HPb",
59+
"agent": "Sisyphus-Junior",
60+
"category": "unspecified-high",
61+
"updated_at": "2026-04-30T23:46:48.253Z"
62+
},
63+
"todo:16": {
64+
"task_key": "todo:16",
65+
"task_label": "16",
66+
"task_title": "**Wire header search to KanbanBoard filter (currently does nothing)**",
67+
"session_id": "ses_21f3284dfffeIDXyoST1AQqyo4",
68+
"agent": "Sisyphus-Junior",
69+
"category": "quick",
70+
"updated_at": "2026-04-30T23:50:56.161Z"
71+
}
72+
},
73+
"previous_boulder_archived": {
74+
"plan": "god-mode-web-search-voice",
75+
"progress": "8/75",
76+
"started_at": "2026-02-17T08:20:33.282Z",
77+
"reason": "User explicitly approved new plan openlinear-80-percent which supersedes earlier work"
78+
}
79+
}

.omo/drafts/github-auth-wireup.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Draft: GitHub Auth — Wire Up & Polish
2+
3+
## Requirements (confirmed from user spec)
4+
- Add `.env.example` with all required env vars → ALREADY EXISTS at `apps/api/.env.example`
5+
- Add `.env` with placeholder credentials → Currently only has DATABASE_URL
6+
- Add sign-in entry point to sidebar bottom (below Settings)
7+
- When authenticated: show user avatar + username + sign-out in sidebar
8+
- Remove UserMenu from header (page.tsx)
9+
- "Implement best level auth" — AMBIGUOUS, needs clarification
10+
11+
## Existing Implementation (fully built)
12+
13+
### Backend (Complete)
14+
- `apps/api/src/routes/auth.ts` — OAuth routes: /github (redirect), /github/callback (exchange code + JWT), /me, /logout
15+
- `apps/api/src/services/github.ts` — Full GitHub service: auth URL, token exchange, user/repo fetching, Prisma operations
16+
- `apps/api/src/middleware/auth.ts` — optionalAuth() and requireAuth() middleware
17+
- `apps/api/src/routes/repos.ts` — Authenticated repo operations
18+
- `apps/api/src/app.ts` — Express app with CORS, cookieParser, all routes registered
19+
20+
### Frontend (Complete)
21+
- `apps/desktop-ui/hooks/use-auth.tsx` — AuthContext: user, activeProject, isLoading, isAuthenticated, token in localStorage
22+
- `apps/desktop-ui/lib/api.ts` — Full API client with Bearer token auth
23+
- `apps/desktop-ui/components/auth/user-menu.tsx` — Sign in / avatar+logout component
24+
- `apps/desktop-ui/components/auth/project-selector.tsx` — ProjectSelector dialog
25+
26+
### Environment
27+
- `apps/api/.env.example` — All vars documented (GITHUB_CLIENT_ID, SECRET, REDIRECT_URI, JWT_SECRET, FRONTEND_URL, etc.)
28+
- `.env` — Only DATABASE_URL (no GitHub vars)
29+
- `.gitignore``.env` is gitignored
30+
31+
### UI Layout
32+
- `app-shell.tsx` — Sidebar + main content layout with drag-resize
33+
- `sidebar.tsx` — ProjectSelector (when auth'd), nav links, Settings at bottom (line 202-215)
34+
- `page.tsx` — Header with UserMenu at line 50
35+
36+
## Security Audit Findings
37+
38+
### CRITICAL Issues in Existing Code:
39+
1. **JWT passed via URL query param** (auth.ts:51) — `?token=${token}` visible in browser history, logs, referrer
40+
2. **No OAuth state validation** (auth.ts:20-24) — State generated but NEVER verified on callback → CSRF vulnerability
41+
3. **GitHub accessToken stored in plain text** (schema.prisma:84) — If DB compromised, all tokens exposed
42+
4. **JWT_SECRET hardcoded fallback in 3 files** — auth.ts:13, middleware/auth.ts:4, repos.ts:15 — should be centralized
43+
5. **JWT stored in localStorage** — XSS-vulnerable (though less critical for desktop app)
44+
6. **Logout is a no-op** (auth.ts:84-86) — No server-side invalidation
45+
7. **The /me endpoint duplicates auth middleware logic** — Manual header parsing instead of using requireAuth
46+
47+
### Minor Issues:
48+
- cookieParser imported and configured but unused
49+
- CORS credentials:true set but no cookies used
50+
- No token refresh mechanism (7-day hard expiry)
51+
52+
## Technical Decisions
53+
- PENDING: Scope of "best level auth"
54+
- CONFIRMED: Use Tailwind CSS, lucide-react icons, shadcn/ui components (matching existing patterns)
55+
- CONFIRMED: Express backend with Prisma ORM
56+
- CONFIRMED: Next.js frontend with AuthContext
57+
58+
## Open Questions
59+
1. What does "Implement best level auth" mean? Security hardening or just functional wiring?
60+
2. Test strategy — vitest exists, should we add auth tests?
61+
62+
## Scope Boundaries
63+
- INCLUDE: Env vars, sidebar auth UI, header cleanup
64+
- INCLUDE?: Security fixes (state validation, token delivery, JWT centralization)
65+
- EXCLUDE: Probably don't need token encryption at rest for a local dev tool
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# F1 — Plan Compliance Audit
2+
3+
```
4+
Must Have [16/17] | Must NOT Have [13/16] | Tasks [48/48] | Evidence [62/48] | VERDICT: REJECT
5+
```
6+
7+
**Date**: 2026-05-06
8+
**Auditor**: F1 (oracle plan-compliance)
9+
**Plan**: `.sisyphus/plans/openlinear-80-percent.md`
10+
11+
---
12+
13+
## Headline
14+
15+
Implementation is materially complete (all 48 tasks committed, all named deliverables on disk, API + sidecar typecheck clean, schema models migrated, security routes hardened, brand assets shipped, landing copy purged). However, **3 explicit "Must NOT Have" guardrails are violated** and **1 typecheck target fails**, which the plan's Must-Have list requires to pass implicitly via the build/run criterion. Verdict is **REJECT** pending small fixes — none touch architecture, all fixable in <30 min.
16+
17+
---
18+
19+
## 1. Must Have — Evidence
20+
21+
| # | Item | Evidence | Status |
22+
|---|------|----------|--------|
23+
| 1 | Auth + team-scope on POST/PATCH/DELETE `/api/tasks` | `apps/api/src/services/ownership.ts` exists; `apps/api/src/routes/tasks.ts` uses `requireAuth` + `assertTaskOwned`; commit `66ee3c6`; evidence `task-7-unauth-rejected.txt`, `task-7-cross-tenant-rejected.txt`, `task-7-archived-scoped.txt` ||
24+
| 2 | Shell injection eliminated in git.ts/worktree.ts | `grep -rEn 'execAsync\(\`\|exec\(\`' apps/sidecar/src/services/execution/git.ts apps/sidecar/src/services/worktree.ts` → 0 matches; `apps/sidecar/src/services/execution/exec.ts` exports `execFileAsync`; commit `867c895`; evidence `task-6-injection-blocked.txt`, `task-6-no-token-leak.txt`, `task-6-happy-path.txt` ||
25+
| 3 | Single `apiFetch()` wrapper used everywhere | `apps/desktop-ui/lib/api/fetch.ts` exists; commit `72c38b4`; evidence `task-3-no-module-capture.txt` | ⚠️ See REJECT-1 (2 stragglers) |
26+
| 4 | 401 clears token + redirects to /login | `apiFetch` dispatches `auth:expired`; `hooks/use-auth.tsx` listens; evidence `task-3-qa-scenarios.txt` ||
27+
| 5 | Comment + Notification + AgentRun + ActivityLog models | `grep -E "^model (Comment\|AgentRun\|Notification\|ActivityLog) " packages/db/prisma/schema.prisma` → 4 matches; commit `88dbd92`; evidence `task-1-migration-success.txt` ||
28+
| 6 | `assigneeId` + `creatorId` on Task; my-issues filters | schema.prisma:114-119 + indexes 130-131; commit `6af55e0`; evidence `task-32-assignee.txt` ||
29+
| 7 | Cmd+K command palette with global search | `apps/desktop-ui/components/command-palette.tsx`; commit `bd3b498`; evidence `task-25-palette.txt` ||
30+
| 8 | Markdown rendering on tasks + comments | commit `ecd48dc`; evidence `task-26-markdown.txt` ||
31+
| 9 | Theme switcher functional (dark/system) | commit `f8d412d` (theme batch); evidence `task-29-theme.txt` ||
32+
| 10 | `prefers-reduced-motion` respected | commit `8dacbb6` + `22da6de`; evidence `task-21-css-diff.txt`, `task-24-animations.txt` ||
33+
| 11 | `focus-visible` 2px accent ring | commit `22da6de`; evidence `task-21-css-diff.txt` ||
34+
| 12 | SVG logomark + wordmark + favicon + Tauri icon set | `apps/desktop-ui/public/brand/{logomark,wordmark}.svg` exist; commits `f374471`, `117d517`; evidence `task-5-tauri-icons.txt`, `task-5-logomark-sizes.png`, `task-34-logo-svg.txt`, `task-35-tauri-icons.txt` ||
35+
| 13 | Domain unified to `openlinear.tech` | `grep -rn 'openlinear\.dev' apps/landing/` → 0 matches; commit `2310987` ||
36+
| 14 | `kaizen403` handle replaced everywhere user-visible | `grep -rin "kaizen403"` → only in `.sisyphus/plans/` and `.sisyphus/notepads/` (plan history, not user-visible); zero user-visible refs; commit `5b6f39b`; evidence `task-41-handle.txt` ||
37+
| 15 | Landing copy: zero Zep/Mem0, zero fake stats, footer links resolve | grep for `zep\|mem0\|google drive\|onedrive` in `apps/landing/` → 0 matches; commits `810710a`, `2310987`; evidence `task-39-copy.txt`, `task-40-footer.txt` ||
38+
| 16 | App Router error boundaries (loading.tsx/error.tsx/not-found.tsx) | All 3 files exist at `apps/desktop-ui/app/`; commit `4495952`; evidence `task-43-boundaries.txt` ||
39+
| 17 | Final container builds/runs smoke test | API typecheck PASS; sidecar typecheck PASS; **desktop-ui typecheck FAIL** (see REJECT-3) ||
40+
41+
**Score: 16/17**
42+
43+
---
44+
45+
## 2. Must NOT Have — Violations
46+
47+
| # | Guardrail | Result | Status |
48+
|---|-----------|--------|--------|
49+
| 1 | No `as any` / `@ts-ignore` introduced | **1 violation** in `apps/sidecar/src/routes/opencode.ts:196` | ❌ REJECT-2 |
50+
| 2 | No `console.log` in production code | **20+ violations** in sidecar (see REJECT-4) ||
51+
| 3 | No `window.confirm` / `window.alert` / `window.prompt` | grep clean ||
52+
| 4 | No raw `localStorage.getItem('token')` outside `apiFetch()` | **2 violations** (sidebar.tsx:198, inbox/page.tsx:141) | ❌ REJECT-1 |
53+
| 5 | No new direct `fetch()` in pages — must go through `apiFetch()` | Spot-checked OK ||
54+
| 6 | No new raw hex color literals | grep for `bg-\[#\|text-\[#\|border-\[#` in components/app → 0 matches ||
55+
| 7 | No `exec()` with shell interpolation in git.ts/worktree.ts | grep clean ||
56+
| 8 | No new endpoints without auth + ownership | Spot-checked tasks/comments/notifications/activity → all use `requireAuth` + ownership helpers ||
57+
| 9 | No new module-level `getApiUrl()` captures | Per `task-3-no-module-capture.txt` — clean at audit time ||
58+
| 10 | No deferring of security tasks (T6, T7, W2.1, W2.2) | All committed (`867c895`, `66ee3c6`, `b08e37f`, `9289d9d`) ||
59+
| 11 | No light theme | Dark/system only — confirmed ||
60+
| 12 | No file attachments | Not added ||
61+
| 13 | No cycles/roadmap/templates | Not added ||
62+
| 14 | No Tauri Rust changes | Not touched ||
63+
| 15 | No OpenCode binary bundling | Not added ||
64+
| 16 | No "fix everything in one mega-task" | All 48 tasks bounded with separate commits ||
65+
66+
**Score: 13/16**
67+
68+
---
69+
70+
## 3. Tasks (48/48)
71+
72+
48 implementation commits since baseline (T1=`88dbd92` through T48=`a81b72d`). All 48 plan checkboxes marked `[x]`. The 11 unchecked boxes in the plan are the Definition-of-Done meta-items + the F1-F4 review tasks themselves (this audit being one), not implementation tasks.
73+
74+
## 4. Evidence (62/48)
75+
76+
`ls .sisyphus/evidence/ | wc -l` → 62. All `task-N-*` slots filled for N=1..48 (some tasks have multiple files, e.g. `task-1-migration-success.txt` + `task-1-email-unique-error.txt`).
77+
78+
## 5. Concrete Deliverables — file existence audit
79+
80+
| Plan deliverable | File | Status |
81+
|------------------|------|--------|
82+
| `apiFetch()` wrapper | `apps/desktop-ui/lib/api/fetch.ts` ||
83+
| Design tokens module | `apps/desktop-ui/lib/design-tokens.ts` ||
84+
| Brand SVG logomark | `apps/desktop-ui/public/brand/logomark.svg` ||
85+
| Brand SVG wordmark | `apps/desktop-ui/public/brand/wordmark.svg` ||
86+
| `execFileAsync` helper | `apps/sidecar/src/services/execution/exec.ts` ||
87+
| Ownership helper | `apps/api/src/services/ownership.ts` ||
88+
| Comments API | `apps/api/src/routes/comments.ts` ||
89+
| Search API | `apps/api/src/routes/search.ts` ||
90+
| Notifications API | `apps/api/src/routes/notifications.ts` ||
91+
| Activity Log API | `apps/api/src/routes/activity-log.ts` (plan said `activity.ts` — same surface, different filename) ||
92+
| Cost analytics page | `apps/desktop-ui/app/usage/page.tsx` ||
93+
| Command palette | `apps/desktop-ui/components/command-palette.tsx` ||
94+
| Error boundaries | `apps/desktop-ui/app/{loading,error,not-found}.tsx` ||
95+
| Schema migrated | `packages/db/prisma/schema.prisma` (Comment/AgentRun/Notification/ActivityLog + assigneeId/creatorId/parentId + indexes) ||
96+
97+
---
98+
99+
## REJECT items (with file:line + remediation)
100+
101+
### REJECT-1 — `localStorage.getItem('token')` outside `apiFetch()` (Must Have #3 + Must NOT #4)
102+
103+
**Files**:
104+
- `apps/desktop-ui/components/layout/sidebar.tsx:198` — reads token to build EventSource URL for `/api/events` (SSE notification stream)
105+
- `apps/desktop-ui/app/inbox/page.tsx:141``readToken()` helper for SSE EventSource
106+
107+
**Why it slipped**: Both are EventSource consumers. `apiFetch` does HTTP only; native `EventSource` cannot attach Authorization headers, so the codepath chose query-string token. The plan does not exempt SSE.
108+
109+
**Remediation** (Quick, ~15 min): Either
110+
1. Add `getAuthToken()` exported from `lib/api/fetch.ts` and call it from these two sites (centralised access still goes through one module — satisfies the spirit), OR
111+
2. Extract `createAuthedEventSource(path)` into `lib/api/sse.ts` and have both sites use it.
112+
113+
Option 2 is cleaner; bundles the lazy-URL + token-attach pattern that `apiFetch` enforces.
114+
115+
### REJECT-2 — `as any` introduced in sidecar (Must NOT #1)
116+
117+
**File**: `apps/sidecar/src/routes/opencode.ts:196`
118+
119+
```ts
120+
allProviders.push({
121+
id: 'opencode',
122+
name: 'OpenCode',
123+
models: {},
124+
} as any);
125+
```
126+
127+
**Remediation** (Quick, ~5 min): Type the pushed object against the `OpenCode SDK Provider` type or define a local `type ProviderListEntry = typeof providerList.data.all[number]` and cast to that, or use `satisfies ProviderListEntry`. Since `models` is `{}` it likely needs `Record<string, never>` or the actual `ModelMap` type — check the SDK type.
128+
129+
### REJECT-3 — desktop-ui typecheck FAILS (Must Have #17, smoke-build criterion)
130+
131+
**File**: `apps/desktop-ui/components/ui/command.tsx:33`
132+
133+
```
134+
error TS2322: Type 'ReactNode' is not assignable to type 'React.ReactNode'.
135+
Property 'children' is missing in type 'ReactElement<...>' but required in type 'ReactPortal'.
136+
```
137+
138+
**Cause**: React 19 type duplication — `cmdk`/`@radix-ui` packages bundle a different `@types/react` version, producing two incompatible `ReactNode` types in the same graph.
139+
140+
**Remediation** (Short, ~30 min):
141+
1. Pin a single `@types/react` version via `pnpm.overrides` in root `package.json`:
142+
```json
143+
"pnpm": { "overrides": { "@types/react": "19.2.7" } }
144+
```
145+
2. Run `pnpm install` to dedupe.
146+
3. If issue persists, wrap the offending portal child in `<>{child}</>` or add an explicit `ReactNode` import alias from one canonical location inside `command.tsx`.
147+
148+
### REJECT-4 — `console.log` in sidecar production code (Must NOT #2)
149+
150+
**Files (sample, 20+ total)**:
151+
- `apps/sidecar/src/routes/execution.ts:33,37,180,183,191,196`
152+
- `apps/sidecar/src/services/worktree.ts:34,40,44,47,53,77,80,97,118,122,133,163,172,179` (and more)
153+
154+
**Why it slipped**: T4 added `pino` to API + sidecar `app.ts`, but execution/worktree services were authored pre-pino and never migrated. They use a `[Worktree]`/`[Tasks]` prefix convention as a poor-man's structured log.
155+
156+
**Remediation** (Short, ~1h):
157+
1. Export a `logger` from `apps/sidecar/src/lib/logger.ts` (pino instance).
158+
2. Replace `console.log(\`[Worktree] X\`)``logger.info({ component: 'worktree' }, 'X')` via codemod or hand-edit.
159+
3. ast-grep replace pattern:
160+
```
161+
console.log(`[$NAME] $MSG`) → logger.info({ component: '$NAME' }, `$MSG`)
162+
```
163+
(Note: needs `.toLowerCase()` on $NAME or post-fix.)
164+
165+
---
166+
167+
## Recommendation
168+
169+
**Do not approve until REJECT-1, REJECT-2, REJECT-3 land.** Total effort: **~1 hour**.
170+
171+
REJECT-4 (console.log) is technically a guardrail violation but is **low risk in a Tauri-bundled sidecar** (logs go to stderr regardless). Recommend either:
172+
- (a) Fix in this audit cycle for clean compliance (~1h), or
173+
- (b) File as a P2 follow-up ticket with explicit waiver — pino infrastructure already exists, so the migration is mechanical and doesn't change behaviour.
174+
175+
Everything else lines up with the plan. Schema migrated, security holes closed, brand identity shipped, landing truthful, 48/48 task commits visible in `git log`, evidence trail complete (62 files for 48 tasks).
176+
177+
After REJECT-1/2/3 fixes, re-run:
178+
```bash
179+
grep -rn "localStorage.getItem('token')" apps/desktop-ui/components/ apps/desktop-ui/app/ # expect 0
180+
grep -rn "as any\|@ts-ignore" apps/api/src apps/sidecar/src apps/desktop-ui/{lib,components,hooks,providers,app} # expect 0
181+
pnpm --filter @openlinear/desktop-ui typecheck # expect exit 0
182+
```
183+
184+
Then this verdict flips to **APPROVE**.

0 commit comments

Comments
 (0)