Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
03b078d
Split Workshop route tests from handlers
vinniefalco Sep 5, 2026
97856d0
Replace the `serve` verb with root serving and `--config`
vinniefalco Sep 5, 2026
f303718
Extract gateway-logging crate with bounded priority queue
vinniefalco Sep 6, 2026
1009b3f
Add diagnostics report, five-run retention, and redaction
vinniefalco Sep 6, 2026
4a1136a
Fix rustdoc private links in gateway runner docs
vinniefalco Sep 6, 2026
ccb77bf
Pin gateway-logging dependency boundary, document logging
vinniefalco Sep 6, 2026
bde3846
Close plan: gateway-logging-cli
vinniefalco Sep 6, 2026
6e5f0ac
Pin batch and realtime speech behavior
vinniefalco Sep 6, 2026
bcc6582
Pin native Whisper runtime behavior
vinniefalco Sep 6, 2026
655dc16
Freeze the realtime transcription wire contract
vinniefalco Sep 6, 2026
6b7ec5f
Rename the transcription crate as the STT engine
vinniefalco Sep 6, 2026
672befe
Move take ownership into gateway STT
vinniefalco Sep 6, 2026
c7c1c1f
Separate Whisper from the STT engine
vinniefalco Sep 6, 2026
b8caab4
Enforce exact STT architecture ratchets
vinniefalco Sep 6, 2026
75f4cb3
Bound transcription workers and expose test fixtures
vinniefalco Sep 6, 2026
12a233f
Harden STT workers and extend release gates
vinniefalco Sep 6, 2026
3642d6d
Migrate STT tuning to canonical configuration
vinniefalco Sep 6, 2026
4b49007
Add bounded realtime audio ingestion
vinniefalco Sep 6, 2026
101deda
Define the private Realtime wire
vinniefalco Sep 6, 2026
04e887d
Pin STT architecture tools to Rust 1.89
vinniefalco Sep 6, 2026
f10f7c9
Remove unused STT test imports
vinniefalco Sep 6, 2026
32717a1
Stage Gateway sidecars for Workshop CI
vinniefalco Sep 6, 2026
c65961a
Bound Realtime session input ownership
vinniefalco Sep 6, 2026
1fc3c20
Finalize realtime items independently
vinniefalco Sep 6, 2026
b6021e4
Use preinstalled Rust on native runners
vinniefalco Sep 6, 2026
2550188
Replace the STT runtime with a speech facade
vinniefalco Sep 6, 2026
c9cbe63
Resolve Windows cache ownership by SID
vinniefalco Sep 6, 2026
15c210d
Quiesce speech generations before replacement
vinniefalco Sep 6, 2026
467a262
Make profile replacement transactional
vinniefalco Sep 6, 2026
909ffea
Separate Gateway and Workshop origin policies
vinniefalco Sep 6, 2026
6016500
Publish generic speech discovery facts
vinniefalco Sep 6, 2026
781172f
Streamline contributor and CI maintenance
seanpar203 Sep 6, 2026
1b50919
Mount Gateway Realtime transcription
vinniefalco Sep 6, 2026
dee47d7
Make session retirement cleanup event-driven
vinniefalco Sep 6, 2026
16c1b29
Gate Gateway Windows-only declarations
vinniefalco Sep 7, 2026
06cba48
Add the Workshop Realtime relay
vinniefalco Sep 7, 2026
d17d168
Implement recoverable browser speech capture
vinniefalco Sep 7, 2026
7452751
Migrate Workshop dictation to Realtime
vinniefalco Sep 7, 2026
6ce3872
Prove Realtime flows with canonical fixtures
vinniefalco Sep 7, 2026
4944116
Require a model before built-in chat turns
vinniefalco Sep 7, 2026
94357c3
Converge Workshop startup state
vinniefalco Sep 7, 2026
aeec7b4
Bind live hypotheses before commit acknowledgment
vinniefalco Sep 7, 2026
fb4e0bf
Converge chat sessions with live catalogs
vinniefalco Sep 7, 2026
e7216d9
Partition live hypotheses into disjoint fields
vinniefalco Sep 7, 2026
006ba06
Schedule and rebase whole-window hypotheses
vinniefalco Sep 7, 2026
2d1ecca
Reconcile explicitly skipped final ranges
vinniefalco Sep 7, 2026
3766461
Record installed acceptance and repair UI fixture
vinniefalco Sep 7, 2026
2b7537e
Reduce input.rs test line count
vinniefalco Sep 7, 2026
49001c6
Retire legacy speech seams
vinniefalco Sep 7, 2026
faf122f
Finalize generic Realtime STT architecture
vinniefalco Sep 7, 2026
d79823e
Bookend Gateway serving file logs
vinniefalco Sep 7, 2026
13fb8ee
Recover Workshop after local Gateway exits
vinniefalco Sep 7, 2026
5c80bbd
Close plan: generic Realtime STT
vinniefalco Sep 7, 2026
f434c41
Split Gateway Realtime integration coverage
vinniefalco Sep 7, 2026
af5e64d
Split Workshop relay integration coverage
vinniefalco Sep 7, 2026
cbd20b6
Enforce integration test suite ceilings
vinniefalco Sep 7, 2026
3012863
Bound formatted logging records
vinniefalco Sep 7, 2026
8f81dea
Order and bound logging queue admission
vinniefalco Sep 7, 2026
e4370e8
Bound logging stalls and shutdown
vinniefalco Sep 7, 2026
fc2f929
Pin native CI to the exact Rust toolchain
vinniefalco Sep 7, 2026
b492a99
Pin STT API toolchain and package selection
vinniefalco Sep 7, 2026
f8e07fb
Rotate logs within fixed byte budgets
vinniefalco Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Pre-commit hook: Fast formatting check before creating commits.
set -e

