9.0 KiB
9.0 KiB
Task: Diagnose live AI design freeze after HTTP1 package
Identity
- Task ID: 20260819-design-freeze-live-6e2c
- Mode: Feature
- Branch: codex/20260819-design-freeze-live-6e2c-design-freeze-live
- Worktree: D:\mk-design-freeze-live-6e2c
- Base commit:
1ba68a9e41 - Owner: codex-root
- Status: Completed
Scope
- Inspect the live installed Makelore process after the combined native-login and HTTP/2-disabled diagnostic package froze in AI Design.
- Verify package provenance, Chromium transport flags, process health, TCP state, local Host API responsiveness, session-refresh eligibility, Works service health, and the matching request implementation.
- Implement the directly authorized fix in the same task: bound finite AI Design and Works session-refresh requests, prevent implicit replay of non-idempotent requests, and add focused regressions.
- Build a Windows diagnostic package that retains native password/SMS login and
disable-http2so this behavior change can be isolated in the user's next smoke test.
Intent And Constraints
- The user explicitly requested direct execution without sub-agents.
- Treat the observed 409, global Loading state, and previous
ERR_HTTP2_PROTOCOL_ERRORas separate signals until live evidence connects them. - Read the encrypted session only to project expiration/activity metadata and to issue bounded read-only requests; never print or persist access/refresh tokens.
- Do not replay the Quote PATCH because its idempotency and server-side commit state are not proven.
- Remove every temporary harness and isolated Chromium profile before completion.
Outcome
Confirmed facts
- The installed
app.asarSHA-256 exactly matched the combined diagnostic package:80948DDBBD5F9BDE9B4C75CB40E515E63200AA79582BF16CF88347DECCD864C6. - The live Network Service process had
--disable-http2; HTTP/2 was genuinely disabled. - Main, Renderer, GPU, and Network Service remained Windows-responsive. A three-second sample showed zero Main/Renderer CPU growth and only
0.0156seconds in Network Service, so the process was passively waiting rather than spinning or blocking the UI thread. - While the UI remained stuck, three rounds of 20 concurrent requests to the live Host API all completed with the expected unauthenticated
401in47/16/14 ms. Main's HTTP event loop and listener were not globally blocked. - The stored access token was more than 157 minutes from expiry and outside the 30-second refresh skew. The shared
refreshFlightwas not active for this incident. - With the same authenticated session, read-only Node probes to
/api/auth/me, Design capabilities, Workspace list, the affected Workspace, and its two Conversations returned200in31-159 ms. Works, the account, and that Workspace were not globally locked. - A fresh Electron
43.4.0Network Service withdisable-http2returned200for the same three read-only endpoints in1764-1853 ms. HTTP/1.1 itself remained functional. - Product code gives
net.fetch, its global-fetch fallback, session refresh, designauthorizedFetch, IPC Host API requests, Workspace/Conversation loads, and Quote repricing no common deadline or abort contract. Their UI cleanup runs only after the Promise settles. proxyAwareFetchcatches every Electronnet.fetchexception and unconditionally replays the same request with globalfetch. That is unsafe for mutation methods such as QuotePATCHwhen the first request may have committed before its response transport failed.
Conclusion
- Disabling HTTP/2 did not fix the freeze and is not the root cause.
- The live symptom is an unbounded in-process network/IPC Promise in the current Makelore network context. The process remains healthy but a request can wait forever, leaving Renderer loading/busy state waiting for
finally. - The observed
409is a completed conflict response and cannot itself block the JavaScript thread. It may be a secondary symptom of the unconditional transport fallback replay after an earlier protocol failure, but that specific mutation was not replayed during this diagnostic task. - The user's “one request hangs, then everything stays Loading” report is consistent with missing deadlines/cancellation plus page-level state ownership, not with a dead request thread.
Implemented fix
- Added a reusable deadline primitive that aborts the active transport and still rejects deterministically when a transport ignores
AbortSignal. - Bounded the complete AI Design JSON request lifecycle to 30 seconds, including token lookup/refresh, response headers, and response-body parsing. The adapter returns a stable
504 DESIGN_WORKSPACE_REQUEST_TIMEOUTwithAI 设计服务响应超时,请重试. - Bounded the shared Works access-token refresh to 30 seconds. All coalesced callers settle together,
refreshFlightis released by its existingfinally, and a later refresh can retry without clearing a still-valid refresh token. - Restricted Electron-to-Node fetch fallback to safe reads (
GET,HEAD,OPTIONS).POST,PATCH,PUT, andDELETEtransport failures now propagate without implicitly replaying the mutation. - Preserved native password/SMS login and the temporary global
disable-http2switch in the diagnostic installer so the user can isolate this request-lifetime/replay fix before HTTP/2 policy is revisited.
Verification
- Live installed-package hash comparison — PASS, exact match.
- Live process command-line projection — PASS, Network Service had
disable-http2. - Live process responsiveness/CPU sampling — PASS, responsive passive wait.
- Host API concurrency probe — PASS, 60/60 requests completed within 47 ms per round maximum.
- Encrypted-session metadata projection — PASS, no refresh window and no token output.
- Authenticated read-only Works differential probes — PASS, account/Design/Workspace/Conversation endpoints responsive.
- Fresh Electron HTTP/1.1 differential probe — PASS.
- Static request-path inspection — confirmed missing deadlines/AbortSignals and unconditional fallback replay.
- Temporary scripts, metadata output, and isolated Electron profile — removed.
- Red-phase regression run — PASS as evidence: the new mutation-replay, stuck request, and stuck shared-refresh tests all failed against the previous implementation.
- Focused unit tests — PASS, 59/59.
- TypeScript check — PASS,
pnpm run typecheck. - Lint check — PASS with zero errors and seven pre-existing unrelated warnings.
- Full unit suite — PASS on clean rerun, 184 files and 2190 tests. The first run had one unrelated Windows port-release timing failure; its focused rerun passed before the clean full rerun.
- Production compile — PASS,
pnpm run build:vite. - Windows package build — PASS after the verified prior uv binary and verified Learning Player artifact were reused when GitHub download timed out.
- Packaged Learning Player verification — PASS, SHA-256
748d6d7c74d9d0ba444e0c051a50010f7070e7d6e46442b1e60f1e2be80fd020. - Packaged
app.asarmarker inspection — PASS fordisable-http2,DESIGN_WORKSPACE_REQUEST_TIMEOUT, and the request-deadline implementation. - Packaged Electron runtime verification — PASS, including Electron
43.4.0, Node24.18.1, OpenCode, Python, uv, npm, and native addons. - Installer SHA-256 —
FB3BDA4F464770E58EA0AA6E989366685976D5FA7B76E6944B92879B423D83D4. - Packaged
app.asarSHA-256 —A752255B43694814CC3D3FB86C75E024D39E67BBF87BE273960A1FA9FA0366A6.
Follow-ups
- Smoke the original Quote edit/retry/confirm sequence in the diagnostic package. A stalled request should now leave Loading within 30 seconds and show the explicit timeout message; a transport exception must not produce a second Quote PATCH.
- After the user confirms the bounded-request fix, restore HTTP/2 in a separate package and repeat the same regression smoke.
disable-http2remains a diagnostic variable, not the root-cause fix. - Add privacy-safe request lifecycle instrumentation (
route kind, transport, phase, elapsed time, deadline outcome, correlation id) so a future live freeze identifies the exact pending boundary without DevTools or credentials.
Promotion Candidates
- Target:
.project-docs/20-architecture/data-flow.mdand the AI Design transport boundary. - Proposal: document the implemented bounded AbortSignal/deadline contract for Main-owned finite Works requests and the prohibition on implicit mutation replay without an explicit idempotency contract.
- Evidence: this live differential diagnosis, the focused/full regression results,
electron/utils/proxy-fetch.ts,electron/services/works-square-session.ts,electron/image-workspace/works-square-workspace.ts,src/lib/host-api.ts, andsrc/stores/image-workspace.ts. - Future impact: network failures become terminal and recoverable instead of leaving permanent Loading state or ambiguously duplicating Quote mutations.
- Semantic conflicts: none with ADR-001; Workspace/Conversation ownership remains unchanged.
- Human confirmation required: no for a bounded bug fix, but permanent HTTP protocol policy should be decided separately after the fixed package is validated.