Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Evaluate a Tauri desktop app, gated on measured value over browser auto-open

オープン
#289 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
20/100
issue の種類
機能追加
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
rust, sqlite, tauri, wasm

調査の方向性

Start with the D00 inputs and repository facts, then read the dependency graph and the D02, D03a, D04a, D04b, and D05 package steps. The initial five-day spike is limited to a Tauri prototype and core qualification cases; the broader plan includes design, security, cross-platform work, measurements, and release decisions. Done means the required package artifacts and evidence exist and their gates pass; each Stop clause names the decision owner.

索引モデルが issue の本文から書いたものです。

説明

enhancement

Summary

Evaluate shipping CodeTrial as a desktop application, starting with a bounded
Tauri prototype on macOS. The browser deployment stays available throughout.
A desktop release ships only if a complete interview works reliably in the
system WebView and the desktop app shows measurable value over a simpler
alternative: the existing binary opening the browser automatically.

This is a proposal with an explicit stop at every stage, not a commitment to
ship. No prototype or benchmark has been run; every threshold below is a
proposed acceptance target.

Why Tauri first, and what is out of scope

  • CodeTrial already ships as one Rust binary with embedded web assets, WASM,
    and vendored dependencies. With no arguments it starts web mode and falls
    back to setup when no config exists. It prints a URL; it does not open a
    browser. Auto-open is therefore the baseline any desktop shell has to beat.
  • Tauri fits the Rust backend and can host the Axum service in-process. That
    is design work (bootstrap, runtime, lifecycle), not an existing feature.
  • tinyjs would run the current binary as a sidecar, adding a JavaScript runtime
    and child-process management. Tauri and tinyjs both use system WebViews, so
    switching between them does not remove the main media-compatibility risk.
    Revisit tinyjs only with measured gains (D13); no migration is planned.
  • Electron bundles Chromium, which reduces engine differences at the cost of a
    much larger distribution and update burden.
  • Interviews still need LiveKit and Gemini; C, C++, and Java tests still use
    Compiler Explorer. A desktop installer does not make interviews offline.
  • Initial desktop scope: managed startup, a dedicated window, optional
    fullscreen, a report-ready notification, predictable shutdown. Not in scope:
    a new frontend framework, interview protocol changes, replacing SQLite, a
    framework-neutral plugin layer, or eye tracking (a separate, contract-gated
    study in D12).
  • The desktop app still listens on loopback. Tauri uses WKWebView, WebView2,
    and WebKitGTK; existing Chromium browser tests do not qualify any of them.
  • Fullscreen is presentation only. Native focus signals or gaze estimates must
    not change scoring or imply misconduct (docs/observable-delivery-policy.md,
    docs/integrity-evidence.md, docs/recording-contract.md).
  • Cloud cost: plan for 0% LiveKit or model savings at the same workload
    (docs/provider-cost-and-degradation.md).

Release criteria

Ship only when the core qualification gates pass and at least one benefit is
measured: simpler unassisted use, a useful native integration, or a
performance gain against the auto-open baseline (at least 20% faster median
launch-to-lobby, p95 no more than 10% slower; memory and CPU no more than 10%
worse at equal workload). Ten failure-free qualification sessions are a
release checklist, not a reliability claim: they still allow about a 26%
per-session failure rate at one-sided 95% confidence.

Formulas, always on observed values:

  • Time reduction: (baseline s - desktop s) / baseline s.
  • Annual user time saved: users * launches per year * seconds saved / 3600.
  • Memory reduction: (baseline tree memory - desktop tree memory) / baseline tree memory, same accounting method and workload.
  • Economic return: annual time and support savings minus engineering,
    signing, release, and maintenance cost, once labor rates are agreed.

Timing protocol: release builds of one revision on one machine, at least 30
cold and 30 warm launches per variant in random order, failures kept, OS and
WebView versions recorded. Browser resource cost is the incremental cost of
the interview tab and its processes, plus a dedicated-browser run.

How the tasks are written

Every work package has: Accountable (one person), Depends on, Inputs,
checkbox Steps (one verifiable action each), Done (numbers or named
artifacts), Evidence (where the sanitized record goes), and Stop (condition
and decider).