echo "==> Running cargo fmt --all --check..."
cargo fmt --all --check
16 changes: 16 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Pre-push hook: Comprehensive validation before pushing to remote.
set -e

echo "==> Checking headless gateway (AGENTS.md rule)..."
cargo check -p gateway --no-default-features

echo "==> Running Clippy on workspace..."
cargo clippy --workspace --exclude workshop --exclude workshop-server --all-targets --all-features -- -D warnings

if command -v cargo-deny >/dev/null 2>&1; then
echo "==> Running cargo deny check..."
cargo deny check
fi

echo "==> Pre-push checks passed successfully."
53 changes: 50 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ jobs:
with:
components: rustfmt, clippy

- uses: dtolnay/rust-toolchain@1.89.0

# cargo-public-api 0.52.0 requires nightly rustdoc JSON. Keep this exact
# and in sync with the explicit +toolchain invocation in the driver.
- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: nightly-2026-09-05

- name: Cache cargo
uses: Swatinem/rust-cache@v2

Expand All @@ -41,14 +49,33 @@ jobs:
with:
node-version: 22

- name: Install UI dependencies
working-directory: crates/workshop-server/ui
run: npm ci
- name: Test integration test ceiling driver
run: node tools/check-integration-test-ceilings.test.mjs

- name: Check integration test ceilings
run: node tools/check-integration-test-ceilings.mjs

- name: Install architecture tools
run: |
RUSTUP_TOOLCHAIN=1.89.0 cargo install cargo-modules --version 0.25.0 --locked
RUSTUP_TOOLCHAIN=1.89.0 cargo install cargo-public-api --version 0.52.0 --locked

- name: Install config UI dependencies
working-directory: crates/gateway-config-ui/ui
run: npm ci

- name: Build Gateway without Workshop UI tooling
run: cargo build --locked -p gateway

- name: Test STT architecture driver
run: node --test tools/check-stt-architecture.test.mjs

- name: Check STT module and public API architecture
run: node tools/check-stt-architecture.mjs

- name: Check STT Cargo and ceiling architecture
run: cargo test -p gateway-stt --test it architecture

- name: Format
run: cargo fmt --all --check

Expand Down Expand Up @@ -108,12 +135,22 @@ jobs:
working-directory: crates/workshop-server/ui
run: npm ci

- name: Build featureless Gateway
run: cargo build --locked -p gateway --no-default-features

- name: Stage Gateway sidecar
run: node tools/stage-gateway-sidecar.mjs stage --target x86_64-pc-windows-msvc --source target/debug/promptforge-gateway.exe

- name: Clippy (workshop)
run: cargo clippy -p workshop -p workshop-server --all-targets -- -D warnings

