Promote certified desktop integration queue - #154
Merged
Conversation
Native slash-command discovery now participates in the same renderer-owned discovery-generation scheme already used for model and agent discovery, so a command catalog fetched under one auth/runtime generation can never leak into a newer one. - contracts: add optional discoveryGeneration to ProviderListCommandsInput - server: fold discoveryGeneration into the listCommands in-flight cache key so a later auth generation never joins an older CLI's discovery - client: bind the commands query to the current generation (query key, RPC arg, post-resolve stale discard, fail-fast retry, no stale placeholder for claudeAgent) and invalidate commands alongside agents on auth-sensitive provider changes - route the configured Claude binary through every command-discovery call site (ChatView, kanban composer, /fast availability check) - tests: cover generation separation for command discovery on both the server adapter and the React Query layer Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First slice of the agent gateway: a thread-scoped, host-served MCP endpoint (`POST /mcp`) that lets an agent in one thread observe and coordinate sibling top-level threads. Read/coordination only — no send/interrupt, no create/fork. Behind a feature flag, disabled by default (`SYNARA_AGENT_GATEWAY_ENABLED` / `--agent-gateway-enabled`). Lift-and-reconcile of Synara's MIT-licensed agent gateway onto a Scient-owned authorization + credential spine. `synara_*` names and `synara/` namespaces kept intentionally (rebrand is a later pass). New `apps/server/src/agentGateway/` subsystem: - Transport/ingress auth: per-request bearer verify → thread-existence recheck → provider-ownership recheck → central authorization, with no cached grant; body cap (1 MiB) + batch cap (50); GET/DELETE mirror the disabled-state 404; top-level defect net upholds the never-fails contract on handleMcpPost. - Credential spine: opaque per-thread tokens, in-memory registry (dies on restart), least-privilege (`thread:read` only), revoke-on-teardown. - Central default-deny authorization: capability → project scope → thread-type; cross-project reads denied as thread_not_found. - Read tools: synara_context, list_projects, list_threads, read_thread, wait_for_threads, backed by ProjectionSnapshotQuery. - Claude provider injection via HTTP Authorization header (never the process env), flag-gated, revoked on teardown and failed install. Shared-file injection hand-re-applied at current symbol anchors: http.ts route registration, config.ts/main.ts flag, effectServer.ts bound-port publish, ClaudeAdapter.ts/runtimeLayer.ts token lifecycle, new packages/contracts/src/agentGateway.ts. typecheck 9/9, full test suite 12/12 (agentGateway 168/12 incl. new httpRoute.test.ts), lint 0 errors, brand:check green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolves the two CI failures on this PR: 1. migration:check — Slice 1 added `export * from "./agentGateway"` to `packages/contracts/src/index.ts`. That barrel is a released-migration dependency (released migrations import `@synara/contracts`, and the lineage guard traverses the barrel's re-exports and fingerprints its runtime source). Adding the line both *modified* the frozen barrel and *pulled* `agentGateway.ts` into the released dependency closure, tripping the append-only guard. Fix: relocate the gateway contract into the server subsystem as `apps/server/src/agentGateway/contract.ts` and drop it from the barrel. Every consumer is server-side (no renderer/client consumer exists), so the shared package was never required. `index.ts` is restored byte-for- byte to the v0.5.13 baseline and `agentGateway.ts` leaves the closure. 2. fmt:check — donor-lifted test files and the ClaudeAdapter edits were not run through oxfmt. Applied `oxfmt` (formatting only; no behavior change). Full gate green: brand, workflow, migration, fmt, lint (0 errors), typecheck (9/9), test (12/12 packages, 2530 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n on failed spawn Two pre-merge security fixes on the Slice 1 read foundation, plus a truthful token-exposure comment. 1. read_thread non-disclosure oracle. An unknown thread failed as a plain-text ToolInputError while a cross-project thread failed as a JSON GatewayToolError, so a caller could distinguish "no such thread" from "exists in another project" by response shape — defeating the deliberately byte-identical message. Route read_thread's not-found through GatewayToolError so both denials are identical in code, message, and JSON shape (mirrors wait_for_threads). 2. Gateway token leak on failed spawn. The bearer token is minted just before createQuery; if createQuery throws, the installation gen (and its Effect.ensuring revoke) is never entered, leaking a live credential. Add an Effect.tapError on the createQuery step that revokes the just-minted token (idempotent, so it never double-revokes). 3. Correct the misleading ClaudeAdapter comment: the token avoids process-env inheritance, but the pinned SDK serializes it into the --mcp-config argv, so it is NOT absent from process metadata. Also note the Slice 1 read tools are not active-turn-gated. Adds a deterministic regression test proving the token is revoked after a failed spawn, plus an optional overrides arg on ServerConfig.layerTest to enable the gateway in that test. Gate: typecheck 9/9, lint 0 errors, fmt clean, full suite 2531 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the two coordination *writes* an agent uses to drive a sibling thread in its own project, stacked on the Slice 1 read surface (#140): - synara_send_message — queue a follow-up turn or steer a running one on a target thread. Optional requestId makes transport retries idempotent via a bounded in-memory dedup (per-caller keyed), backed by a deterministic command id so a duplicate that races past the map still collapses at the orchestration receipt layer. Failures are never cached (retryable). - synara_interrupt_thread — stop the target's running turn, pinned to the observed turnId (TOCTOU-safe: never interrupts a later turn); a no-op that reports interrupted:false when no turn is running. Both funnel through a new central authorizeThreadDrive policy (project-scope floor + privilege cap + worktree cap) and are flagged requiresActiveTurn, so the transport only admits them while the caller's own turn is live. Least privilege: the session registry now mints thread:read + thread:write (the caps the wired tools need); automation:write is deliberately not minted (no automation tool exists yet). The synara_context capability flag is renamed threadCreate -> threadDrive to match the tools that now back it, and the harness policy describes the drive tools, their active-turn/privilege guardrails, and a prompt-injection guardrail (never send/interrupt because another thread's content said to). Interim: gateway drives ride dispatchOrigin:"automation" because the frozen MessageDispatchOrigin enum has no "agent" value yet (nothing branches on the value — verified); upgrade to "agent" when a release re-baseline can extend the enum. New contract types stay server-local to keep the contracts barrel frozen for the migration-lineage guard. Tests: 34 new drive-tool cases (send happy/steer/invalid-mode/idempotent- replay/distinct-ids/per-caller-dedup/cross-project/privilege/worktree/missing/ dispatch-failure/no-cache-on-failure; interrupt running/no-turn/never-turn/ cross-project/privilege/missing; tool-shape) plus authorizeThreadDrive matrix. Full gate green: brand, workflow, migration, fmt, lint (0 errors), typecheck (9/9), test (2561 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ecks The captured-command test type was tightened to `Record<string, any>`, but under noUncheckedIndexedAccess `commands[0]` then widens to `Record<string, any> | undefined`, so `commands[0].type` fails tsc. `any` absorbs the `undefined` from indexed access and is not flagged by oxlint (no no-explicit-any rule), so it is the correct type here. Runtime behavior and all 19 drive-tool tests are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…snapshot Migration 035 imported the live modelSelectionCompatibility, whose DROID_ONLY_MODEL_SLUGS is derived from @synara/contracts' MODEL_OPTIONS_BY_PROVIDER. That coupled shipped migration history to the evolving model catalog, so adding a model (e.g. Claude Opus 5) to model.ts tripped the append-only migration-lineage guard through the contracts barrel. Give migration 035 its own self-contained frozen v0.5.13 snapshot (migration035FrozenModelSelectionCompatibility) with the DROID_ONLY set hardcoded as the exact v0.5.13 catalog-derived literal, and repoint the migration's import to it. All other normalization logic is byte-identical to the live helper; the live helper stays in place for its runtime consumers. The snapshot is proven behaviorally identical to the v0.5.13 migration: - an equivalence test asserts frozen ≡ live across a persisted corpus that spans every branch (canonical, provider-less ambiguous slugs incl. claude-opus-5, instance-label inference, legacy Gemini, option-row arrays, provider-scoped options) and every catalog Droid-only slug, and - the hardcoded DROID_ONLY literal is an exact match to the droid-only set derived from the origin/release/stable (v0.5.13) MODEL_OPTIONS_BY_PROVIDER. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Repointing migration 035 to its frozen snapshot changes the shipped migration dependency graph: severing the sole import of the live modelSelectionCompatibility removes the only bridge from migration history into @synara/contracts, so modelSelectionCompatibility and the entire contracts barrel legitimately leave the migration dependency closure while the frozen snapshot enters it. It also changes migration 035's own content (the import line). Bless exactly this delta with exact, path-and-blob-pinned, one-time audited allowances — not a general bypass and without advancing the release baseline or touching the protected release-tag manifest: - RELEASED_CONTENT_ALLOWANCES gains the 035 old→new blob pair. - RELEASED_DEPENDENCY_GRAPH_ALLOWANCES (new) pins 29 removed baseline blobs and the 1 added frozen-snapshot blob. Each allowance pins a Git blob, so the guard fails closed on any other change: editing the frozen snapshot voids its added-blob allowance, and a dependency that stays reachable but changes content is never blessed (that branch remains a hard violation). Violation messages now emit the exact allowance key so future audited deltas are self-documenting. Guard self-tests cover both content and removed/added graph suppression. This precise closure also unfreezes unrelated contract files (e.g. providerDiscovery.ts) that were only frozen transitively through the barrel, and lets model.ts add Opus 5 without editing shipped history. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update PR #123 onto current main (ecca291) so the migration-lineage guard and full suites re-run against the real base and the PR is truly mergeable. main did not touch the migration guard, migration 035, contracts/model.ts, or providerDiscovery.ts since the fork point, so the blob-pinned allowances remain valid; the incoming provider/catalog churn is re-verified below. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…60725 Catch up to current main so the branch is up-to-date (strict protection). The incoming commit touches only workspace filesystem code — orthogonal to this PR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ion/agent-gateway-queue-20260728
…ion/agent-gateway-queue-20260728
…28' into feature/scm-writing-pr-template-20260728
…scm-writing-pr-template-20260728
This was referenced Jul 28, 2026
Contributor
Author
|
Promotion completed at main commit c0fcbe1. Repository policy permits squash merges only; the promoted main tree exactly matches certified queue head 20846fa. CI run 30360920167 is fully green. Its initial Windows dependency prepare failure was retried only at the failed job; the retry passed installation plus all Windows process, provider runtime, private-state, backend lifecycle, packaged-startup, and release-staging coverage. The automatically deleted shadow branch was restored and synchronized at a594c4b; its tree exactly matches main and main is its ancestor. Incorporated source PRs #68, #123, #140, #141, #144, #146, and #149 are closed with provenance comments; source branches are preserved. |
yaacovcorcos
added a commit
that referenced
this pull request
Jul 28, 2026
* Route telemetry through ScientFactory gateway (#43) * Fix unsigned macOS release signatures (#44) * Add consent-aware desktop analytics (#47) * Fix Claude terminal auth and connection recovery (#52) * fix provider status refresh invariants * fix Claude auth recovery * Use direct OAuth for Grok sign-in (#53) * Use direct OAuth for Grok sign-in * Expose safe Grok OAuth browser fallback * Secure Scient state initialization (#48) * Secure Scient state initialization * Allow legacy migration state test * fix(security): harden private state files * test(security): lock private file boundaries * fix(security): reject unsafe private file nodes * Supervise the desktop backend lifecycle (#49) * Supervise the desktop backend lifecycle * fix(desktop): preserve backend lifecycle ownership * fix(desktop): replace semantically unready backends * fix(desktop): close backend lifecycle races * Supervise desktop connection recovery (#50) * Supervise desktop connection recovery * Isolate provider dialog browser fixtures * fix(desktop): bind activation readiness generation * fix(web): enforce single-owner connection recovery * style(web): format connection recovery * fix(web): satisfy connection transport types * fix(web): harden stream and terminal recovery * fix(web): fail closed on stuck stream cancellation * fix(web): preserve terminal recovery ordering * fix(web): clamp reconnect jitter ceilings * fix(desktop): preserve connection wake after restack * Define safe RPC recovery policies (#51) * Define safe RPC recovery policies * test(web): cover RPC recovery integration * fix(web): recover after uncertain mutation failures * test(web): type RPC recovery harness precisely * fix(web): recover a failed replay generation * Surface connection recovery diagnostics (#55) * Surface connection recovery diagnostics * test(web): cover connection recovery experience * style(web): format recovery browser coverage * fix(web): keep recovery diagnostics current * Recover Codex sessions after authentication loss (#56) * fix: recover Codex sessions after auth loss * fix(codex): gate auth recovery by provider mode * fix: harden Codex authentication recovery * Support Linux desktop development launch (#57) * Secure Scient state initialization * Allow legacy migration state test * Supervise the desktop backend lifecycle * Supervise desktop connection recovery * Define safe RPC recovery policies * Surface connection recovery diagnostics * Support Linux desktop development launch * Isolate provider dialog browser fixtures * fix(desktop): fail closed on unsafe Linux sandbox * style(desktop): format Linux launcher hardening * fix(release): preserve AppImage sandbox * revert(release): keep AppImage migration out of launcher hardening * fix(desktop): honor Linux user namespace sandbox * Fix Antigravity browser authentication (#59) * Fix Antigravity browser authentication * Harden Antigravity authentication lifecycle * Close Antigravity code window deterministically * Keep Antigravity code submission cancellable * Scope desktop signing credentials by platform (#60) * Fix managed Antigravity updates, authentication, and dialog UX (#62) * Fix trusted Antigravity install and update routing * Fix Antigravity browser authentication and models * Refine provider connection dialog actions * Harden managed provider update recovery * Stabilize macOS release identity (#63) * Reduce unintended macOS permission prompts (#64) * Stabilize macOS release identity * Reduce unintended macOS permission prompts * Apply repository formatting * Control macOS notarization lifecycle (#65) * Add Evidence to Note as a latent built-in (#70) * Harden bidirectional chat rendering (#71) * feat(web): harden bidirectional chat rendering * fix(web): close bidi review gaps * Add Medical Exam Study built-in (#72) * Fix YAML frontmatter in Markdown previews (#69) * Add T3-inspired project source dialog (#76) * Add project source dialog * Harden project source cloning * Add T3-style right dock surfaces (#77) * Add T3-style right dock surfaces * Fix right dock test formatting * fix: remove AppSnap startup announcement (#80) * Add artifact preview cards to chat (#81) * fix: select providers after connection (#82) * Add message-level conversation forks (#78) * Add message-level conversation forks * Stabilize hosted fork browser test * Close message fork boundary gaps * Close final fork review gaps * Resolve final fork recertification blockers * Avoid replaying completed fork bootstrap * Harden fork lineage and restart recovery * Stabilize cold browser geometry startup * Repair legacy fork title families * Preserve unrecorded fork rename boundaries * Clear drifted fork title lineage * Improve desktop contribution workflow (#75) * Set default base font to 15px and fix numeric editing (#79) * Increase default base font size to 15px * Fix manual font size editing * Preserve external font setting updates * Use recommended provider model defaults (#83) * Use recommended provider model defaults * Apply repository formatting * Update browser expectation for Codex default * Preserve explicit drafts before model discovery * Respect live provider model availability * Align desktop approval policy (#85) * Fix release-candidate regressions (#86) * Fix release candidate regressions * Fix long transcript fork validation * fix(release): preserve Linux sandbox (#87) * fix(release): preserve Linux sandbox * test(release): resolve nested builder package * test(release): follow Bun package symlinks * fix: preserve whitespace in folder browsing (#90) * Collapse long assistant artifact shelves (#91) * Remove project setup confirmation card (#93) * Build unified notification system (#96) * Hide provider setup banner on empty chats (#94) * Hide provider setup banner on empty chats * Stabilize empty provider banner coverage * Harden provider banner browser readiness * Fix Droid model discovery lifecycle (#95) * Add ChatGPT-first voice transcription with local Whisper fallback (#97) * feat(voice): define transcription backend contract * feat(voice): add verified local transcription core * Fix ChatGPT voice account context * feat(voice): add ChatGPT-first local Whisper fallback * Default Git writing to GPT-5.6 Luna (#99) * Apply updated settings defaults once (#101) * Apply updated settings defaults once * Enable Studio in its browser fixture * Improve voice dictation and active-turn composer controls (#102) * Improve voice recording controls * Add live local voice previews * Keep voice send locked through completion * Keep active-turn composer actions available * Pin Whisper runtime source revision * Fix voice transition regressions * Fix folder picker navigation and project opening (#98) * Fix folder picker navigation and project opening * Tighten project setup choices * Prevent duplicate folder picker submissions * Fix Whisper runtime packaging on Windows (#104) * fix: make Whisper packaging cross-platform safe * fix: verify signed Windows Whisper runtime * Secure HTML artifact previews with isolated execution (#100) * feat: add secure HTML artifact previews * fix: enforce HTML preview ownership boundaries * Document cross-platform manual verification * Use trash icon for voice cancel action (#106) * Fix browser pane close and runtime recovery (#113) * Isolate temporary Claude discovery from MCP servers (#116) * Respect reduced motion in thread spinner (#84) Adapt the upstream accessibility concept while retaining Scient-owned spinner geometry. * Harden upstream-derived release tooling (#109) * Salvage safe PR 61 interaction improvements (#107) * Salvage safe PR 61 interaction improvements * Harden terminal selection copy handling * Adapt Studio Git gating and folder access (#108) * Adapt Studio folder controls from Synara * Gate Studio review command on repository detection * Improve changed-file accessibility and density (#110) * Add compact previews for bulky changed-file cards (#117) * Improve changed-file accessibility and density * Add compact changed-file previews * Ensure changed-file previews show every file * feat: add curated in-app release notes (#112) * feat: add curated release notes workflow * fix: harden release note experience * refactor: share release note footer layout * test: keep release note diagnostics concise * Reject developer-facing release note copy * Revert "Reject developer-facing release note copy" This reverts commit 1006003. * Harden release note structural validation * Harden release note asset validation * Resolve release note certification findings * Bound release note PNG chunk parsing * Validate all release note PNG chunk CRCs * Fix browser multi-tab controls and menu occlusion (#119) * Fix browser multi-tab controls and menu occlusion * Keep browser sessions alive under overlays * Harden browser overlay lifecycle coverage * Complete browser tab and overlay semantics * Restore focus after final browser tab closes * Synchronize split-pane browser focus * Harden Electron overlay lifecycle runner * Isolate macOS Electron test bundle state * Keep Electron lifecycle tests fully hermetic * Resolve Electron sandbox from workspace package * Guarantee Electron test harness cleanup * Register Electron fixture cleanup immediately * Restore focus after browser close controls * Complete browser close focus recovery * Handle early Electron test interruptions * Cover earliest Electron setup interruption * Refine branch and automation workflow affordances (#111) * Refine upstream-derived workflow affordances * Respect resolved automation triage state * Fix native branch clipboard acceptance * Document native workflow UX acceptance * Add universal local file viewer (#114) * Add universal local file viewer * Harden local HTML preview capabilities * Resolve HTML preview review blockers * Close final HTML preview review gaps * Fail closed on truncated active HTML * Preserve complex HTML preview dependencies * Fail closed on SVG runtime link mutation * Block alternate network egress in HTML previews * Recover HTML preview network setup * Serialize HTML preview retries * Occlude native HTML previews under overlays * Harden provider installation and sign-in (#103) * Harden provider installation and sign-in * Fix Windows provider runtime test fixtures * Make Windows PATH test path-stable * Close provider onboarding reliability gaps * Keep post-install sign-in recovery on the correct path * Canonicalize Windows runtime discovery test paths * Harden provider device-code recovery * Harden OpenCode and Kilo turn completion (#120) * Harden OpenCode and Kilo turn completion * fix(provider): isolate OpenCode turn completion ownership * fix(provider): close OpenCode completion review races * fix(provider): fence OpenCode reply and replay races * fix(provider): clean interrupted OpenCode replies * fix(provider): harden OpenCode interaction ownership * fix(provider): fail closed on ambiguous replies * Harden OpenCode lifecycle retirement * Serialize OpenCode session retirement * Make OpenCode retirement interruption safe * Finalize confirmed OpenCode process exits * Add native folder drop to Add Project (#115) * feat(projects): add native folder drop intake * fix(projects): harden folder drop feedback * fix(projects): keep folder errors visible * fix(projects): preserve compact folder dialog footer * fix(projects): harden native folder intake * docs(qa): align folder intake evidence * fix(projects): scope folder drop to dialog * test(projects): cover platform folder labels * docs: correct folder drop verification evidence * docs: qualify native drag evidence * docs: refresh folder drop verification evidence * docs: refresh folder drop certification evidence * docs: recertify folder drop on latest main * Neutralize project drops outside dialog * Update folder drop acceptance evidence * Make new thread workspace intent explicit (#118) * fix(web): make new thread workspace intent explicit * fix(web): serialize distinct new thread intents * test(web): type exact workspace branch mocks * fix(web): preserve new thread request ordering * fix(web): preserve latest new thread intent * fix(web): coordinate all new thread navigation * fix(web): preserve latest navigation across preparation * fix(web): close remaining navigation races * chore: clean merged sidebar imports * fix(web): close terminal and route ownership gaps * fix(web): coordinate every new-thread route intent * fix(web): enforce route ownership before history commits * test(web): use typed routes in navigation guard proof * fix(web): release committed navigation ownership * Show active file explorer toggle state (#124) * Prevent background Cursor login browser launches (#125) * Guard released migration lineage and dependencies (#129) Adds a fail-closed, read-only release guard for shipped migration history and reviewed runtime dependency resolution. * build(deps): bump actions/checkout from 7.0.0 to 7.0.1 (#131) Update every retained workflow use to the verified immutable v7.0.1 commit. * Bound settled attachment sync generations (#132) Retire settled generation markers while preserving stale-write suppression and prior pending ownership after synchronous staging failure. * Use lightweight snapshots for PR polling (#133) Adapt Synara PR polling on a Scient-owned project-only query seam. Preserve active-project filtering and schema normalization, prove live-layer wiring, and avoid hydrating unrelated thread/session/turn state. * Advance Synara review checkpoint to July 26 (#134) * chore(upstream): advance reviewed Synara checkpoint * chore(upstream): include late lifecycle review * Prove packaged macOS and Windows startup before release (#121) * test(release): prove packaged desktop startup * Close packaged startup proof gaps * Preserve packaged smoke isolation * Avoid duplicate Windows tree kills * Harden packaged smoke process cleanup * Harden packaged startup proof acceptance * Close packaged startup certification gaps * Close exact packaged startup proof gaps * Bound packaged smoke process cleanup * Harden packaged startup release proof * Close packaged startup review findings * Keep startup proof test lint-clean * fix(release): close packaged startup proof gaps * fix(release): harden packaged startup cleanup * fix(release): authenticate startup ownership records * fix(release): bind cleanup to process instances * fix(release): type cleanup authorities explicitly * fix(release): close final startup proof findings * fix(release): contain packaged startup by OS identity * fix(release): fail closed after sentinel loss * fix(release): close packaged cleanup containment gaps * fix(release): fail closed on startup cleanup uncertainty * fix(release): authenticate Windows startup verifier * ci(release): exercise Windows startup launcher * fix(release): close packaged startup proof gaps * fix(release): harden packaged startup certification * Fix packaged startup reconnect hydration * fix(release): bind packaged startup containment lifetime * fix(release): request sentinel cleanup over IPC * fix(release): bind Windows verifier authority to pipe * Bound repeated desktop backend crash restarts (#126) * fix(desktop): bound backend crash restarts Adapt the bounded supervision lessons from Synara commits 83b685234b2c474ea4d9a6ce593ac730ca95f8f7 and 5495a6e81e4da80e996867a1c487c9546cbd0196 onto Scient's existing generation-safe supervisor. Require post-readiness stability before resetting retry history, pause after repeated failures in a rolling window, and surface local log guidance without importing Synara's database-recovery architecture. * fix(desktop): make backend crash recovery actionable * fix(desktop): retain recovery dialog when logs fail * fix(desktop): preserve crash recovery guarantees * fix(desktop): suppress crash recovery while quitting * fix(desktop): harden crash recovery diagnostics * fix(desktop): preserve backend breaker through updater recovery * test(desktop): prove native crash-breaker recovery * fix(desktop): preserve crash-breaker recovery * fix(desktop): preserve crash history across updater recovery * test(desktop): prove updater crash recovery wiring * fix(desktop): preserve shutdown authority during updater failure * test(desktop): wait for native recovery accessibility * test(desktop): isolate crash recovery acceptance * test(desktop): bind recovery fixture process identity * fix(desktop): retain quit authority during update handoff * fix(desktop): restart after failed updater stop * Keep diff mode and Git status refresh responsive (#127) * fix(web): keep diff and git status refresh responsive Adapted from Synara 807acfe3c784b41229b81c4b78957681ec8e6cb2. Remount the third-party diff renderer when its mount-time view mode changes, use the shared menu radio primitive, and prevent branch-discovery races or non-repo workspaces from starting a permanent Git-status invalidation loop. Add focused regression coverage for each boundary. * fix(web): ignore stale Git status before repository confirmation * fix(web): require exact branch status for git actions * fix(git): preserve branch authority across actions * fix(git): serialize repository mutations * fix(git): cover repository mutation workflows * style(server): apply repository formatting * fix(git): isolate live mutation authority contracts * fix(git): overlay live mutation RPC authority * test(web): align stacked action transport contract * Keep local HTML previews live across source changes (#130) * fix(desktop): keep local HTML previews live * fix(desktop): harden live preview refresh * fix(web): clear stale HTML preview errors * fix(web): report queued preview refresh failures * fix(desktop): release retired preview session hooks * fix(browser): preserve refresh ownership and latest revision * fix(browser): close live preview certification gaps * fix(browser): close live preview review findings * fix(browser): close final live preview review findings * fix(browser): close exact-head preview review findings * test(browser): cover preview discovery limits * fix(browser): preserve optional preview limit metadata * test(browser): require prepared source authority * fix(browser): attest local preview capabilities * fix(html-preview): harden atomic refresh authority * fix(html-preview): close source watch startup gap * fix(desktop): close live preview review gaps * fix(desktop): close preview ownership failure gaps * fix(html-preview): close remaining security boundaries * fix(html-preview): pin inspected file versions * fix(html-preview): serve attested document bytes * Stop duplicating completed replies in Activity (#135) * Stop duplicating completed replies in Activity * Prove Activity completion ownership in Chromium * Synchronize completion regression assertions * Show fork provenance in conversation timelines (#136) * Show fork provenance in transcripts * Keep unavailable fork provenance truthful * Require confirmed provider updates (#137) Gate the Settings > Providers Update action behind a confirmed fresh version check, and harden the confirmed-update boundary so the updater child process only ever spawns against a probed, certified, and re-validated target (closes six concurrency/TOCTOU windows). See PR description for full details. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix oversized transcript–composer gap when a task panel is showing (#138) * Fix oversized transcript–composer gap when a task panel is showing The composer is a flex sibling below the transcript, so the stacked composer chrome (live-changes header, active task list, queued follow-ups) already reserves its own vertical space through the flex layout. The transcript then fed that same chrome height into its in-list bottom spacer (bottomContentInsetPx = composerStackedChromeHeight + 8), reserving the space a second time. The result was a large, growing gap between the last message and the composer whenever a task/stacked panel was present, while the no-task case (spacer at its 64px baseline) already looked correct. Remove the double reservation: the transcript's bottom spacer is now a fixed 64px in every state, matching the perfect no-task gap. This also retires the now-vestigial bottomContentInsetPx prop chain (ChatView → ChatTranscriptPane → MessagesTimeline / AgentActivityDetailView), collapsing both consumers to their constant baseline and correcting the misleading "composer overlaps / reserves matching bottom space" comments. composerStackedChromeHeight is kept for its real remaining job: the scroll-compensation layout effect that keeps the transcript pinned to its end as the flex viewport shrinks while the chrome grows. - Task-present gap now equals the no-task gap (single flex reservation). - Agent activity detail view uses the same fixed baseline (it was also double-counting). - No behavior change to the no-task case. Verified: oxfmt, oxlint (0 errors), tsc --noEmit (web), and the affected component/scroll unit tests (106 passing). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add regression coverage for the transcript–composer gap fix Prove the stacked composer chrome is reserved only once: a [geometry:linux] browser test mounts ChatView with an active task card and again once the turn settles (no card), then asserts the gap between the transcript tail and the composer stack is unchanged. It anchors on the tail spacer's top (the true end of transcript content, past any live-turn activity indicator) so a running turn does not confound the measurement. Verified the test fails on the pre-fix code — the gap balloons to ~180px when the task card appears — and passes on the fix (~44px in both states). Adds two stable test hooks: data-chat-composer-stack on the composer block wrapper and data-testid="transcript-bottom-spacer" on the list tail spacer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Fix file links failing to open across git worktrees (#139) * fix(server): resolve workspace file links across git worktrees Bare/partial file references (e.g. a chat link to `kanbanDispatch.ts`) could fail to open with a misleading "no such file" error even though the file plainly exists. Two root causes: 1. The filesystem-walk index descended into linked git worktrees, so a single logical file was indexed multiple times (the real checkout plus each worktree copy). The suffix resolver treats multiple matches as ambiguous and gave up, and the read then surfaced the realpath ENOENT for the literal (non-existent) path. Indexing the duplicates also inflated the index toward its 25k-entry cap, truncating it. 2. On a genuine ambiguity the resolver returned null, which the reader reported as ENOENT -- a "file not found" message for a file that exists. Changes (server-only): - Prune linked git worktree subtrees from the index walk (a worktree records `.git` as a regular file pointer, the reliable discriminator), and skip `.git` entries whether file or directory. Extract the shared worktree/skip predicates. - Rework resolveWorkspaceFileBySuffix to return a structured result (resolved | ambiguous | unresolved). Resolve only on a single distinct match; report the competing paths on a true ambiguity instead of guessing between different files. - When the cached index is truncated (unreliable), re-scan the tree directly (bounded) for a trustworthy candidate set. - Surface an honest, actionable error listing the competing files instead of a false ENOENT. Reuses the existing WorkspaceFileSystemError tag, so no contract/client change. Tests: worktree pruning, unique/ambiguous/unresolved resolution, the worktree-duplicate scenario end-to-end, and the truncated-index disk re-scan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(server): don't prune submodules; fail closed on incomplete suffix scan Follow-up correctness fixes to the worktree-aware file-link resolution. 1. Submodule false-prune. The worktree detector treated *any* directory whose `.git` is a regular file as a linked worktree and pruned it. Git submodules also store `.git` as a file, so their subtrees were pruned too -- silently hiding submodule files from search and link resolution. Discriminate by the `gitdir:` pointer target: prune only when it points into `.git/worktrees/<name>` (a linked worktree), never when it points into `.git/modules/<name>` (a submodule). Reading the pointer fails open (do not prune) so an unreadable `.git` can never hide real files. 2. Incomplete-scan false-unique. The bounded disk re-scan (used when the index is truncated) returned whatever it had found when it hit the scanned-directory cap. A single match found before the cap was then reported as a unique "resolved" even though a second match could sit in the unscanned remainder -- risking opening the wrong file. The scan now reports whether it completed, and classification fails closed to a new "indeterminate" outcome when an incomplete scan saw fewer than two matches. The reader surfaces an honest "too large to resolve, use a fuller path" error instead of guessing or falsely claiming ENOENT. Tests: submodule files stay resolvable and searchable (not pruned); the disk scan reports incomplete at its directory cap; classification fails closed (single match from an incomplete scan -> indeterminate, two distinct matches -> ambiguous even when incomplete, empty complete scan -> unresolved). The existing linked-worktree fixtures now use realistic `.git/worktrees/<name>` pointer contents. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(web): guard Enter during IME composition in message composers (#143) CJK/Japanese/Korean IMEs use Enter to confirm a candidate. An unguarded Enter-to-send handler treats that confirmation keystroke as "send" and submits a half-composed message. Add a shared isImeCompositionKeyEvent() helper (isComposing || keyCode === 229) and apply it at the two message-composer key handlers: - ComposerCommandKeyPlugin, the shared chat + kanban Lexical handler: swallow Enter fired mid-composition before it reaches the send/menu logic. Lexical already drops keydowns while editor.isComposing() is true, but on Safari/WebKit compositionend fires before the confirming keydown, so that Enter still dispatches KEY_ENTER_COMMAND; the keyCode === 229 branch closes that gap. - PullRequestCommentComposer, a plain <textarea> with no Lexical gate, replacing its isComposing-only check so a keyCode-229 confirm no longer submits. Value: correct multi-language text entry; no accidental send on IME candidate confirmation. Out of scope (follow-up): other bare-Enter inputs (project/rename/search fields) share the hazard and could adopt the same helper. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * feat(web): self-host UI fonts, drop Google Fonts CDN (#142) Remove the runtime Google Fonts <link> from index.html and self-host the needed families (Geist, Geist Mono, Inter) via @fontsource-variable/* packages, alongside the JetBrains Mono face already bundled. DM Sans was listed in the CDN link but has zero references, so it is dropped rather than self-hosted. The @fontsource-variable packages register their @font-face under a "<Family> Variable" name (e.g. "Inter Variable") while themes store the plain family name, so add expandBundledVariableFontAliases() and apply it at the theme->CSS-variable emission boundary: the bundled face is matched and the plain name is kept after it as a fallback. Value: offline usability, no third-party font beacon on launch, no font flicker. The default appearance (systemUiFont + JetBrains Mono fallback) needs no Google fonts, so removing the CDN cannot regress it. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Make new-chat project selection safe across draft and project lifecycles Integrate the reviewed project-picker interaction and project-lifecycle safety fixes. Complete local certification, three independent final reviews, hosted CI, and manual native visual acceptance passed. * fix(desktop): preserve Windows Ctrl-minus zoom (#148) * fix: preserve Windows Ctrl-minus zoom Adapted from Synara 94b59220e26bc337406110c84220aec76b065490. * fix: preserve shortcuts help chord compatibility Keep the Windows physical-minus disambiguation scoped to Windows while retaining the existing Meta-or-Ctrl slash behavior on every platform. * fix: align Windows minus shortcut routing * Promote certified desktop integration queue (#154) Promotes the certified July 28 desktop integration queue. Includes the reviewed work represented by PRs #123, #140, #141, #144, #149, #150, and aligned replacement #151 for #146. Supersedes #68 through the hardened #144 implementation. See PR #154 for exact heads, dispositions, verification, limitations, and rollback evidence. * Promote certified desktop queue + v0.5.14 release note into main (#155) * Add Claude Opus 5 capabilities * Harden Claude capability discovery and Opus gating * Refresh Claude discovery results * Fail closed on Claude capability boundaries * Scope Claude discovery to the exact runtime * Bind Claude Opus 5 to the exact runtime * Harden Claude Opus 5 runtime gating * Keep Claude fresh defaults available * fix(claude): isolate discovery lifecycle generations * fix(claude): bind discovery cache generations * test(web): bind Claude prefetch generation keys * fix(claude): authorize Opus 5 from exact runtime * fix(claude): make discovery generations monotonic * Fix provider runtime extraction and setup progress * fix(claude): harden discovery lifecycle ownership * fix(claude): generation-key native slash-command discovery Native slash-command discovery now participates in the same renderer-owned discovery-generation scheme already used for model and agent discovery, so a command catalog fetched under one auth/runtime generation can never leak into a newer one. - contracts: add optional discoveryGeneration to ProviderListCommandsInput - server: fold discoveryGeneration into the listCommands in-flight cache key so a later auth generation never joins an older CLI's discovery - client: bind the commands query to the current generation (query key, RPC arg, post-resolve stale discard, fail-fast retry, no stale placeholder for claudeAgent) and invalidate commands alongside agents on auth-sensitive provider changes - route the configured Claude binary through every command-discovery call site (ChatView, kanban composer, /fast availability check) - tests: cover generation separation for command discovery on both the server adapter and the React Query layer Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(agent-gateway): host-served MCP read/coordination tools (Slice 1) First slice of the agent gateway: a thread-scoped, host-served MCP endpoint (`POST /mcp`) that lets an agent in one thread observe and coordinate sibling top-level threads. Read/coordination only — no send/interrupt, no create/fork. Behind a feature flag, disabled by default (`SYNARA_AGENT_GATEWAY_ENABLED` / `--agent-gateway-enabled`). Lift-and-reconcile of Synara's MIT-licensed agent gateway onto a Scient-owned authorization + credential spine. `synara_*` names and `synara/` namespaces kept intentionally (rebrand is a later pass). New `apps/server/src/agentGateway/` subsystem: - Transport/ingress auth: per-request bearer verify → thread-existence recheck → provider-ownership recheck → central authorization, with no cached grant; body cap (1 MiB) + batch cap (50); GET/DELETE mirror the disabled-state 404; top-level defect net upholds the never-fails contract on handleMcpPost. - Credential spine: opaque per-thread tokens, in-memory registry (dies on restart), least-privilege (`thread:read` only), revoke-on-teardown. - Central default-deny authorization: capability → project scope → thread-type; cross-project reads denied as thread_not_found. - Read tools: synara_context, list_projects, list_threads, read_thread, wait_for_threads, backed by ProjectionSnapshotQuery. - Claude provider injection via HTTP Authorization header (never the process env), flag-gated, revoked on teardown and failed install. Shared-file injection hand-re-applied at current symbol anchors: http.ts route registration, config.ts/main.ts flag, effectServer.ts bound-port publish, ClaudeAdapter.ts/runtimeLayer.ts token lifecycle, new packages/contracts/src/agentGateway.ts. typecheck 9/9, full test suite 12/12 (agentGateway 168/12 incl. new httpRoute.test.ts), lint 0 errors, brand:check green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(agent-gateway): keep contracts barrel frozen + format Slice 1 files Resolves the two CI failures on this PR: 1. migration:check — Slice 1 added `export * from "./agentGateway"` to `packages/contracts/src/index.ts`. That barrel is a released-migration dependency (released migrations import `@synara/contracts`, and the lineage guard traverses the barrel's re-exports and fingerprints its runtime source). Adding the line both *modified* the frozen barrel and *pulled* `agentGateway.ts` into the released dependency closure, tripping the append-only guard. Fix: relocate the gateway contract into the server subsystem as `apps/server/src/agentGateway/contract.ts` and drop it from the barrel. Every consumer is server-side (no renderer/client consumer exists), so the shared package was never required. `index.ts` is restored byte-for- byte to the v0.5.13 baseline and `agentGateway.ts` leaves the closure. 2. fmt:check — donor-lifted test files and the ClaudeAdapter edits were not run through oxfmt. Applied `oxfmt` (formatting only; no behavior change). Full gate green: brand, workflow, migration, fmt, lint (0 errors), typecheck (9/9), test (12/12 packages, 2530 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(agent-gateway): close read_thread disclosure oracle + revoke token on failed spawn Two pre-merge security fixes on the Slice 1 read foundation, plus a truthful token-exposure comment. 1. read_thread non-disclosure oracle. An unknown thread failed as a plain-text ToolInputError while a cross-project thread failed as a JSON GatewayToolError, so a caller could distinguish "no such thread" from "exists in another project" by response shape — defeating the deliberately byte-identical message. Route read_thread's not-found through GatewayToolError so both denials are identical in code, message, and JSON shape (mirrors wait_for_threads). 2. Gateway token leak on failed spawn. The bearer token is minted just before createQuery; if createQuery throws, the installation gen (and its Effect.ensuring revoke) is never entered, leaking a live credential. Add an Effect.tapError on the createQuery step that revokes the just-minted token (idempotent, so it never double-revokes). 3. Correct the misleading ClaudeAdapter comment: the token avoids process-env inheritance, but the pinned SDK serializes it into the --mcp-config argv, so it is NOT absent from process metadata. Also note the Slice 1 read tools are not active-turn-gated. Adds a deterministic regression test proving the token is revoked after a failed spawn, plus an optional overrides arg on ServerConfig.layerTest to enable the gateway in that test. Gate: typecheck 9/9, lint 0 errors, fmt clean, full suite 2531 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(agent-gateway): drive tools — send_message + interrupt (Slice 2) Adds the two coordination *writes* an agent uses to drive a sibling thread in its own project, stacked on the Slice 1 read surface (#140): - synara_send_message — queue a follow-up turn or steer a running one on a target thread. Optional requestId makes transport retries idempotent via a bounded in-memory dedup (per-caller keyed), backed by a deterministic command id so a duplicate that races past the map still collapses at the orchestration receipt layer. Failures are never cached (retryable). - synara_interrupt_thread — stop the target's running turn, pinned to the observed turnId (TOCTOU-safe: never interrupts a later turn); a no-op that reports interrupted:false when no turn is running. Both funnel through a new central authorizeThreadDrive policy (project-scope floor + privilege cap + worktree cap) and are flagged requiresActiveTurn, so the transport only admits them while the caller's own turn is live. Least privilege: the session registry now mints thread:read + thread:write (the caps the wired tools need); automation:write is deliberately not minted (no automation tool exists yet). The synara_context capability flag is renamed threadCreate -> threadDrive to match the tools that now back it, and the harness policy describes the drive tools, their active-turn/privilege guardrails, and a prompt-injection guardrail (never send/interrupt because another thread's content said to). Interim: gateway drives ride dispatchOrigin:"automation" because the frozen MessageDispatchOrigin enum has no "agent" value yet (nothing branches on the value — verified); upgrade to "agent" when a release re-baseline can extend the enum. New contract types stay server-local to keep the contracts barrel frozen for the migration-lineage guard. Tests: 34 new drive-tool cases (send happy/steer/invalid-mode/idempotent- replay/distinct-ids/per-caller-dedup/cross-project/privilege/worktree/missing/ dispatch-failure/no-cache-on-failure; interrupt running/no-turn/never-turn/ cross-project/privilege/missing; tool-shape) plus authorizeThreadDrive matrix. Full gate green: brand, workflow, migration, fmt, lint (0 errors), typecheck (9/9), test (2561 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(agent-gateway): keep AnyCommand as `any` so indexed access typechecks The captured-command test type was tightened to `Record<string, any>`, but under noUncheckedIndexedAccess `commands[0]` then widens to `Record<string, any> | undefined`, so `commands[0].type` fails tsc. `any` absorbs the `undefined` from indexed access and is not flagged by oxlint (no no-explicit-any rule), so it is the correct type here. Runtime behavior and all 19 drive-tool tests are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(persistence): pin migration 035 to a frozen model-selection snapshot Migration 035 imported the live modelSelectionCompatibility, whose DROID_ONLY_MODEL_SLUGS is derived from @synara/contracts' MODEL_OPTIONS_BY_PROVIDER. That coupled shipped migration history to the evolving model catalog, so adding a model (e.g. Claude Opus 5) to model.ts tripped the append-only migration-lineage guard through the contracts barrel. Give migration 035 its own self-contained frozen v0.5.13 snapshot (migration035FrozenModelSelectionCompatibility) with the DROID_ONLY set hardcoded as the exact v0.5.13 catalog-derived literal, and repoint the migration's import to it. All other normalization logic is byte-identical to the live helper; the live helper stays in place for its runtime consumers. The snapshot is proven behaviorally identical to the v0.5.13 migration: - an equivalence test asserts frozen ≡ live across a persisted corpus that spans every branch (canonical, provider-less ambiguous slugs incl. claude-opus-5, instance-label inference, legacy Gemini, option-row arrays, provider-scoped options) and every catalog Droid-only slug, and - the hardcoded DROID_ONLY literal is an exact match to the droid-only set derived from the origin/release/stable (v0.5.13) MODEL_OPTIONS_BY_PROVIDER. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(migration-guard): audited one-time allowance for the 035 decouple Repointing migration 035 to its frozen snapshot changes the shipped migration dependency graph: severing the sole import of the live modelSelectionCompatibility removes the only bridge from migration history into @synara/contracts, so modelSelectionCompatibility and the entire contracts barrel legitimately leave the migration dependency closure while the frozen snapshot enters it. It also changes migration 035's own content (the import line). Bless exactly this delta with exact, path-and-blob-pinned, one-time audited allowances — not a general bypass and without advancing the release baseline or touching the protected release-tag manifest: - RELEASED_CONTENT_ALLOWANCES gains the 035 old→new blob pair. - RELEASED_DEPENDENCY_GRAPH_ALLOWANCES (new) pins 29 removed baseline blobs and the 1 added frozen-snapshot blob. Each allowance pins a Git blob, so the guard fails closed on any other change: editing the frozen snapshot voids its added-blob allowance, and a dependency that stays reachable but changes content is never blessed (that branch remains a hard violation). Violation messages now emit the exact allowance key so future audited deltas are self-documenting. Guard self-tests cover both content and removed/added graph suppression. This precise closure also unfreezes unrelated contract files (e.g. providerDiscovery.ts) that were only frozen transitively through the barrel, and lets model.ts add Opus 5 without editing shipped history. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(providers): add safe sign-out controls * fix(providers): close review gaps * fix(providers): polish status accessibility * fix(providers): preserve released contract lineage * fix(providers): use native sign-out confirmation * Fix Claude discovery generation isolation * Fix Claude model discovery without init event * perf(git): fetch compact diff scope stats Adapt the server-side working-tree diff statistics lane from Synara b3fc978308b30342694c06f651dc42762fd04552. Preserve selected-scope patch rendering while replacing picker-wide patch transfers and renderer parsing with compact totals. Donor license: MIT. Scient's existing LICENSE carries the applicable Emanuele Di Pietro copyright and MIT notice. * fix(diff): keep selected scope count current * fix(diff): move stats RPC outside released contracts * fix: enforce provider archive extraction limits * fix(web): close project actions before editing * test(web): cover project action focus handoff * feat(git): discover committed PR templates safely * fix(server): harden agent gateway session boundaries * fix(server): close agent gateway review gaps * fix(server): bind gateway limits to session lifecycle * fix(agent-gateway): preserve honest message provenance * fix(orchestration): retain agent dispatch provenance * fix(git): honor GitHub PR template variants * fix(git): require canonical PR template names * fix(git): require dotted template extensions * Add governed source-control writing (#153) Integrates the reviewed SCM writing policy into the certified desktop queue. Exact source head 13f933d passed focused and full verification plus three independent final reviews with no remaining P0-P3 findings. See PR #153 for credential, provider-isolation, provenance, rollback, and limitation evidence. * Add floating browser preview (#152) Integrate the reviewed floating browser preview into the desktop shadow queue. Exact candidate c8cb572 was certified against queue base 3f7ef52 with green hosted CI, real Electron acceptance, and three independent final reviews with no unresolved P0-P2 findings. * docs(release): add Scient v0.5.14 in-app release note Adds the required Scient-owned v0.5.14 entry to the in-app "What's new" catalog. Highlights the two new user-facing capabilities in this release (floating browser preview and source-control writing help) plus the verified refinements shipped since v0.5.13. Text-only; no artwork added. Verified locally: release:notes:check 0.5.14, brand:check, fmt:check, lint (0 errors), whatsNew logic tests (14), verify-release-notes tests (12), web typecheck. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Scient Release Engineer <yaacov.corcos@datavant.com> --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Scient Release Engineer <yaacov.corcos@datavant.com>
yaacovcorcos
added a commit
that referenced
this pull request
Jul 28, 2026
) * Route telemetry through ScientFactory gateway (#43) * Fix unsigned macOS release signatures (#44) * Add consent-aware desktop analytics (#47) * Fix Claude terminal auth and connection recovery (#52) * fix provider status refresh invariants * fix Claude auth recovery * Use direct OAuth for Grok sign-in (#53) * Use direct OAuth for Grok sign-in * Expose safe Grok OAuth browser fallback * Secure Scient state initialization (#48) * Secure Scient state initialization * Allow legacy migration state test * fix(security): harden private state files * test(security): lock private file boundaries * fix(security): reject unsafe private file nodes * Supervise the desktop backend lifecycle (#49) * Supervise the desktop backend lifecycle * fix(desktop): preserve backend lifecycle ownership * fix(desktop): replace semantically unready backends * fix(desktop): close backend lifecycle races * Supervise desktop connection recovery (#50) * Supervise desktop connection recovery * Isolate provider dialog browser fixtures * fix(desktop): bind activation readiness generation * fix(web): enforce single-owner connection recovery * style(web): format connection recovery * fix(web): satisfy connection transport types * fix(web): harden stream and terminal recovery * fix(web): fail closed on stuck stream cancellation * fix(web): preserve terminal recovery ordering * fix(web): clamp reconnect jitter ceilings * fix(desktop): preserve connection wake after restack * Define safe RPC recovery policies (#51) * Define safe RPC recovery policies * test(web): cover RPC recovery integration * fix(web): recover after uncertain mutation failures * test(web): type RPC recovery harness precisely * fix(web): recover a failed replay generation * Surface connection recovery diagnostics (#55) * Surface connection recovery diagnostics * test(web): cover connection recovery experience * style(web): format recovery browser coverage * fix(web): keep recovery diagnostics current * Recover Codex sessions after authentication loss (#56) * fix: recover Codex sessions after auth loss * fix(codex): gate auth recovery by provider mode * fix: harden Codex authentication recovery * Support Linux desktop development launch (#57) * Secure Scient state initialization * Allow legacy migration state test * Supervise the desktop backend lifecycle * Supervise desktop connection recovery * Define safe RPC recovery policies * Surface connection recovery diagnostics * Support Linux desktop development launch * Isolate provider dialog browser fixtures * fix(desktop): fail closed on unsafe Linux sandbox * style(desktop): format Linux launcher hardening * fix(release): preserve AppImage sandbox * revert(release): keep AppImage migration out of launcher hardening * fix(desktop): honor Linux user namespace sandbox * Fix Antigravity browser authentication (#59) * Fix Antigravity browser authentication * Harden Antigravity authentication lifecycle * Close Antigravity code window deterministically * Keep Antigravity code submission cancellable * Scope desktop signing credentials by platform (#60) * Fix managed Antigravity updates, authentication, and dialog UX (#62) * Fix trusted Antigravity install and update routing * Fix Antigravity browser authentication and models * Refine provider connection dialog actions * Harden managed provider update recovery * Stabilize macOS release identity (#63) * Reduce unintended macOS permission prompts (#64) * Stabilize macOS release identity * Reduce unintended macOS permission prompts * Apply repository formatting * Control macOS notarization lifecycle (#65) * Add Evidence to Note as a latent built-in (#70) * Harden bidirectional chat rendering (#71) * feat(web): harden bidirectional chat rendering * fix(web): close bidi review gaps * Add Medical Exam Study built-in (#72) * Fix YAML frontmatter in Markdown previews (#69) * Add T3-inspired project source dialog (#76) * Add project source dialog * Harden project source cloning * Add T3-style right dock surfaces (#77) * Add T3-style right dock surfaces * Fix right dock test formatting * fix: remove AppSnap startup announcement (#80) * Add artifact preview cards to chat (#81) * fix: select providers after connection (#82) * Add message-level conversation forks (#78) * Add message-level conversation forks * Stabilize hosted fork browser test * Close message fork boundary gaps * Close final fork review gaps * Resolve final fork recertification blockers * Avoid replaying completed fork bootstrap * Harden fork lineage and restart recovery * Stabilize cold browser geometry startup * Repair legacy fork title families * Preserve unrecorded fork rename boundaries * Clear drifted fork title lineage * Improve desktop contribution workflow (#75) * Set default base font to 15px and fix numeric editing (#79) * Increase default base font size to 15px * Fix manual font size editing * Preserve external font setting updates * Use recommended provider model defaults (#83) * Use recommended provider model defaults * Apply repository formatting * Update browser expectation for Codex default * Preserve explicit drafts before model discovery * Respect live provider model availability * Align desktop approval policy (#85) * Fix release-candidate regressions (#86) * Fix release candidate regressions * Fix long transcript fork validation * fix(release): preserve Linux sandbox (#87) * fix(release): preserve Linux sandbox * test(release): resolve nested builder package * test(release): follow Bun package symlinks * fix: preserve whitespace in folder browsing (#90) * Collapse long assistant artifact shelves (#91) * Remove project setup confirmation card (#93) * Build unified notification system (#96) * Hide provider setup banner on empty chats (#94) * Hide provider setup banner on empty chats * Stabilize empty provider banner coverage * Harden provider banner browser readiness * Fix Droid model discovery lifecycle (#95) * Add ChatGPT-first voice transcription with local Whisper fallback (#97) * feat(voice): define transcription backend contract * feat(voice): add verified local transcription core * Fix ChatGPT voice account context * feat(voice): add ChatGPT-first local Whisper fallback * Default Git writing to GPT-5.6 Luna (#99) * Apply updated settings defaults once (#101) * Apply updated settings defaults once * Enable Studio in its browser fixture * Improve voice dictation and active-turn composer controls (#102) * Improve voice recording controls * Add live local voice previews * Keep voice send locked through completion * Keep active-turn composer actions available * Pin Whisper runtime source revision * Fix voice transition regressions * Fix folder picker navigation and project opening (#98) * Fix folder picker navigation and project opening * Tighten project setup choices * Prevent duplicate folder picker submissions * Fix Whisper runtime packaging on Windows (#104) * fix: make Whisper packaging cross-platform safe * fix: verify signed Windows Whisper runtime * Secure HTML artifact previews with isolated execution (#100) * feat: add secure HTML artifact previews * fix: enforce HTML preview ownership boundaries * Document cross-platform manual verification * Use trash icon for voice cancel action (#106) * Fix browser pane close and runtime recovery (#113) * Isolate temporary Claude discovery from MCP servers (#116) * Respect reduced motion in thread spinner (#84) Adapt the upstream accessibility concept while retaining Scient-owned spinner geometry. * Harden upstream-derived release tooling (#109) * Salvage safe PR 61 interaction improvements (#107) * Salvage safe PR 61 interaction improvements * Harden terminal selection copy handling * Adapt Studio Git gating and folder access (#108) * Adapt Studio folder controls from Synara * Gate Studio review command on repository detection * Improve changed-file accessibility and density (#110) * Add compact previews for bulky changed-file cards (#117) * Improve changed-file accessibility and density * Add compact changed-file previews * Ensure changed-file previews show every file * feat: add curated in-app release notes (#112) * feat: add curated release notes workflow * fix: harden release note experience * refactor: share release note footer layout * test: keep release note diagnostics concise * Reject developer-facing release note copy * Revert "Reject developer-facing release note copy" This reverts commit 1006003. * Harden release note structural validation * Harden release note asset validation * Resolve release note certification findings * Bound release note PNG chunk parsing * Validate all release note PNG chunk CRCs * Fix browser multi-tab controls and menu occlusion (#119) * Fix browser multi-tab controls and menu occlusion * Keep browser sessions alive under overlays * Harden browser overlay lifecycle coverage * Complete browser tab and overlay semantics * Restore focus after final browser tab closes * Synchronize split-pane browser focus * Harden Electron overlay lifecycle runner * Isolate macOS Electron test bundle state * Keep Electron lifecycle tests fully hermetic * Resolve Electron sandbox from workspace package * Guarantee Electron test harness cleanup * Register Electron fixture cleanup immediately * Restore focus after browser close controls * Complete browser close focus recovery * Handle early Electron test interruptions * Cover earliest Electron setup interruption * Refine branch and automation workflow affordances (#111) * Refine upstream-derived workflow affordances * Respect resolved automation triage state * Fix native branch clipboard acceptance * Document native workflow UX acceptance * Add universal local file viewer (#114) * Add universal local file viewer * Harden local HTML preview capabilities * Resolve HTML preview review blockers * Close final HTML preview review gaps * Fail closed on truncated active HTML * Preserve complex HTML preview dependencies * Fail closed on SVG runtime link mutation * Block alternate network egress in HTML previews * Recover HTML preview network setup * Serialize HTML preview retries * Occlude native HTML previews under overlays * Harden provider installation and sign-in (#103) * Harden provider installation and sign-in * Fix Windows provider runtime test fixtures * Make Windows PATH test path-stable * Close provider onboarding reliability gaps * Keep post-install sign-in recovery on the correct path * Canonicalize Windows runtime discovery test paths * Harden provider device-code recovery * Harden OpenCode and Kilo turn completion (#120) * Harden OpenCode and Kilo turn completion * fix(provider): isolate OpenCode turn completion ownership * fix(provider): close OpenCode completion review races * fix(provider): fence OpenCode reply and replay races * fix(provider): clean interrupted OpenCode replies * fix(provider): harden OpenCode interaction ownership * fix(provider): fail closed on ambiguous replies * Harden OpenCode lifecycle retirement * Serialize OpenCode session retirement * Make OpenCode retirement interruption safe * Finalize confirmed OpenCode process exits * Add native folder drop to Add Project (#115) * feat(projects): add native folder drop intake * fix(projects): harden folder drop feedback * fix(projects): keep folder errors visible * fix(projects): preserve compact folder dialog footer * fix(projects): harden native folder intake * docs(qa): align folder intake evidence * fix(projects): scope folder drop to dialog * test(projects): cover platform folder labels * docs: correct folder drop verification evidence * docs: qualify native drag evidence * docs: refresh folder drop verification evidence * docs: refresh folder drop certification evidence * docs: recertify folder drop on latest main * Neutralize project drops outside dialog * Update folder drop acceptance evidence * Make new thread workspace intent explicit (#118) * fix(web): make new thread workspace intent explicit * fix(web): serialize distinct new thread intents * test(web): type exact workspace branch mocks * fix(web): preserve new thread request ordering * fix(web): preserve latest new thread intent * fix(web): coordinate all new thread navigation * fix(web): preserve latest navigation across preparation * fix(web): close remaining navigation races * chore: clean merged sidebar imports * fix(web): close terminal and route ownership gaps * fix(web): coordinate every new-thread route intent * fix(web): enforce route ownership before history commits * test(web): use typed routes in navigation guard proof * fix(web): release committed navigation ownership * Show active file explorer toggle state (#124) * Prevent background Cursor login browser launches (#125) * Guard released migration lineage and dependencies (#129) Adds a fail-closed, read-only release guard for shipped migration history and reviewed runtime dependency resolution. * build(deps): bump actions/checkout from 7.0.0 to 7.0.1 (#131) Update every retained workflow use to the verified immutable v7.0.1 commit. * Bound settled attachment sync generations (#132) Retire settled generation markers while preserving stale-write suppression and prior pending ownership after synchronous staging failure. * Use lightweight snapshots for PR polling (#133) Adapt Synara PR polling on a Scient-owned project-only query seam. Preserve active-project filtering and schema normalization, prove live-layer wiring, and avoid hydrating unrelated thread/session/turn state. * Advance Synara review checkpoint to July 26 (#134) * chore(upstream): advance reviewed Synara checkpoint * chore(upstream): include late lifecycle review * Prove packaged macOS and Windows startup before release (#121) * test(release): prove packaged desktop startup * Close packaged startup proof gaps * Preserve packaged smoke isolation * Avoid duplicate Windows tree kills * Harden packaged smoke process cleanup * Harden packaged startup proof acceptance * Close packaged startup certification gaps * Close exact packaged startup proof gaps * Bound packaged smoke process cleanup * Harden packaged startup release proof * Close packaged startup review findings * Keep startup proof test lint-clean * fix(release): close packaged startup proof gaps * fix(release): harden packaged startup cleanup * fix(release): authenticate startup ownership records * fix(release): bind cleanup to process instances * fix(release): type cleanup authorities explicitly * fix(release): close final startup proof findings * fix(release): contain packaged startup by OS identity * fix(release): fail closed after sentinel loss * fix(release): close packaged cleanup containment gaps * fix(release): fail closed on startup cleanup uncertainty * fix(release): authenticate Windows startup verifier * ci(release): exercise Windows startup launcher * fix(release): close packaged startup proof gaps * fix(release): harden packaged startup certification * Fix packaged startup reconnect hydration * fix(release): bind packaged startup containment lifetime * fix(release): request sentinel cleanup over IPC * fix(release): bind Windows verifier authority to pipe * Bound repeated desktop backend crash restarts (#126) * fix(desktop): bound backend crash restarts Adapt the bounded supervision lessons from Synara commits 83b685234b2c474ea4d9a6ce593ac730ca95f8f7 and 5495a6e81e4da80e996867a1c487c9546cbd0196 onto Scient's existing generation-safe supervisor. Require post-readiness stability before resetting retry history, pause after repeated failures in a rolling window, and surface local log guidance without importing Synara's database-recovery architecture. * fix(desktop): make backend crash recovery actionable * fix(desktop): retain recovery dialog when logs fail * fix(desktop): preserve crash recovery guarantees * fix(desktop): suppress crash recovery while quitting * fix(desktop): harden crash recovery diagnostics * fix(desktop): preserve backend breaker through updater recovery * test(desktop): prove native crash-breaker recovery * fix(desktop): preserve crash-breaker recovery * fix(desktop): preserve crash history across updater recovery * test(desktop): prove updater crash recovery wiring * fix(desktop): preserve shutdown authority during updater failure * test(desktop): wait for native recovery accessibility * test(desktop): isolate crash recovery acceptance * test(desktop): bind recovery fixture process identity * fix(desktop): retain quit authority during update handoff * fix(desktop): restart after failed updater stop * Keep diff mode and Git status refresh responsive (#127) * fix(web): keep diff and git status refresh responsive Adapted from Synara 807acfe3c784b41229b81c4b78957681ec8e6cb2. Remount the third-party diff renderer when its mount-time view mode changes, use the shared menu radio primitive, and prevent branch-discovery races or non-repo workspaces from starting a permanent Git-status invalidation loop. Add focused regression coverage for each boundary. * fix(web): ignore stale Git status before repository confirmation * fix(web): require exact branch status for git actions * fix(git): preserve branch authority across actions * fix(git): serialize repository mutations * fix(git): cover repository mutation workflows * style(server): apply repository formatting * fix(git): isolate live mutation authority contracts * fix(git): overlay live mutation RPC authority * test(web): align stacked action transport contract * Keep local HTML previews live across source changes (#130) * fix(desktop): keep local HTML previews live * fix(desktop): harden live preview refresh * fix(web): clear stale HTML preview errors * fix(web): report queued preview refresh failures * fix(desktop): release retired preview session hooks * fix(browser): preserve refresh ownership and latest revision * fix(browser): close live preview certification gaps * fix(browser): close live preview review findings * fix(browser): close final live preview review findings * fix(browser): close exact-head preview review findings * test(browser): cover preview discovery limits * fix(browser): preserve optional preview limit metadata * test(browser): require prepared source authority * fix(browser): attest local preview capabilities * fix(html-preview): harden atomic refresh authority * fix(html-preview): close source watch startup gap * fix(desktop): close live preview review gaps * fix(desktop): close preview ownership failure gaps * fix(html-preview): close remaining security boundaries * fix(html-preview): pin inspected file versions * fix(html-preview): serve attested document bytes * Stop duplicating completed replies in Activity (#135) * Stop duplicating completed replies in Activity * Prove Activity completion ownership in Chromium * Synchronize completion regression assertions * Show fork provenance in conversation timelines (#136) * Show fork provenance in transcripts * Keep unavailable fork provenance truthful * Require confirmed provider updates (#137) Gate the Settings > Providers Update action behind a confirmed fresh version check, and harden the confirmed-update boundary so the updater child process only ever spawns against a probed, certified, and re-validated target (closes six concurrency/TOCTOU windows). See PR description for full details. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix oversized transcript–composer gap when a task panel is showing (#138) * Fix oversized transcript–composer gap when a task panel is showing The composer is a flex sibling below the transcript, so the stacked composer chrome (live-changes header, active task list, queued follow-ups) already reserves its own vertical space through the flex layout. The transcript then fed that same chrome height into its in-list bottom spacer (bottomContentInsetPx = composerStackedChromeHeight + 8), reserving the space a second time. The result was a large, growing gap between the last message and the composer whenever a task/stacked panel was present, while the no-task case (spacer at its 64px baseline) already looked correct. Remove the double reservation: the transcript's bottom spacer is now a fixed 64px in every state, matching the perfect no-task gap. This also retires the now-vestigial bottomContentInsetPx prop chain (ChatView → ChatTranscriptPane → MessagesTimeline / AgentActivityDetailView), collapsing both consumers to their constant baseline and correcting the misleading "composer overlaps / reserves matching bottom space" comments. composerStackedChromeHeight is kept for its real remaining job: the scroll-compensation layout effect that keeps the transcript pinned to its end as the flex viewport shrinks while the chrome grows. - Task-present gap now equals the no-task gap (single flex reservation). - Agent activity detail view uses the same fixed baseline (it was also double-counting). - No behavior change to the no-task case. Verified: oxfmt, oxlint (0 errors), tsc --noEmit (web), and the affected component/scroll unit tests (106 passing). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add regression coverage for the transcript–composer gap fix Prove the stacked composer chrome is reserved only once: a [geometry:linux] browser test mounts ChatView with an active task card and again once the turn settles (no card), then asserts the gap between the transcript tail and the composer stack is unchanged. It anchors on the tail spacer's top (the true end of transcript content, past any live-turn activity indicator) so a running turn does not confound the measurement. Verified the test fails on the pre-fix code — the gap balloons to ~180px when the task card appears — and passes on the fix (~44px in both states). Adds two stable test hooks: data-chat-composer-stack on the composer block wrapper and data-testid="transcript-bottom-spacer" on the list tail spacer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Fix file links failing to open across git worktrees (#139) * fix(server): resolve workspace file links across git worktrees Bare/partial file references (e.g. a chat link to `kanbanDispatch.ts`) could fail to open with a misleading "no such file" error even though the file plainly exists. Two root causes: 1. The filesystem-walk index descended into linked git worktrees, so a single logical file was indexed multiple times (the real checkout plus each worktree copy). The suffix resolver treats multiple matches as ambiguous and gave up, and the read then surfaced the realpath ENOENT for the literal (non-existent) path. Indexing the duplicates also inflated the index toward its 25k-entry cap, truncating it. 2. On a genuine ambiguity the resolver returned null, which the reader reported as ENOENT -- a "file not found" message for a file that exists. Changes (server-only): - Prune linked git worktree subtrees from the index walk (a worktree records `.git` as a regular file pointer, the reliable discriminator), and skip `.git` entries whether file or directory. Extract the shared worktree/skip predicates. - Rework resolveWorkspaceFileBySuffix to return a structured result (resolved | ambiguous | unresolved). Resolve only on a single distinct match; report the competing paths on a true ambiguity instead of guessing between different files. - When the cached index is truncated (unreliable), re-scan the tree directly (bounded) for a trustworthy candidate set. - Surface an honest, actionable error listing the competing files instead of a false ENOENT. Reuses the existing WorkspaceFileSystemError tag, so no contract/client change. Tests: worktree pruning, unique/ambiguous/unresolved resolution, the worktree-duplicate scenario end-to-end, and the truncated-index disk re-scan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(server): don't prune submodules; fail closed on incomplete suffix scan Follow-up correctness fixes to the worktree-aware file-link resolution. 1. Submodule false-prune. The worktree detector treated *any* directory whose `.git` is a regular file as a linked worktree and pruned it. Git submodules also store `.git` as a file, so their subtrees were pruned too -- silently hiding submodule files from search and link resolution. Discriminate by the `gitdir:` pointer target: prune only when it points into `.git/worktrees/<name>` (a linked worktree), never when it points into `.git/modules/<name>` (a submodule). Reading the pointer fails open (do not prune) so an unreadable `.git` can never hide real files. 2. Incomplete-scan false-unique. The bounded disk re-scan (used when the index is truncated) returned whatever it had found when it hit the scanned-directory cap. A single match found before the cap was then reported as a unique "resolved" even though a second match could sit in the unscanned remainder -- risking opening the wrong file. The scan now reports whether it completed, and classification fails closed to a new "indeterminate" outcome when an incomplete scan saw fewer than two matches. The reader surfaces an honest "too large to resolve, use a fuller path" error instead of guessing or falsely claiming ENOENT. Tests: submodule files stay resolvable and searchable (not pruned); the disk scan reports incomplete at its directory cap; classification fails closed (single match from an incomplete scan -> indeterminate, two distinct matches -> ambiguous even when incomplete, empty complete scan -> unresolved). The existing linked-worktree fixtures now use realistic `.git/worktrees/<name>` pointer contents. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(web): guard Enter during IME composition in message composers (#143) CJK/Japanese/Korean IMEs use Enter to confirm a candidate. An unguarded Enter-to-send handler treats that confirmation keystroke as "send" and submits a half-composed message. Add a shared isImeCompositionKeyEvent() helper (isComposing || keyCode === 229) and apply it at the two message-composer key handlers: - ComposerCommandKeyPlugin, the shared chat + kanban Lexical handler: swallow Enter fired mid-composition before it reaches the send/menu logic. Lexical already drops keydowns while editor.isComposing() is true, but on Safari/WebKit compositionend fires before the confirming keydown, so that Enter still dispatches KEY_ENTER_COMMAND; the keyCode === 229 branch closes that gap. - PullRequestCommentComposer, a plain <textarea> with no Lexical gate, replacing its isComposing-only check so a keyCode-229 confirm no longer submits. Value: correct multi-language text entry; no accidental send on IME candidate confirmation. Out of scope (follow-up): other bare-Enter inputs (project/rename/search fields) share the hazard and could adopt the same helper. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * feat(web): self-host UI fonts, drop Google Fonts CDN (#142) Remove the runtime Google Fonts <link> from index.html and self-host the needed families (Geist, Geist Mono, Inter) via @fontsource-variable/* packages, alongside the JetBrains Mono face already bundled. DM Sans was listed in the CDN link but has zero references, so it is dropped rather than self-hosted. The @fontsource-variable packages register their @font-face under a "<Family> Variable" name (e.g. "Inter Variable") while themes store the plain family name, so add expandBundledVariableFontAliases() and apply it at the theme->CSS-variable emission boundary: the bundled face is matched and the plain name is kept after it as a fallback. Value: offline usability, no third-party font beacon on launch, no font flicker. The default appearance (systemUiFont + JetBrains Mono fallback) needs no Google fonts, so removing the CDN cannot regress it. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Make new-chat project selection safe across draft and project lifecycles Integrate the reviewed project-picker interaction and project-lifecycle safety fixes. Complete local certification, three independent final reviews, hosted CI, and manual native visual acceptance passed. * fix(desktop): preserve Windows Ctrl-minus zoom (#148) * fix: preserve Windows Ctrl-minus zoom Adapted from Synara 94b59220e26bc337406110c84220aec76b065490. * fix: preserve shortcuts help chord compatibility Keep the Windows physical-minus disambiguation scoped to Windows while retaining the existing Meta-or-Ctrl slash behavior on every platform. * fix: align Windows minus shortcut routing * Promote certified desktop integration queue (#154) Promotes the certified July 28 desktop integration queue. Includes the reviewed work represented by PRs #123, #140, #141, #144, #149, #150, and aligned replacement #151 for #146. Supersedes #68 through the hardened #144 implementation. See PR #154 for exact heads, dispositions, verification, limitations, and rollback evidence. * Promote certified desktop queue + v0.5.14 release note into main (#155) * Add Claude Opus 5 capabilities * Harden Claude capability discovery and Opus gating * Refresh Claude discovery results * Fail closed on Claude capability boundaries * Scope Claude discovery to the exact runtime * Bind Claude Opus 5 to the exact runtime * Harden Claude Opus 5 runtime gating * Keep Claude fresh defaults available * fix(claude): isolate discovery lifecycle generations * fix(claude): bind discovery cache generations * test(web): bind Claude prefetch generation keys * fix(claude): authorize Opus 5 from exact runtime * fix(claude): make discovery generations monotonic * Fix provider runtime extraction and setup progress * fix(claude): harden discovery lifecycle ownership * fix(claude): generation-key native slash-command discovery Native slash-command discovery now participates in the same renderer-owned discovery-generation scheme already used for model and agent discovery, so a command catalog fetched under one auth/runtime generation can never leak into a newer one. - contracts: add optional discoveryGeneration to ProviderListCommandsInput - server: fold discoveryGeneration into the listCommands in-flight cache key so a later auth generation never joins an older CLI's discovery - client: bind the commands query to the current generation (query key, RPC arg, post-resolve stale discard, fail-fast retry, no stale placeholder for claudeAgent) and invalidate commands alongside agents on auth-sensitive provider changes - route the configured Claude binary through every command-discovery call site (ChatView, kanban composer, /fast availability check) - tests: cover generation separation for command discovery on both the server adapter and the React Query layer Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(agent-gateway): host-served MCP read/coordination tools (Slice 1) First slice of the agent gateway: a thread-scoped, host-served MCP endpoint (`POST /mcp`) that lets an agent in one thread observe and coordinate sibling top-level threads. Read/coordination only — no send/interrupt, no create/fork. Behind a feature flag, disabled by default (`SYNARA_AGENT_GATEWAY_ENABLED` / `--agent-gateway-enabled`). Lift-and-reconcile of Synara's MIT-licensed agent gateway onto a Scient-owned authorization + credential spine. `synara_*` names and `synara/` namespaces kept intentionally (rebrand is a later pass). New `apps/server/src/agentGateway/` subsystem: - Transport/ingress auth: per-request bearer verify → thread-existence recheck → provider-ownership recheck → central authorization, with no cached grant; body cap (1 MiB) + batch cap (50); GET/DELETE mirror the disabled-state 404; top-level defect net upholds the never-fails contract on handleMcpPost. - Credential spine: opaque per-thread tokens, in-memory registry (dies on restart), least-privilege (`thread:read` only), revoke-on-teardown. - Central default-deny authorization: capability → project scope → thread-type; cross-project reads denied as thread_not_found. - Read tools: synara_context, list_projects, list_threads, read_thread, wait_for_threads, backed by ProjectionSnapshotQuery. - Claude provider injection via HTTP Authorization header (never the process env), flag-gated, revoked on teardown and failed install. Shared-file injection hand-re-applied at current symbol anchors: http.ts route registration, config.ts/main.ts flag, effectServer.ts bound-port publish, ClaudeAdapter.ts/runtimeLayer.ts token lifecycle, new packages/contracts/src/agentGateway.ts. typecheck 9/9, full test suite 12/12 (agentGateway 168/12 incl. new httpRoute.test.ts), lint 0 errors, brand:check green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(agent-gateway): keep contracts barrel frozen + format Slice 1 files Resolves the two CI failures on this PR: 1. migration:check — Slice 1 added `export * from "./agentGateway"` to `packages/contracts/src/index.ts`. That barrel is a released-migration dependency (released migrations import `@synara/contracts`, and the lineage guard traverses the barrel's re-exports and fingerprints its runtime source). Adding the line both *modified* the frozen barrel and *pulled* `agentGateway.ts` into the released dependency closure, tripping the append-only guard. Fix: relocate the gateway contract into the server subsystem as `apps/server/src/agentGateway/contract.ts` and drop it from the barrel. Every consumer is server-side (no renderer/client consumer exists), so the shared package was never required. `index.ts` is restored byte-for- byte to the v0.5.13 baseline and `agentGateway.ts` leaves the closure. 2. fmt:check — donor-lifted test files and the ClaudeAdapter edits were not run through oxfmt. Applied `oxfmt` (formatting only; no behavior change). Full gate green: brand, workflow, migration, fmt, lint (0 errors), typecheck (9/9), test (12/12 packages, 2530 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(agent-gateway): close read_thread disclosure oracle + revoke token on failed spawn Two pre-merge security fixes on the Slice 1 read foundation, plus a truthful token-exposure comment. 1. read_thread non-disclosure oracle. An unknown thread failed as a plain-text ToolInputError while a cross-project thread failed as a JSON GatewayToolError, so a caller could distinguish "no such thread" from "exists in another project" by response shape — defeating the deliberately byte-identical message. Route read_thread's not-found through GatewayToolError so both denials are identical in code, message, and JSON shape (mirrors wait_for_threads). 2. Gateway token leak on failed spawn. The bearer token is minted just before createQuery; if createQuery throws, the installation gen (and its Effect.ensuring revoke) is never entered, leaking a live credential. Add an Effect.tapError on the createQuery step that revokes the just-minted token (idempotent, so it never double-revokes). 3. Correct the misleading ClaudeAdapter comment: the token avoids process-env inheritance, but the pinned SDK serializes it into the --mcp-config argv, so it is NOT absent from process metadata. Also note the Slice 1 read tools are not active-turn-gated. Adds a deterministic regression test proving the token is revoked after a failed spawn, plus an optional overrides arg on ServerConfig.layerTest to enable the gateway in that test. Gate: typecheck 9/9, lint 0 errors, fmt clean, full suite 2531 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(agent-gateway): drive tools — send_message + interrupt (Slice 2) Adds the two coordination *writes* an agent uses to drive a sibling thread in its own project, stacked on the Slice 1 read surface (#140): - synara_send_message — queue a follow-up turn or steer a running one on a target thread. Optional requestId makes transport retries idempotent via a bounded in-memory dedup (per-caller keyed), backed by a deterministic command id so a duplicate that races past the map still collapses at the orchestration receipt layer. Failures are never cached (retryable). - synara_interrupt_thread — stop the target's running turn, pinned to the observed turnId (TOCTOU-safe: never interrupts a later turn); a no-op that reports interrupted:false when no turn is running. Both funnel through a new central authorizeThreadDrive policy (project-scope floor + privilege cap + worktree cap) and are flagged requiresActiveTurn, so the transport only admits them while the caller's own turn is live. Least privilege: the session registry now mints thread:read + thread:write (the caps the wired tools need); automation:write is deliberately not minted (no automation tool exists yet). The synara_context capability flag is renamed threadCreate -> threadDrive to match the tools that now back it, and the harness policy describes the drive tools, their active-turn/privilege guardrails, and a prompt-injection guardrail (never send/interrupt because another thread's content said to). Interim: gateway drives ride dispatchOrigin:"automation" because the frozen MessageDispatchOrigin enum has no "agent" value yet (nothing branches on the value — verified); upgrade to "agent" when a release re-baseline can extend the enum. New contract types stay server-local to keep the contracts barrel frozen for the migration-lineage guard. Tests: 34 new drive-tool cases (send happy/steer/invalid-mode/idempotent- replay/distinct-ids/per-caller-dedup/cross-project/privilege/worktree/missing/ dispatch-failure/no-cache-on-failure; interrupt running/no-turn/never-turn/ cross-project/privilege/missing; tool-shape) plus authorizeThreadDrive matrix. Full gate green: brand, workflow, migration, fmt, lint (0 errors), typecheck (9/9), test (2561 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(agent-gateway): keep AnyCommand as `any` so indexed access typechecks The captured-command test type was tightened to `Record<string, any>`, but under noUncheckedIndexedAccess `commands[0]` then widens to `Record<string, any> | undefined`, so `commands[0].type` fails tsc. `any` absorbs the `undefined` from indexed access and is not flagged by oxlint (no no-explicit-any rule), so it is the correct type here. Runtime behavior and all 19 drive-tool tests are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(persistence): pin migration 035 to a frozen model-selection snapshot Migration 035 imported the live modelSelectionCompatibility, whose DROID_ONLY_MODEL_SLUGS is derived from @synara/contracts' MODEL_OPTIONS_BY_PROVIDER. That coupled shipped migration history to the evolving model catalog, so adding a model (e.g. Claude Opus 5) to model.ts tripped the append-only migration-lineage guard through the contracts barrel. Give migration 035 its own self-contained frozen v0.5.13 snapshot (migration035FrozenModelSelectionCompatibility) with the DROID_ONLY set hardcoded as the exact v0.5.13 catalog-derived literal, and repoint the migration's import to it. All other normalization logic is byte-identical to the live helper; the live helper stays in place for its runtime consumers. The snapshot is proven behaviorally identical to the v0.5.13 migration: - an equivalence test asserts frozen ≡ live across a persisted corpus that spans every branch (canonical, provider-less ambiguous slugs incl. claude-opus-5, instance-label inference, legacy Gemini, option-row arrays, provider-scoped options) and every catalog Droid-only slug, and - the hardcoded DROID_ONLY literal is an exact match to the droid-only set derived from the origin/release/stable (v0.5.13) MODEL_OPTIONS_BY_PROVIDER. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(migration-guard): audited one-time allowance for the 035 decouple Repointing migration 035 to its frozen snapshot changes the shipped migration dependency graph: severing the sole import of the live modelSelectionCompatibility removes the only bridge from migration history into @synara/contracts, so modelSelectionCompatibility and the entire contracts barrel legitimately leave the migration dependency closure while the frozen snapshot enters it. It also changes migration 035's own content (the import line). Bless exactly this delta with exact, path-and-blob-pinned, one-time audited allowances — not a general bypass and without advancing the release baseline or touching the protected release-tag manifest: - RELEASED_CONTENT_ALLOWANCES gains the 035 old→new blob pair. - RELEASED_DEPENDENCY_GRAPH_ALLOWANCES (new) pins 29 removed baseline blobs and the 1 added frozen-snapshot blob. Each allowance pins a Git blob, so the guard fails closed on any other change: editing the frozen snapshot voids its added-blob allowance, and a dependency that stays reachable but changes content is never blessed (that branch remains a hard violation). Violation messages now emit the exact allowance key so future audited deltas are self-documenting. Guard self-tests cover both content and removed/added graph suppression. This precise closure also unfreezes unrelated contract files (e.g. providerDiscovery.ts) that were only frozen transitively through the barrel, and lets model.ts add Opus 5 without editing shipped history. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(providers): add safe sign-out controls * fix(providers): close review gaps * fix(providers): polish status accessibility * fix(providers): preserve released contract lineage * fix(providers): use native sign-out confirmation * Fix Claude discovery generation isolation * Fix Claude model discovery without init event * perf(git): fetch compact diff scope stats Adapt the server-side working-tree diff statistics lane from Synara b3fc978308b30342694c06f651dc42762fd04552. Preserve selected-scope patch rendering while replacing picker-wide patch transfers and renderer parsing with compact totals. Donor license: MIT. Scient's existing LICENSE carries the applicable Emanuele Di Pietro copyright and MIT notice. * fix(diff): keep selected scope count current * fix(diff): move stats RPC outside released contracts * fix: enforce provider archive extraction limits * fix(web): close project actions before editing * test(web): cover project action focus handoff * feat(git): discover committed PR templates safely * fix(server): harden agent gateway session boundaries * fix(server): close agent gateway review gaps * fix(server): bind gateway limits to session lifecycle * fix(agent-gateway): preserve honest message provenance * fix(orchestration): retain agent dispatch provenance * fix(git): honor GitHub PR template variants * fix(git): require canonical PR template names * fix(git): require dotted template extensions * Add governed source-control writing (#153) Integrates the reviewed SCM writing policy into the certified desktop queue. Exact source head 13f933d passed focused and full verification plus three independent final reviews with no remaining P0-P3 findings. See PR #153 for credential, provider-isolation, provenance, rollback, and limitation evidence. * Add floating browser preview (#152) Integrate the reviewed floating browser preview into the desktop shadow queue. Exact candidate c8cb572 was certified against queue base 3f7ef52 with green hosted CI, real Electron acceptance, and three independent final reviews with no unresolved P0-P2 findings. * docs(release): add Scient v0.5.14 in-app release note Adds the required Scient-owned v0.5.14 entry to the in-app "What's new" catalog. Highlights the two new user-facing capabilities in this release (floating browser preview and source-control writing help) plus the verified refinements shipped since v0.5.13. Text-only; no artwork added. Verified locally: release:notes:check 0.5.14, brand:check, fmt:check, lint (0 errors), whatsNew logic tests (14), verify-release-notes tests (12), web typecheck. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Scient Release Engineer <yaacov.corcos@datavant.com> * Fix release preflight tag visibility (#157) Fetch the official Synara tag set through a push-disabled remote before migration-lineage validation in Release Preflight. Preserve the reviewed 79-tag manifest and enforce the fetch commands and ordering through release smoke coverage. --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Scient Release Engineer <yaacov.corcos@datavant.com>
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.
Outcome
Promotes the frozen and certified desktop integration queue into main.
Users gain hardened provider setup and account controls, Claude Opus 5 support, the governed agent gateway foundation, compact Git diff statistics, reliable project-action closing, and safe committed pull-request-template discovery.
Exact state
Included work
Explicitly not included
Verification and review
The combined queue through 66e341f passed the full upstream intake certification and exactly three combined correctness, security, and architecture reviews with no unresolved P0-P3.
PR #150 then aligned normally on that queue. Its exact final tree passed the complete repository gate, 26 focused tests, all 9 typecheck tasks, full tests, desktop build, identity, formatting, lint, diff check, exactly three final reviews, and all hosted checks. The queue merge tree is byte-for-byte identical to that tested and reviewed PR #150 tree.
Accepted documented limitation: the Claude SDK serializes the loopback, project-scoped, turn-gated gateway bearer in the same-UID child argv. The child already inherits the more powerful Anthropic credential; the gateway token remains memory-only and is revoked on teardown.
Promotion and rollback
Merge only after this promotion PRs hosted checks are green. No release is performed by this PR. Rollback is a normal revert of the promotion merge; source branches are retained until the promotion is confirmed.