Conventions shared by all packages:

  • Paths. Specifications go in proposed docs/desktop/. Sanitized evidence goes
    in proposed docs/desktop/evidence/<package>/. Raw data containing device
    identifiers, service usage, or participant information stays outside the
    repository at a private location recorded in D00. Nothing public carries
    credentials, session tokens, candidate content, or recordings
    (CONTRIBUTING.md).
  • Evidence record. Each record starts with revision SHA, date, artifact
    checksum, OS and WebView build, hardware, devices, accountable person, and
    decider. Its body lists the steps run, the exact commands, expected versus
    actual results, pass/fail/unsupported per case, and evidence links. Raw
    measurements go in a sibling CSV.
  • Commands. Commands that exist today appear bare. Commands that a package
    creates are marked # proposed: until they have run successfully.
  • Gate rule. A new script or self-test is either registered in
    scripts/test.sh as a named gate (Python suites use unittest through
    unittest_gate tests/test_<name>.py, see scripts/test.sh:305-319) or is
    declared out-of-gate with a reason. Any new crate states how fmt, clippy,
    and cargo test reach it, because the gate only runs the root manifest
    (scripts/test.sh:275-297) and the repository has no Cargo workspace.
  • Size rule. A package estimated at more than three engineering days, or
    producing more than one kind of deliverable (spec, code, measurement, study),
    is split. The packages below are already split on that basis.
  • Port. Desktop work and tests use 127.0.0.1:3101. Never port 3000.

Decision owners. Every Stop clause cites one of these roles:

Role Owns
Maintainer Scope, budget, go/no-go, extensions, platform deferral, fallback
Security reviewer Trust boundary, native bridge authorization, OAuth and secret policy
Test lead Case definitions and pass/fail/unsupported rulings
Report owner Any change that could lose or alter a saved report
Policy owner Anything touching integrity evidence, recording, or candidate privacy

Decision owners. Every Stop clause cites one of these roles:

Role Owns
Maintainer Scope, budget, go/no-go, extensions, platform deferral, fallback
Security reviewer Trust boundary, native bridge authorization, OAuth and secret policy
Test lead Case definitions and pass/fail/unsupported rulings
Report owner Any change that could lose or alter a saved report
Policy owner Anything touching integrity evidence, recording, or candidate privacy

Repository facts the tasks rely on

Checked at revision df69ac3:

  • run_web (src/main.rs:300) prints its readiness line at src/main.rs:363
    and serve_setup (src/main.rs:512) at src/main.rs:532. Both print after
    binding but before axum::serve starts accepting, so a readiness line is
    not proof that a page will load.
  • primary_config_path (src/main.rs:785) searches ./config/ and ./
    before the executable directory. cold_start_config_path
    (src/main.rs:1150) writes to ./config/ whenever
    config/codetrial.env.example exists in the working directory. web_dir
    defaults to a working-directory-relative web (src/config.rs:66), and
    files on disk override the embedded assets one file at a time
    (src/web/assets.rs). A Finder launch has an arbitrary working directory.
  • web_error_log_path (src/main.rs:655) writes codetrial-error.log into
    exe_dir(). In a macOS bundle that directory is .app/Contents/MacOS.
  • The only Host check is host_is_loopback in src/web/setup.rs:76, and it
    covers setup only. The main router validates neither Host nor Origin.
    src/web/policy.rs builds CSP and security headers only. CSRF protection is
    the SameSite=Lax session cookie (src/web/auth.rs:548).
  • random_token(bytes) in src/accounts/sessions.rs:212 is the existing
    cryptographic token generator; ring 0.17 is already a dependency.
  • endInterview(reason) (web/interview.js:573) returns nothing and acts only
    when state.phase === "live". Close handling therefore needs a completion
    signal it does not have today.
  • web/before-unload.js is tested in
    tests/browser/interview-lifecycle.test.js; web/report-recovery.js in
    tests/browser/report-recovery.test.js; web/history.js in
    tests/browser/history.test.js.
  • Unit tests attach with #[path = "../tests/unit/<name>.rs"] (for example
    src/main.rs:1162, src/lib.rs:120).
  • rusqlite is built without its backup feature (Cargo.toml:37).
  • CI builds release binaries in the build matrix
    (.github/workflows/check.yml:612, macos-15 and windows-2025) and
    publishes in the release job (.github/workflows/check.yml:928).
  • docs/integrity-evidence.md:129 refuses gaze-direction inference. Any gaze
    work is a contract question before it is an engineering question.

Plan

Dependency graph:

D00 -> D01 -> D02 -> D03a -> D04a -> D04b -> D05 (core C1-C7)
                              D04b -> D04c -> D05 (remaining cases)
D03a -> D03b (only if D00 requires import) -> D10b
D00 (scope) + D04b + D05 -> D06a / D06b / D06c (each only if required)
D03a + D05 -> D07
D04b + D05 + D07 -> D08
D01 + D05 + D07 + D08 -> D09a -> D09b
D00 (recruitment approval) + D09a -> D09c
D00 -> D10-prep (signing membership and credentials, in parallel)
D04c + D05..D09 + D10-prep -> D10a -> D10b -> D10c -> D11-win, D11-linux
D10c -> optional D12 (gaze, contract decision first) / optional D13 (tinyjs)

Five-day spike allocation (engineering days, not calendar days): D02 one day;
D03a plus D04a two days; D04b one day; D05 core cases C1-C7 one day. D03b,
D04c, the remaining D05 cases, and everything after are outside the box.

Work packages