- name: Test (workshop)
run: cargo test --locked -p workshop -p workshop-server

- name: Remove Gateway sidecar
if: always()
run: node tools/stage-gateway-sidecar.mjs remove --target x86_64-pc-windows-msvc

- name: Clean tree
shell: bash
run: |
Expand Down Expand Up @@ -156,9 +193,19 @@ jobs:
working-directory: crates/workshop-server/ui
run: npm ci

- name: Build featureless Gateway
run: cargo build --locked -p gateway --no-default-features

- name: Stage Gateway sidecar
run: node tools/stage-gateway-sidecar.mjs stage --target x86_64-unknown-linux-gnu --source target/debug/promptforge-gateway

- name: Build (workshop, Linux)
run: cargo build --locked -p workshop

- name: Remove Gateway sidecar
if: always()
run: node tools/stage-gateway-sidecar.mjs remove --target x86_64-unknown-linux-gnu

- name: Clean tree
shell: bash
run: |
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/dist-ci/build-setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: crates/*/ui/package-lock.json
- name: Install UI dependencies
run: npm ci --prefix crates/workshop-server/ui
- name: Install config UI dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/gateway-release-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
run: |
workdir="$(mktemp -d)"
printf 'config-version = 2\n[server]\nbind = "127.0.0.1:8081"\napi_key = "test-key"\n\n[[profile]]\nname = "main"\nmodels = []\n' > "$workdir/gateway.toml"
promptforge-gateway serve "$workdir/gateway.toml" --profile main &
promptforge-gateway --config "$workdir/gateway.toml" --profile main &
server_pid=$!
trap 'kill $server_pid 2>/dev/null || true' EXIT
for attempt in $(seq 1 30); do
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: crates/*/ui/package-lock.json
- name: Install UI dependencies
run: |
npm ci --prefix crates/workshop-server/ui
Expand Down Expand Up @@ -97,6 +99,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: crates/*/ui/package-lock.json
- name: Install UI dependencies
run: |
npm ci --prefix crates/workshop-server/ui
Expand Down Expand Up @@ -157,6 +161,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: crates/*/ui/package-lock.json

