Avatar for the mpiton user
mpiton
forgent
BlogDocsChangelog

Performance History

Latest Results

feat(infra): T-226 shell detector for $SHELL / pwsh / cmd.exe Implement `infrastructure/pty/shell_detector.rs` per ARCHI §11.2. `detect()` returns a `ShellSpec { program, args }` that `PtyPool::spawn` will hand to `portable_pty::CommandBuilder`: - Unix: honours `$SHELL`, falls back to `/bin/bash` when unset or empty. - Windows: prefers `pwsh` (PowerShell 7) over `powershell.exe` over `%COMSPEC%` / `cmd.exe`. `-NoLogo` on PowerShell variants. `ShellSpec` derives `Serialize + Deserialize + TS` (exported to `src/shared/types/ShellSpec.ts`) so it can flow through debug IPC later. The Windows priority chain lives in a pure `resolve_windows_shell` helper that is unit-tested on every platform; Linux CI runners exercise the full pwsh > powershell > COMSPEC > cmd.exe fallback ladder without needing real PowerShell binaries. Three `temp_env::with_var` tests cover the Unix env-var fallback (set, unset, empty). `which = "8.0.2"` added via `cargo add --target 'cfg(windows)'` so the Unix build keeps the dependency surface lean. Closes #121
feat/T-226-shell-detector
10 days ago
fix(infra+ci): unblock smoke E2E by gating single_instance off under pilot feature (#119) Sprint 2 smoke E2E (T-224) hung on every GitHub Actions run since the merge of PR #118. tauri-pilot ping responded but `tauri-pilot wait --selector` timed out, snapshot artifact came back empty, and the daily app log file was never created — every signal we had pointed at "WebView never rendered" without explaining why. Boot-stage instrumentation on the `debug/smoke-webview-blank` branch (documented in CHANGELOG with run IDs) localised the hang to inside `builder.run(generate_context!())` BEFORE the user `setup()` closure. Root cause: `tauri_plugin_single_instance` uses zbus on Linux to register a well-known name on the D-Bus session bus during its plugin setup hook. xvfb provides X11 but not a session bus, so the registration call hangs forever. Even after wrapping the smoke under `dbus-run-session`, the plugin still raced against the bus daemon's name-release bookkeeping when the second consecutive `pnpm tauri dev` lifecycle started. Fix: 1. `src-tauri/src/lib.rs` — gate `tauri_plugin_single_instance` out under `cfg(not(feature = "pilot"))`. Production behaviour is unchanged: every shipped Tauri bundle builds with `--features` empty so the plugin stays active and prevents double-launch. The smoke harness already serialises lifecycles via PID + socket cleanup, so the plugin's protection is irrelevant there. 2. `.github/workflows/smoke-e2e.yml` — install `dbus-x11` and wrap the smoke command under `dbus-run-session --`. Belt-and-suspenders: if a future Tauri plugin or webkit2gtk transitive dep rediscovers a session-bus dependency, the smoke stays green without re-debugging from the same blank-WebView starting point. Verified on the debug branch (run 25866097897): both `pnpm tauri dev smoke (sprint-1)` and `pnpm tauri dev smoke (sprint-2)` jobs green end-to-end. Co-authored-by: Mathieu Piton <27002047+mpiton@users.noreply.github.com>
main
10 days ago
fix(infra+ci): unblock smoke E2E by gating single_instance off under pilot feature Sprint 2 smoke E2E (T-224) hung on every GitHub Actions run since the merge of PR #118. tauri-pilot ping responded but `tauri-pilot wait --selector` timed out, snapshot artifact came back empty, and the daily app log file was never created — every signal we had pointed at "WebView never rendered" without explaining why. Boot-stage instrumentation on the `debug/smoke-webview-blank` branch (documented in CHANGELOG with run IDs) localised the hang to inside `builder.run(generate_context!())` BEFORE the user `setup()` closure. Root cause: `tauri_plugin_single_instance` uses zbus on Linux to register a well-known name on the D-Bus session bus during its plugin setup hook. xvfb provides X11 but not a session bus, so the registration call hangs forever. Even after wrapping the smoke under `dbus-run-session`, the plugin still raced against the bus daemon's name-release bookkeeping when the second consecutive `pnpm tauri dev` lifecycle started. Fix: 1. `src-tauri/src/lib.rs` — gate `tauri_plugin_single_instance` out under `cfg(not(feature = "pilot"))`. Production behaviour is unchanged: every shipped Tauri bundle builds with `--features` empty so the plugin stays active and prevents double-launch. The smoke harness already serialises lifecycles via PID + socket cleanup, so the plugin's protection is irrelevant there. 2. `.github/workflows/smoke-e2e.yml` — install `dbus-x11` and wrap the smoke command under `dbus-run-session --`. Belt-and-suspenders: if a future Tauri plugin or webkit2gtk transitive dep rediscovers a session-bus dependency, the smoke stays green without re-debugging from the same blank-WebView starting point. Verified on the debug branch (run 25866097897): both `pnpm tauri dev smoke (sprint-1)` and `pnpm tauri dev smoke (sprint-2)` jobs green end-to-end.
fix/smoke-dbus-single-instance
10 days ago
feat(ci): T-224 Sprint 2 smoke E2E with persistence-after-restart (#118) * feat(ci): T-224 Sprint 2 smoke E2E + persistence-after-restart (closes #92) Add scripts/smoke-sprint-2.sh exercising the full Sprint 2 flow: boot pnpm tauri dev --features pilot → create project via ProjectTabBar → open TaskCreationWizard → drag card from Backlog to Code (with tasks_move IPC fallback for the @dnd-kit PointerSensor / tauri-pilot drag event-family mismatch) → kill the dev server via process-group TERM/KILL → reboot → assert tasks.phase still 'Code' AND the card re-renders under [data-testid="kanban-column-code-list"]. Workflow .github/workflows/smoke-e2e.yml restructures the single job into a strategy.matrix.scenario (sprint-1, sprint-2) with fail-fast disabled; apt install extends to sqlite3 + jq (required by the new script's sqlite probe + IPC poller); artifact paths and names are scenario-scoped so each shard uploads only its own bundle. Hardening reuse from PR #66 / T-134 is verbatim: setsid + negative- PID kill, plugin_socket_dir() XDG_RUNTIME_DIR fallback, per-lifecycle LOG_SIZE_BEFORE freshness gate, process-substitution log tail, pinned tauri-pilot-cli=0.5.1 --locked, redacted *_DISPLAY paths. Sprint 1 collateral fix: scripts/smoke-e2e.sh#L191's tasks_list --args '{}' is stale since T-211 added a required project_id: i64; payload changed to '{"project_id":1}' (Sprint 1 has zero projects so the WHERE filter still returns []). Without this, the new sprint-1 matrix row would block the AC "workflow green on main". Adversarial review hardening: poll_ipc_for_phase replaces the DOM-stability gate before sqlite probes (the optimistic-update path mutates the DOM before invokeTasksMove resolves); CI=true / FORGENT_SMOKE_FORCE_WIPE=1 guard prevents local invocations from wiping the developer's real tasks.db; preflight aborts when another dev server holds the pilot socket; process-group existence checks use kill -0 -- "-PGID" so cleanup catches orphaned grandchildren; TASK_ID validated against the v4 UUID regex before SQL interpolation. CHANGELOG entry under [Unreleased] Added. README smoke section points at both smoke-e2e.sh and smoke-sprint-2.sh. * fix(frontend): T-224 follow-up — IPC camelCase + tauri-pilot 0.5.2 + verified smoke green Round trip from running `FORGENT_SMOKE_FORCE_WIPE=1 ./scripts/smoke-sprint-2.sh` locally. The new gate caught three production defects + one upstream tooling bug that vitest could not surface (mocked `invoke` boundary hides Tauri 2's camelCase rename, and `pnpm tauri dev` is not part of the unit-test loop). Smoke now PASSES end-to-end on this commit. Production fixes: - `src/shared/ipc/tasks.ts` — `invokeTasksList`, `invokeTasksCreate`, `invokeTasksMove` now send the canonical camelCase wire keys (`projectId`, `targetPhase`) that Tauri 2's default `rename_all = "camelCase"` rewrite of `#[tauri::command]` parameter names expects. The previous snake_case payloads failed silently with `command X missing required key projectId` / `targetPhase` on every real IPC call. Invisible to `vitest` because the test suite mocked `@tauri-apps/api/core`'s `invoke` AND asserted the (broken) snake_case payload verbatim. `src/shared/ipc/tasks.test.ts` assertions + test names + a `/* … */` comment block (oxlint `capitalized-comments` on multi-line `//`) updated; 17/17 cases pass. - `scripts/smoke-e2e.sh` — Sprint 1 `tauri-pilot ipc tasks_list` payload follows the same camelCase rename. Still returns `[]` unchanged (Sprint 1 has zero projects in the wiped DB so the `WHERE project_id = ?` filter resolves empty regardless of the passed id). Tauri-pilot upstream bump (mpiton/tauri-pilot#91): - `src-tauri/Cargo.toml` + `Cargo.lock`: `tauri-plugin-pilot` 0.5.1 → 0.5.2 via `cargo add tauri-plugin-pilot@0.5.2 --optional` (per CLAUDE.md `cargo add` rule, no manual Cargo.toml edits). - `.github/workflows/smoke-e2e.yml` + `README.md`: `cargo install tauri-pilot-cli --version "=0.5.2" --locked`. - 0.5.2 fixes a long-standing internal-timeout cap on `wait` where any `--timeout` above 10000 ms was silently truncated to the hardcoded `DEFAULT_TIMEOUT`. We surfaced the bug from the Forgent harness — it manifested as "UUID-bearing testids time out" because the UUID-bearing `<li>` rows hydrate after API state lands, i.e. after the 10 s cap. Reported in https://github.com/mpiton/tauri-pilot/issues/91 with the comparative selector table, fixed in 0.5.2 by the upstream author within hours. `scripts/smoke-sprint-2.sh` refinements after live runs: - `boot_app`'s readiness gate switched from `[data-testid="kanban-board"]` to `[data-testid="project-tab-bar"]`. `<KanbanBoard>` only mounts when `selectedProjectId !== undefined` (`App.tsx:177-186`); a fresh DB has zero projects so lifecycle 1 renders `<TasksEmptyState />` and the old gate would always time out. `<ProjectTabBar>` is always rendered on the default `route="tasks"`. - DOM assertions replaced bounded `tauri-pilot wait --selector` with `for` loops over `tauri-pilot snapshot` + `grep`. `wait` is unreliable when the target sits behind a modal Radix Dialog (the TaskCreationWizard lingers a few frames after `onOpenChange(false)` and pushes `aria-hidden="true"` onto the background, hiding it from the matcher); the accessibility-tree snapshot exposes the full DOM regardless of `aria-hidden`. - Lifecycle-1 Code-column DOM check removed. Issue #92 step 6 only requires the sqlite probe (`tasks.phase = 'Code'`); step 7 reserves the DOM check for after restart. The IPC fallback (`tauri-pilot ipc tasks_move`) writes the DB but bypasses the Zustand store, so the lifecycle-1 UI does not re-render until a refetch trigger fires. Lifecycle 2's cold boot triggers a fresh `tasks_list` fetch via T-221, which is where the DOM assertion actually belongs per the issue spec. - `fail()` now dumps a best-effort `tauri-pilot snapshot` to `target/smoke-sprint-2-logs/snapshot-on-fail-<N>.txt` for post-mortem when the pilot socket is still up. Verified locally on commit e8ce3c8's branch: `FORGENT_SMOKE_FORCE_WIPE=1 ./scripts/smoke-sprint-2.sh` exits 0, produces all three screenshots, confirms `tasks.phase = 'Code'` post-lifecycle-1 drag, kills + restarts the app, re-verifies DB + DOM persistence after T-223/T-221 boot effects restore the selection. * fix(frontend): T-224 follow-up — App.test.tsx tasks_list assertions to camelCase Two regressions surfaced by the full vitest run on top of commit 1dbd149: - `App — kanban hydration … renders KanbanBoard and invokes tasks_list` - `App — kanban hydration … refetches tasks_list … when switching projects` Both asserted the previously-broken snake_case payload (`{ project_id: 1 }`) that `invokeTasksList` used to send. After the camelCase fix in `src/shared/ipc/tasks.ts`, the wrappers send `{ projectId: 1 }` so the assertions had to follow. 333/333 vitest cases now pass. CHANGELOG entry under T-224 extended with point (f). * fix(ci): T-224 PR #118 review pass — readme/header copy + lifecycle-aware log Three minor follow-ups surfaced by the CodeRabbit + cubic-dev-ai pass on PR #118. - `README.md` (CodeRabbit #3240080125): Sprint 1 quickstart probe example `tauri-pilot ipc tasks_list --args '{}'` is stale since T-211 added a required `project_id: i64` argument. Tauri 2's default `rename_all = "camelCase"` rewrites the wire key to `projectId`, so the payload becomes `'{"projectId":1}'`. Sprint 1 has zero projects in the wiped DB, so the `WHERE project_id = ?` filter still returns `[]`. - `scripts/smoke-e2e.sh:9` (CodeRabbit #3240080129 + cubic-dev-ai #3240111500): header comment showed the old positional-JSON form `tauri_pilot ipc tasks_list '{"projectId":1}'` (underscore + no `--args`). Updated to match the actual 0.5.x invocation: `tauri-pilot ipc tasks_list --args '{"projectId":1}'`. No behavior change — the body of the script already used the correct form at the call site. - `scripts/smoke-sprint-2.sh:48` (CodeRabbit #3240080133): `LOG_FILE="…/forgent.log.$(date -u +%Y-%m-%d)"` was evaluated once at script-load time, so a lifecycle-2 boot that crosses UTC midnight would stat yesterday's stale path. Replaced with a `current_log_file()` helper invoked inside `boot_app` (size-before capture) and inside the freshness assertion (post-boot). The user-facing `LOG_FILE_DISPLAY` placeholder changed from a baked-in date to `<YYYY-MM-DD>` to honestly reflect the lazy resolution. CHANGELOG entry (g) + (h) appended. * fix(ci): T-224 PR #118 review pass — UTC roll race between log size capture and grep cubic-dev-ai PR comment 3241391324 on `scripts/smoke-sprint-2.sh:304` flagged a residual race after the lazy log-path fix in 00e83a2: - `boot_app` captures `wc -c < $(current_log_file)` at start. - The dev server boots, the handshake completes (~tens of seconds on a cold cargo cache). - UTC midnight may roll between those two points. The daily roller inside `tracing_appender` opens a new dated file and writes `Forgent ready` to it. - Post-handshake `current_log_file()` resolves to the NEW path, which the byte offset captured at start refers to a DIFFERENT file. `tail -c "+SIZE+1"` then either reads past the end of a smaller new file (empty output) or skips the `Forgent ready` line altogether. Fix: capture both the path AND the size at start (`LIFECYCLE_LOG_PATH_AT_START` + `LIFECYCLE_LOG_SIZE_BEFORE`). Post-handshake, compare `current_log_file()` against the captured path. If they match (the common case), slice from the recorded offset. If they diverged (UTC roll happened during boot), read the new file from byte 0 — its entire content is post-launch by definition since the roller created it after the script started. CHANGELOG entry (i) appended under T-224. --------- Co-authored-by: Mathieu Piton <27002047+mpiton@users.noreply.github.com>
main
10 days ago
fix(ci): T-224 PR #118 review pass — readme/header copy + lifecycle-aware log Three minor follow-ups surfaced by the CodeRabbit + cubic-dev-ai pass on PR #118. - `README.md` (CodeRabbit #3240080125): Sprint 1 quickstart probe example `tauri-pilot ipc tasks_list --args '{}'` is stale since T-211 added a required `project_id: i64` argument. Tauri 2's default `rename_all = "camelCase"` rewrites the wire key to `projectId`, so the payload becomes `'{"projectId":1}'`. Sprint 1 has zero projects in the wiped DB, so the `WHERE project_id = ?` filter still returns `[]`. - `scripts/smoke-e2e.sh:9` (CodeRabbit #3240080129 + cubic-dev-ai #3240111500): header comment showed the old positional-JSON form `tauri_pilot ipc tasks_list '{"projectId":1}'` (underscore + no `--args`). Updated to match the actual 0.5.x invocation: `tauri-pilot ipc tasks_list --args '{"projectId":1}'`. No behavior change — the body of the script already used the correct form at the call site. - `scripts/smoke-sprint-2.sh:48` (CodeRabbit #3240080133): `LOG_FILE="…/forgent.log.$(date -u +%Y-%m-%d)"` was evaluated once at script-load time, so a lifecycle-2 boot that crosses UTC midnight would stat yesterday's stale path. Replaced with a `current_log_file()` helper invoked inside `boot_app` (size-before capture) and inside the freshness assertion (post-boot). The user-facing `LOG_FILE_DISPLAY` placeholder changed from a baked-in date to `<YYYY-MM-DD>` to honestly reflect the lazy resolution. CHANGELOG entry (g) + (h) appended.
feat/i-92-t-224-smoke-sprint-2-e2e
10 days ago

Latest Branches

CodSpeed Performance Gauge
0%
feat(infra): T-226 shell detector for $SHELL / pwsh / cmd.exe (closes #121)#133
10 days ago
06c65e1
feat/T-226-shell-detector
CodSpeed Performance Gauge
0%
fix(infra+ci): unblock smoke E2E by gating single_instance off under pilot feature#119
10 days ago
5ba139b
fix/smoke-dbus-single-instance
CodSpeed Performance Gauge
0%
10 days ago
386577d
feat/i-92-t-224-smoke-sprint-2-e2e
© 2026 CodSpeed Technology
Home Terms Privacy Docs