D00 - Freeze scope, credentials, and the test matrix
  • Accountable: maintainer. Depends on: none.
  • Inputs: README.md, docs/install.md, docs/interview-length.md,
    docs/observable-delivery-policy.md, docs/integrity-evidence.md,
    docs/recording-contract.md, docs/provider-cost-and-degradation.md.
  • Steps:
    • Create proposed docs/desktop/scope.md. Record git rev-parse HEAD, the
      exact Tauri crate version (tauri = "=2.x.y"), the application
      identifier, sw_vers output, system_profiler SPHardwareDataType
      summary, and the microphone, camera, and output device models.
    • Assign one person to each role in the decision-owner table.
    • Mark each feature required, optional, or deferred, with a case ID and an
      expected result: solo interview, preflight, Pyodide, JavaScript runner,
      Compiler Explorer languages, face presence, avatar, whiteboard, replay,
      export/download, GitHub OAuth, recording, Meet presentation, fullscreen,
      report-ready notification. Default: solo, non-recorded, no OAuth.
    • Name the holder of each credential without its value: LiveKit URL, key,
      and secret; Gemini key; GitHub OAuth client (only if OAuth is required);
      recording service account (only if recording is required).
    • Decide Apple Developer Program membership: buy, defer, or no. Without it,
      D10 ends at an ad-hoc local build and the release decision is no-go.
    • Size the live-service budget from planned session counts (D05 core, D09b
      active runs, ten default-length sessions per configuration in D10c and
      D11) and get a written USD ceiling from the maintainer.
    • Approve or reject the D09c usability study: participant count, consent
      text, and compensation. Rejection removes D09c; D10 then relies on D09b
      or a native-integration benefit.
    • Cap the number of declared device/OS configurations per platform.
    • Record the private location for raw evidence.
  • Done: docs/desktop/scope.md has no empty cell, no secret value, and a
    maintainer sign-off line.
  • Evidence: docs/desktop/scope.md.
  • Stop: missing credentials block only their live cases. The maintainer
    resolves them within five working days or marks those cases deferred.
    Required OAuth or recording makes the matching D06 package mandatory.
D01 - Establish an honest browser baseline
  • Accountable: Rust developer. Depends on: D00.
  • Inputs: Python 3, Cargo, one named browser, disposable config, database, and
    browser-profile directories outside the repository.
  • Steps:
    • Read run_web, serve_setup, bind_web_listener (src/main.rs:242),
      and is_cold_start in src/main.rs. In docs/desktop/baseline.md,
      record the two readiness lines, what runs between each line and
      axum::serve, and the failure path (non-zero exit, stderr,
      codetrial-error.log).
    • Run cargo build --release --bin codetrial.
    • Create proposed scripts/desktop_auto_open.py. It starts
      target/release/codetrial web bound to 127.0.0.1:3101 as an owned child,
      reads one readiness line with a timeout, then polls that URL until the
      owned child answers HTTP, then opens exactly one tab in the dedicated
      profile. On child exit or timeout it opens nothing. On browser launch
      failure it prints the URL. On its own exit it terminates the child.
      The setup-to-lobby handover reuses the same tab.
    • Create proposed tests/test_desktop_auto_open.py (unittest) covering:
      configured line, setup line, setup line followed by configured line
      (one open), line printed but HTTP never answers (no open), exit before
      readiness (no open), browser launch failure (URL printed).
    • Register it in scripts/test.sh:
      gate desktop-auto-open-tests unittest_gate "$ROOT/tests/test_desktop_auto_open.py".
    • Run ./scripts/test.sh.
    • Take three smoke timings per workflow (manual URL, auto-open) using the
      metrics in Release criteria. The full trial is D09b.
  • Done: step 6 passes; manual runs of configured, fresh-setup, bind
    conflict, and invalid-config launches produce the expected tab counts
    (1, 1, 0, 0).
  • Evidence: docs/desktop/baseline.md, docs/desktop/evidence/D01/.
  • Stop: the maintainer reviews the smoke results. If auto-open meets the user
    need and D00 lists no required native integration, the maintainer can
    promote auto-open into the product as a separate change and stop here.