- name: Install UI dependencies
working-directory: crates/workshop-server/ui
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/release-workshop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: crates/*/ui/package-lock.json

- name: Install UI dependencies
working-directory: crates/workshop-server/ui
Expand All @@ -88,7 +90,7 @@ jobs:
# xdg-utils: the AppImage bundler shells out to xdg-open, which the
# ARM runner images do not preinstall (the x64 image does).
# https://github.com/tauri-apps/tauri-action/issues/1319
sudo apt-get install -y libwebkit2gtk-4.1-dev libssl-dev librsvg2-dev xdg-utils
sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev libssl-dev librsvg2-dev xdg-utils

# SIGNING (Windows): import the Authenticode certificate here once an
# EV/OV cert exists; tauri-action picks it up from the machine store.
Expand Down
184 changes: 184 additions & 0 deletions .github/workflows/stt-miri.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
name: STT Miri

on:
push:
branches: [master, main]
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
pure-stt-state:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: nightly-2026-09-05
components: miri

- name: Cache Cargo and Miri
uses: Swatinem/rust-cache@v2

- name: Prepare Miri
run: cargo +nightly-2026-09-05 miri setup

# Miri runs only backend-neutral ownership and bounded queue tests.
# Socket I/O, dynamic FFI, native callbacks, and model loading stay in
# their native CI targets because the interpreter cannot execute them.
- name: Check pure STT worker ownership and queues
run: cargo +nightly-2026-09-05 miri test -p gateway-stt-engine --features test-fixtures miri_

# Filters cover generation admission, explicit request and job counts,
# rollback epochs, registry and committed-item ownership, bounded
# results, final segments, and audio state. Spawned tasks stay native.
- name: Check pure STT generation and session ownership
run: cargo +nightly-2026-09-05 miri test -p gateway-stt --features test-fixtures miri_

native-whisper:
runs-on: [self-hosted, windows, cuda]
timeout-minutes: 90
env:
RUSTUP_TOOLCHAIN: 1.89.0
RUSTUP_AUTO_INSTALL: "0"
steps:
- uses: actions/checkout@v4

- name: Verify preinstalled MSRV Rust
shell: powershell
run: |
$ErrorActionPreference = 'Stop'
$requiredVersion = '1.89.0'
$contractName = 'PROMPTFORGE_RUST_1_89_0_BIN'
$contractBin = [Environment]::GetEnvironmentVariable($contractName)

if (-not [string]::IsNullOrWhiteSpace($contractBin)) {
$contractBin = $contractBin.Trim()
if (-not [IO.Path]::IsPathRooted($contractBin)) {
throw "self-hosted runner Rust $requiredVersion contract $contractName must be an absolute directory: '$contractBin'"
}
if (-not (Test-Path $contractBin -PathType Container)) {
throw "self-hosted runner Rust $requiredVersion contract $contractName directory does not exist: '$contractBin'"
}
$contractBin = (Resolve-Path $contractBin).Path
}

function Resolve-RustTool {
param(
[Parameter(Mandatory = $true)][string] $Name,
[string] $Bin
)

if (-not [string]::IsNullOrWhiteSpace($Bin)) {
$candidate = Join-Path $Bin "$Name.exe"
if (-not (Test-Path $candidate -PathType Leaf)) {
throw "self-hosted runner Rust $requiredVersion contract $contractName is missing $Name.exe at '$candidate'"
}
return (Resolve-Path $candidate).Path
}

$command = Get-Command "$Name.exe" -CommandType Application -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $command) {
throw "self-hosted runner Rust $requiredVersion is not provisioned: $Name.exe was not found on PATH; install it outside CI or set $contractName to its versioned bin directory"
}
return $command.Source
}

function Assert-RustToolVersion {
param(
[Parameter(Mandatory = $true)][string] $Name,
[Parameter(Mandatory = $true)][string] $ToolPath
)

$versionLines = @(& $ToolPath '--version' 2>&1)
$exitCode = $LASTEXITCODE
$versionText = ($versionLines | Out-String).Trim()
if ($exitCode -ne 0) {
throw "self-hosted runner $Name.exe failed at '$ToolPath' with exit code ${exitCode}; provision Rust $requiredVersion outside CI and expose it through PATH or $contractName. Output: $versionText"
}

$versionMatch = [regex]::Match(
$versionText,
"^$([regex]::Escape($Name))\s+(\d+\.\d+\.\d+)(?:\s|$)"
)
if (-not $versionMatch.Success) {
throw "self-hosted runner $Name.exe returned an unrecognized version at '$ToolPath'; required repository MSRV is exactly $requiredVersion. Output: $versionText"
}
$actualVersion = $versionMatch.Groups[1].Value
if ($actualVersion -ne $requiredVersion) {
throw "self-hosted runner $Name.exe has Rust toolchain version $actualVersion at '$ToolPath'; required repository MSRV is exactly $requiredVersion. Reprovision it outside CI or point $contractName at the correct versioned bin directory"
}

Write-Host "Using $Name $actualVersion from $ToolPath"
}

$cargo = Resolve-RustTool -Name 'cargo' -Bin $contractBin
$rustc = Resolve-RustTool -Name 'rustc' -Bin $contractBin
Assert-RustToolVersion -Name 'cargo' -ToolPath $cargo
Assert-RustToolVersion -Name 'rustc' -ToolPath $rustc

if (-not [string]::IsNullOrWhiteSpace($contractBin)) {
$contractBin | Add-Content -Path $env:GITHUB_PATH
}

- name: Cache Cargo
uses: Swatinem/rust-cache@v2

- name: Provision pinned native fixtures
shell: powershell
run: |
$fixture = Join-Path $env:RUNNER_TEMP 'stt-native'
New-Item -ItemType Directory -Path $fixture -Force | Out-Null
$archive = Join-Path $fixture 'whisper.zip'
Invoke-WebRequest `
-Uri 'https://github.com/cppalliance/promptforge/releases/download/whisper-lib-b4938/whisper-b4938-windows-x86_64-cuda.zip' `
-OutFile $archive
$runtimeHash = (Get-FileHash $archive -Algorithm SHA256).Hash
if ($runtimeHash -ne 'F1BC54D7288E21EE826CCB5767249836B780FC316BEC4A0374873E73163DAE12') {
throw "unexpected Whisper runtime hash: $runtimeHash"
}
Expand-Archive -Path $archive -DestinationPath $fixture -Force
$model = Join-Path $fixture 'ggml-tiny.en.bin'
Invoke-WebRequest `
-Uri 'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin' `
-OutFile $model
$modelHash = (Get-FileHash $model -Algorithm SHA256).Hash
if ($modelHash -ne '921E4CF8686FDD993DCD081A5DA5B6C365BFDE1162E72B08D75AC75289920B1F') {
throw "unexpected Whisper model hash: $modelHash"
}
$audio = Join-Path $fixture 'jfk.wav'
Invoke-WebRequest `
-Uri 'https://raw.githubusercontent.com/ggml-org/whisper.cpp/b4938/samples/jfk.wav' `
-OutFile $audio
$audioHash = (Get-FileHash $audio -Algorithm SHA256).Hash
if ($audioHash -ne '59DFB9A4ACB36FE2A2AFFC14BACBEE2920FF435CB13CC314A08C13F66BA7860E') {
throw "unexpected Whisper audio hash: $audioHash"
}
$fixture | Add-Content $env:GITHUB_PATH
"PROMPTFORGE_WHISPER_LIBRARY=$(Join-Path $fixture 'whisper.dll')" | Add-Content $env:GITHUB_ENV
"PROMPTFORGE_WHISPER_MODEL=$model" | Add-Content $env:GITHUB_ENV
"PROMPTFORGE_WHISPER_AUDIO=$audio" | Add-Content $env:GITHUB_ENV

- name: Test safe Whisper backend integration
run: cargo test --locked -p gateway-stt-backend-whisper --test native_whisper -- --ignored --test-threads=1

- name: Test native prompt budgets
run: 'cargo test --locked -p gateway-stt-backend-whisper --lib prompt::tests:: -- --ignored --test-threads=1'

- name: Test native Whisper FFI
run: cargo test --locked -p gateway-whisper-ffi --lib -- --ignored --test-threads=1

- name: Test native Gateway STT units
run: cargo test --locked -p gateway-stt --lib -- --ignored --test-threads=1

- name: Test native Gateway STT integration
run: cargo test --locked -p gateway-stt --test it -- --ignored --test-threads=1
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/guide/scratch/
*.env
# Voice test fixtures, downloaded out of band (see design/design-promptforge-workshop.md).
/crates/gateway-transcribe/tests/fixtures/
/crates/gateway-stt-backend-whisper/tests/fixtures/
# UI build pipeline: npm install target and the esbuild output. The build
# scripts write the bundle to OUT_DIR; `npm run build`/`--watch` still write
# dist/ in place for the jsdom tests, and none of it is tracked.
Expand All @@ -21,3 +21,4 @@
# The gateway sidecar staged for bundle.externalBin by CI before
# `tauri build` (crates/workshop/tauri.conf.json); a build artifact.
/crates/workshop/binaries/
/plan-dist-manifest.json
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ Multi-crate Rust workspace for the PromptForge pipeline runtime, the inference g
- Each crate's own AGENTS.md binds its subtree and is read together with this root file; nested files do not restate workspace-wide rules.
- The existing test suite stays green and intact during refactors: fix forward; never rewrite a test to make it pass.
- After completing work (compiles + tests pass), update README.md if the public surface changed.
- `config-ui` is a default gateway feature and always present in the desktop build. UI bundles are built by crate build scripts into `OUT_DIR` with esbuild; nothing UI-built is checked into the repo, so every build needs Node 22 and one `npm ci` per `ui/` folder. `cargo build` builds the gateway (workspace default member); `cargo build -p workshop` builds the desktop app.
- `config-ui` is a default gateway feature and always present in the desktop build. UI bundles are built by crate build scripts into `OUT_DIR` with esbuild; nothing UI-built is checked into the repo, so a build needs Node 22 and one `npm ci` for each UI crate it includes. `cargo build` builds the gateway (workspace default member); `cargo build -p workshop` builds the desktop app.
- Verify: Rust with `cargo test` at the workspace root (covers the gateway default member; CI runs the full workspace); UI with `npm run typecheck && npm test` in `crates/workshop-server/ui`; config UI with `npm run typecheck && npm run build && npm test` in `crates/gateway-config-ui/ui` (tests import built `dist/app.js`, so build first).
Loading
Loading