D02 - Specify desktop bootstrap, origin, and trust boundary
  • Accountable: Rust developer, reviewed by the security reviewer.
    Depends on: D01. Spike day 1.
  • Inputs: D01 trace.
  • Steps:
    • Read run_web, serve_setup, web_server_config, initialize_accounts
      (src/main.rs:907), published_secret_refusal, and dispatcher
      construction in src/main.rs; read src/dispatch.rs, src/web/mod.rs,
      src/web/setup.rs, src/web/auth.rs, and src/web/policy.rs.
    • Create proposed docs/desktop/bootstrap.md with:
      • a. A Rust interface for proposed src/launch.rs: an explicit paths value
        (config file, database, error log, optional web_dir), a start
        function returning a running handle (bound address, async
        shutdown()) plus a readiness event emitted after axum::serve has
        started, and a typed start error.
      • b. The list of src/main.rs helpers that move to the library and those
        that stay CLI-only.
      • c. A state diagram: Idle, SetupServing, Configuring, Ready, Failed,
        ShuttingDown, Stopped, with the setup-to-lobby handover on one
        listener.
      • d. The runtime model: one Tokio runtime owned off the Tauri main thread;
        no block_on from the UI thread; no nested runtimes.
    • Record one decision: in-process service or owned sidecar, with the files
      each choice changes. Default: in-process.
    • Record the origin decision: http://127.0.0.1:3101, single-instance lock
      acquired before bind, second launch focuses the owner, a port conflict
      fails visibly, never load a page from a port this process does not own.
      Run lsof -iTCP:3101 -sTCP:LISTEN on the target machines and record it.
    • Specify the desktop session secret: random_token(32) from
      src/accounts/sessions.rs, created exclusively, mode 0600, reused across
      launches, fatal on unreadable or malformed content.
    • Write a route-by-route expected-status table for wrong Host, foreign
      Origin, missing session, forged session, authorized setup, username login,
      and account report access, covering setup and main service. Each row
      names its D04c test.
    • Specify the cookie and CSP policy for desktop mode explicitly; do not
      derive it by setting NODE_ENV=production.
  • Done: the Rust developer and security reviewer sign bootstrap.md.
  • Evidence: docs/desktop/bootstrap.md.
  • Stop: if in-process reuse would change more than about 300 lines of
    src/main.rs or any behavior covered by cargo test --test cli, the
    maintainer chooses the sidecar design instead. No second configuration
    pipeline.
D03a - Make bootstrap paths explicit
  • Accountable: Rust developer. Depends on: D02. Spike day 2, shared with D04a.
  • Inputs: bootstrap.md interface.
  • Steps:
    • Add the explicit paths value from D02 to the shared bootstrap. In desktop
      mode, config, database (the CODETRIAL_DB_PATH equivalent), error log,
      and web_dir come only from that value. Desktop never calls
      primary_config_path's working-directory search,
      cold_start_config_path, or exe_dir().
    • Keep CLI path semantics unchanged.
    • Add proposed tests/unit/launch.rs, attached from src/launch.rs with
      #[path]. Tests: with the working directory set to a temporary directory
      holding config/codetrial.env.local, config/codetrial.env.example, and
      web/index.html, a desktop-mode start reads none of them; a failed
      desktop start writes nothing beside the executable.
    • Run cargo test --lib, cargo test --bin codetrial,
      cargo test --test cli.
  • Done: step 4 passes; existing CLI tests are unchanged.
  • Evidence: docs/desktop/evidence/D03a/.
  • Stop: a CLI behavior change goes to the maintainer before merging.
D03b - Optional legacy import (only if D00 requires it)
  • Accountable: Rust developer, reviewed by the report owner.
    Depends on: D03a. Not part of the spike.
  • Steps:
    • Choose the copy mechanism and record it: stopped-source file copy, or
      VACUUM INTO from a read connection, or enabling rusqlite's backup
      feature. Default: VACUUM INTO, which needs no new feature.
    • Import only from a source the user selects; never scan directories.
      Copying a config file containing credentials needs a separate consent.
    • Show, before copying, that browser localStorage and anonymous-account
      identity do not transfer.
    • Stage into an empty destination. Refuse to overwrite. Require
      PRAGMA integrity_check to return ok and source and staged row counts
      to match for the account and report tables. Activate by rename. On
      failure, leave source and destination unchanged and delete staging.
    • Test: overwrite refusal, corrupt source, uncheckpointed WAL data, denied
      access, interrupted staging followed by retry.
    • Run cargo test --lib and cargo test --test web.
  • Done: every step 5 case has a tested outcome; no original data is deleted.
  • Evidence: docs/desktop/evidence/D03b/.
  • Stop: the report owner blocks any path that can lose rows.
D04a - Extract the shared bootstrap
  • Accountable: Rust developer. Depends on: D03a. Spike day 2.
  • Steps:
    • Create proposed src/launch.rs, export it from src/lib.rs, and move the
      helpers listed in bootstrap.md into it. src/main.rs calls it; CLI
      flags, setup handover, validation, and provider/account ordering stay the
      same.
    • Emit the readiness event after axum::serve has started, and implement
      shutdown() with axum's graceful shutdown.
    • Run cargo fmt --check,
      cargo clippy --locked --all-targets -- -D warnings,
      cargo test --lib, cargo test --bin codetrial,
      cargo test --test cli, cargo test --test web, then ./scripts/test.sh.
  • Done: step 3 passes; new tests in tests/unit/launch.rs cover readiness
    after serve, start failure, and shutdown completing.
  • Evidence: docs/desktop/evidence/D04a/.
  • Stop: see D02's stop clause.
D04b - Minimal Tauri shell
  • Accountable: desktop developer. Depends on: D04a. Spike day 3.
  • Steps:
    • Record the crate placement in proposed docs/desktop/development.md.
      Default: a standalone src-tauri/ crate with its own Cargo.lock, kept
      out of the root lockfile and the Bullseye build, plus a macOS-only gate
      line in scripts/test.sh:
      gate desktop-check cargo check --locked --manifest-path "$ROOT/src-tauri/Cargo.toml".
      Alternative: a workspace member. The maintainer decides.
    • Create src-tauri/Cargo.toml, src-tauri/build.rs,
      src-tauri/src/main.rs, src-tauri/tauri.conf.json,
      src-tauri/Info.plist, and src-tauri/Entitlements.plist with the
      pinned version and the D00 identifier.
    • The window loads http://127.0.0.1:3101/ as a remote URL served by the
      embedded Axum assets. frontendDist is unset or points only to a static
      starting page. Do not bundle web/ a second time.
    • Resolve config, data, cache, and log directories with Tauri's path API and
      pass them to the D03a paths value. Record the resolved macOS paths.
    • Set NSCameraUsageDescription and NSMicrophoneUsageDescription; set
      the com.apple.security.device.camera and
      com.apple.security.device.audio-input entitlements needed under the
      hardened runtime.
    • First check, before anything else: confirm getUserMedia works in
      WKWebView on http://127.0.0.1:3101. If not, stop and escalate, because
      it invalidates the origin decision.
    • Start the service on the owned runtime; show the window only after the
      readiness event; keep the native UI responsive during startup.
    • Add the single-instance plugin, acquired before bind.
    • Write the exact install, build, and launch commands into
      development.md and run them from a clean checkout.
  • Done: 20 of 20 launches reach the lobby with a readiness event within 10
    seconds; afterwards pgrep -f codetrial shows no orphan; a second launch
    focuses the first; a port conflict, invalid config, and service failure each
    show an error and load nothing.
  • Evidence: docs/desktop/development.md, docs/desktop/evidence/D04b/.
  • Stop: a startup deadlock that persists through the spike, or step 6
    failing, goes to the maintainer: sidecar fallback, extension, or stop.
D04c - Security implementation and adversarial tests
  • Accountable: desktop developer, reviewed by the security reviewer.
    Depends on: D04b. Must pass before any build leaves the developer's machine.
  • Steps:
    • Implement the D02 secret file and the Host allowlist for setup and main
      service in desktop mode.
    • Write explicit capability files granting only the required operations to
      the named window and the exact remote.urls loopback origin. Configure
      application-command permissions separately from plugin permissions.
      Initially grant no optional IPC.
    • Reject navigation and frames to other origins; if the service fails,
      take the window away instead of reconnecting to a new port occupant.
    • Implement every row of the D02 status table as a test in
      tests/web.rs or tests/unit/launch.rs.
    • From an untrusted page and an untrusted frame, call each prohibited
      bridge command and record that it is rejected. A missing frontend global
      is not proof of denial.
    • Check that no secret appears in URLs, logs, or frontend storage.
    • Run ./scripts/test.sh.
  • Done: every D02 row passes; step 5 records a rejection for each command.
  • Evidence: docs/desktop/evidence/D04c/.
  • Stop: the security reviewer blocks any bridge exposure. Release is blocked
    until resolved.
D05 - Qualify core features in packaged WKWebView
  • Accountable: test lead. Depends on: D04b (core), D04c (remaining cases),
    D00 credentials and budget. Core cases are spike day 4-5.
  • Inputs: packaged app from the development.md procedure, its checksum.
  • Steps:
    • Record the environment in docs/desktop/evidence/D05/environment.md.
    • Create docs/desktop/evidence/D05/cases.csv with columns case ID,
      action, expected, actual, result (pass/fail/unsupported), duration,
      diagnostic link. One row per D00 case.
    • Core cases, in order:
      • C1 microphone and camera prompts appear; grant succeeds.
      • C2 preflight completes (mic meter moves; face check runs or reports
        unavailable).
      • C3 interviewer audio is heard; candidate speech is transcribed.
      • C4 speaking over the interviewer interrupts it.
      • C5 a Python test run through Pyodide passes.
      • C6 ending the interview renders the report and its save is confirmed.
      • C7 quit and relaunch; the report is listed in history.
    • Remaining cases: JavaScript runner, Compiler Explorer languages if
      enabled, face Worker/WASM, avatar render and cache, whiteboard input,
      export/download, replay (only with an authorized fixture), denied
      microphone, denied camera, unplug and replug, output selection or its
      fallback, 30-second network drop, five minutes backgrounded, sleep/wake.
    • After any compatibility fix, run
      node --test tests/browser/runners.test.js tests/browser/face-presence.test.js tests/browser/avatar-model.test.js tests/browser/history.test.js tests/browser/report-recovery.test.js
      and add a regression test for the fix.
  • Done: C1-C7 pass in the packaged app; every other case has a result, and
    unsupported ones show defined UI behavior. Chromium and Node runs do not
    certify WKWebView.
  • Evidence: docs/desktop/evidence/D05/.
  • Stop: at the end of spike day 5, the maintainer records stop, an explicit
    extension in days, or browser fallback. No optional integration starts
    while C1-C7 fail.
D06a - OAuth (only if D00 requires it)
  • Accountable: authentication developer, reviewed by the security reviewer.
    Depends on: D04c, D05.
  • Steps:
    • Read login_handler, callback_handler, and the cookie helpers in
      src/web/auth.rs, src/accounts/sessions.rs, and the login UI in
      web/app.js.
    • In proposed docs/desktop/support.md, record GitHub's current redirect
      URI rules and embedded user-agent policy, with URLs and retrieval date,
      and the chosen session handoff (for example system browser plus loopback
      callback on port 3101). Keep any client secret out of the installer.
    • Implement after the security reviewer approves step 2.
    • Test with a disposable OAuth app: cancellation, wrong state, replayed
      callback, cold and warm launch, session established in the WebView.
  • Done: step 4 passes. Evidence: docs/desktop/evidence/D06a/.
  • Stop: unsupported redirect rules, embedded-login restrictions, or secret
    distribution block account-enabled desktop release; the maintainer decides.
D06b - Recording (only if D00 requires it)
  • Accountable: test lead with the policy owner. Depends on: D06a.
  • Steps:
    • Read docs/recording-contract.md, src/web/recordings/mod.rs, and
      scripts/recording-integration.sh; list the acceptance phases and their
      credential prerequisites in support.md.
    • Run those phases from the packaged app. Do not weaken the verified
      identity requirement.
  • Done: every listed phase passes. Evidence: docs/desktop/evidence/D06b/.
  • Stop: the policy owner blocks any contract deviation.
D06c - Meet presentation (only if D00 requires it)
  • Accountable: test lead. Depends on: D05.
  • Steps:
    • Run docs/meet-tab-audio-manual-check.md, adapted to window or system
      audio capture, with two participants, two endpoints, and headphones.
    • Record whether interviewer audio and candidate speech both reach the
      remote participant, whether either is duplicated, whether echo is
      audible over two minutes, and what is captured (window or whole system).
  • Done: results recorded in that document's results format.
  • Stop: if it fails, desktop shows that Meet presentation needs the browser,
    with the browser route, before an unsupported flow starts.

For any deferred D06 feature, change web/app.js or web/interview.js to show
the limitation and the tested browser route, and test that UI.

D07 - Preserve report semantics through close and recovery
  • Accountable: desktop developer, reviewed by the report owner.
    Depends on: D03a, D05.
  • Steps:
    • Read endInterview, receiveReport, saveHistory, and
      renderReportSaveStatus in web/interview.js; web/before-unload.js;
      web/report-recovery.js; saveReportHistory and reportIsPersisted in
      web/history.js.
    • Create proposed docs/desktop/close-state-machine.md mapping the actual
      state.phase values and the paused, receiving, and save-result flags to
      the close actions: close now, cancel, end and wait, export, or discard
      explicitly.
    • Add the smallest completion signal the native close needs (for example
      endInterview returning a promise that settles on the existing save
      result), reusing the existing report deadlines and recovery UI. No second
      report generator.
    • In the desktop host, intercept close and Quit, keep them idempotent
      (repeated events share one pending operation), and await asynchronously
      without blocking the native event loop.
    • Add browser tests covering idle, preflight, live, paused, ending, report
      recovery, save failed, saved, and repeated close; extend
      tests/browser/interview-lifecycle.test.js and
      tests/browser/report-recovery.test.js.
    • Run node --test tests/browser/interview-lifecycle.test.js tests/browser/report-recovery.test.js tests/browser/history.test.js.
    • Packaged runs: each phase from step 5 crossed with close and Quit, plus
      three rapid double-closes and three closes during a failed save (at least
      20 runs). Then three forced kills during live and during ending.
  • Done: no acknowledged save is lost; the camera indicator is off within five
    seconds; pgrep -f codetrial shows no owned process after exit; forced
    kills reopen with committed data intact.
  • Evidence: close-state-machine.md, docs/desktop/evidence/D07/.
  • Stop: the report owner blocks save loss. Do not persist live session
    snapshots or frozen prompts for crash recovery; a forced kill does not
    promise an ungenerated report.
D08 - Add only the integrations D00 selected
  • Accountable: frontend developer. Depends on: D04b, D05, D07.
  • Steps:
    • Create proposed web/desktop.js: fullscreen and report-ready
      notification, each a no-op when window.__TAURI__ is absent, with no
      import that needs a frontend build step.
    • Load it from web/interview.html and call it from web/interview.js.
      Update tests/browser/dom-contract.test.js if the DOM contract changes.
    • Add only the needed plugin permissions to the D04c capability files.
    • Trigger the notification once per report, when reportIsPersisted
      reports a confirmed save. The body is generic, with no report content.
      Clicking it focuses the interview window. Ask permission in context.
    • Add proposed tests/browser/desktop.test.js: absent globals, denied
      permission, duplicate save callbacks. Run node --test on it.
    • Packaged runs: 20 fullscreen cycles during a live interview, and 20
      notifications with permission granted and Do Not Disturb off. Record
      denial and Do Not Disturb separately.
  • Done: fullscreen keeps media and phase in 20 of 20 runs; 20 of 20
    notifications arrive within five seconds of the confirmed save.
  • Evidence: docs/desktop/evidence/D08/.
  • Stop: an integration needing broad system permission or touching scoring
    goes back to the maintainer before implementation.
D09a - Benchmark instrumentation
  • Accountable: performance tester. Depends on: D01, D05, D07, D08.
  • Steps:
    • Create proposed scripts/desktop_benchmark.py for three variants: V1
      manual URL, V2 auto-open (D01), V3 Tauri app (D04b). It records monotonic
      timestamps for launch, service ready, interactive lobby, preflight done,
      and interviewer connected, on one clock.
    • Resource sampling: attributable process tree once per second, using the
      platform's memory accounting, with shared-memory limits documented.
    • Create proposed tests/test_desktop_benchmark.py (unittest) on fixed
      fixtures: timestamp ordering, failed trials kept, nearest-rank
      percentiles, bootstrap 95% confidence interval (10,000 resamples), and the
      formulas in Release criteria. Register it as a gate.
  • Done: ./scripts/test.sh passes with the new gate.
  • Evidence: docs/desktop/evidence/D09a/.
D09b - Performance and resource trials
  • Accountable: performance tester. Depends on: D09a.
  • Steps:
    • In random order, 30 process-cold and 30 warm launches per variant. Run
      any cache-cold study separately.
    • Three repetitions of five idle and ten active minutes per variant on a
      fixed interview workload.
    • Store launches.csv, resources.csv, environment.json; produce
      analysis.md with proposed
      python3 scripts/desktop_benchmark.py --recompute docs/desktop/evidence/D09b.
  • Done: every number in analysis.md reproduces from the raw CSV; timeouts
    stay as failed trials.
  • Stop: if a confidence interval crosses a target, the maintainer approves a
    bounded extra run count or the result is labeled inconclusive.
D09c - Usability study (only if D00 approved it)
  • Accountable: usability tester. Depends on: D09a, D00 approval.
  • Steps:
    • At least 20 new users per workflow, assigned before testing, with equal
      service access.
    • Success is reaching the interactive lobby unassisted. Record setup time,
      permission time, failures, and assistance separately.
  • Done: counts, medians, and confidence intervals reported; 19/20 is a sample
    outcome, not a population rate.
  • Evidence: aggregates in docs/desktop/evidence/D09c/; participant data in
    the private location.

D09 decision: the maintainer records which benefit qualifies (D09b speed or
resources, D09c usability, or a D08 integration with a stated use). If none
does, recommend auto-open and stop release investment.

D10-prep - Signing access (parallel, after D00)
  • Accountable: release engineer. Steps: complete Apple Developer Program
    enrollment, issue a Developer ID Application certificate to a named holder,
    create a notarytool keychain profile, and store CI secrets with a named
    owner. Done: a test binary signs and notarizes. Stop: without membership,
    D10 ends at an ad-hoc local build.
D10a - CI and versioning
  • Accountable: release engineer. Depends on: D04c, D05-D09, D10-prep.
  • Steps:
    • Read the build matrix and release job in
      .github/workflows/check.yml and docs/install.md.
    • Add a macOS desktop job to the build matrix without changing the CLI
      artifacts or the rolling latest release.
    • Publish desktop artifacts under their own immutable tags (for example
      desktop-v0.1.0) with monotonic versions.
  • Done: CI produces the desktop artifact on a tag push; CLI releases are
    unchanged.
D10b - Sign, notarize, and install
  • Accountable: release engineer. Depends on: D10a.
  • Steps:
    • Write proposed docs/desktop/release.md with tested build, sign,
      notarize, staple, install, uninstall, and previous-version recovery
      commands, including
      # proposed: xcrun notarytool submit "$DESKTOP_ZIP" --keychain-profile "$PROFILE" --wait.
    • On the artifact, run
      codesign --verify --deep --strict --verbose=2 "$DESKTOP_APP",
      spctl --assess --type execute --verbose=2 "$DESKTOP_APP", and
      xcrun stapler validate "$DESKTOP_APP", recording the real paths.
    • Download it with quarantine intact onto a clean macOS account; run fresh
      setup, permissions, data paths, history, D03b import if in scope, and
      CLI coexistence.
  • Done: all three checks pass; spctl reports accepted; step 3 passes.
  • Evidence: release.md, docs/desktop/evidence/D10b/, checksum.
D10c - Media qualification and release decision
  • Accountable: test lead, then the maintainer. Depends on: D10b.
  • Steps:
    • Ten sessions of the configured default length (45 minutes today,
      docs/interview-length.md) through report delivery, per declared
      configuration, within the D00 budget.
    • Record disconnects, report persistence, device release, and service
      spending per session.
    • Run ./scripts/test.sh and disclose skipped lanes.
  • Done: zero app-caused disconnects, missing reports, or device leaks;
    a go/no-go record that cites the D09 benefit.
  • Evidence: docs/desktop/evidence/D10c/.
  • Stop: unresolved save loss, bridge exposure, or a required unsupported
    feature is a no-go. Auto-update is a separate future package; v1 ships
    manual signed installers.
D11-win and D11-linux - Separate platform qualification
  • Accountable: one platform developer per OS. Depends on: D10c.
  • Steps (per OS):
    • Create proposed docs/desktop/windows.md or docs/desktop/linux.md
      naming OS and runtime versions (WebView2 bundled or bootstrapped; distro
      and WebKitGTK version), architectures, devices, build host, installer
      format, and signing choice. Unsigned Windows behavior is stated; a
      certificate does not promise no SmartScreen prompt.
    • List the applicable D03a-D10c case IDs and justified exclusions.
    • Split the work into one-to-three-day packages: paths and build, startup
      and security, media and lifecycle, installer and recovery.
    • Run the build and install commands and record them.
    • Run D05 C1-C7 and the remaining cases, D07, D08, D10b equivalents, ten
      default-length sessions per declared configuration, and D09b.
  • Done: each platform has its own artifacts, commands, and support matrix.
    macOS results do not count.
  • Stop: missing core media support blocks that platform only; the maintainer
    defers it and the browser route remains.
D12 - Optional gaze feasibility study
  • Accountable: policy owner first, then an ML engineer. Depends on: D10c and
    a separately approved budget.
  • Steps:
    • The policy owner records whether the proposed use is permitted under
      docs/integrity-evidence.md (which refuses gaze-direction inference at
      line 129) and docs/observable-delivery-policy.md. If it is not, stop
      here unless a contract revision is approved first.
    • Create proposed docs/desktop/gaze-study.md: one output (head direction,
      gaze direction, or screen coordinates), maximum error, minimum coverage,
      tolerated false alerts per hour, cohort size, consent and withdrawal,
      reference measurement, calibration, and retention.
    • Write the evaluation commands before collecting data.
    • Compare web and native at the same sampling rate and accuracy; report
      LiveKit published-track frame rate with and without the gaze pipeline
      (five-minute runs, three repeats), latency, CPU, and energy.
  • Done: every limit in step 2 has a pass/fail result; missing calibration or
    samples stay neutral.
  • Evidence: aggregates in docs/desktop/evidence/D12/.
  • Stop: the policy owner blocks prohibited inference; feasibility implies no
    scoring or integrity integration.
D13 - Optional tinyjs reassessment
  • Accountable: desktop maintainer. Depends on: D10c, D09b raw data, a
    separately approved budget, and one numeric improvement hypothesis.
  • Steps:
    • Create proposed docs/desktop/tinyjs-reassessment.md: pinned tinyjs
      version, platform support and security/update sources, chosen threshold,
      a 24-month comparison horizon, and engineering-hour rates.
    • Package the same revision as an owned sidecar, keeping the D02 and D03a
      origin, secret, and path rules; test shutdown and child ownership.
    • Run D05 C1-C7, D07, and D09b on equivalent hardware.
    • Estimate one-time migration and recurring maintenance hours.
  • Done: a screening threshold (20% better startup or memory, or 30% smaller installed size, with no reliability regression) is met with
    uncertainty, required cases pass, and savings exceed cost over 24 months.
  • Stop: no threshold-sized gain means keep Tauri and close the reassessment.

Existing checks

Runnable today:

cargo fmt --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --lib
cargo test --bin codetrial
cargo test --test cli
cargo test --test web
node --test tests/browser/interview-lifecycle.test.js \
  tests/browser/history.test.js tests/browser/report-recovery.test.js
./scripts/test.sh

Read scripts/server-check.sh and scripts/browser-check.sh before running
live checks: browser flow and agent modes need different credentials. Those
scripts qualify the browser and server; D05's packaged checks stay separate.

Read scripts/server-check.sh and scripts/browser-check.sh before live
checks; they qualify the browser and server, not the packaged WebView.
Proposed tooling (scripts/desktop_auto_open.py, scripts/desktop_benchmark.py,
src/launch.rs, src-tauri/, web/desktop.js) does not exist until its
package lands.

主要言語
Rust
スター
160
フォーク
64
平均マージ
1日 9時間
マージ済み PR(30日)
111

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

sysprog21/codetrial のほかの issue

sysprog21/codetrial の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。