Skip to content

Log the cause when a capture recovery settlement fails #3514

Log the cause when a capture recovery settlement fails

Log the cause when a capture recovery settlement fails #3514

Workflow file for this run

name: Backend · Unit
# Pure, infra-free backend logic (the Category=Unit tests). No database, no network.
# Real-kernel bubblewrap/prlimit confinement tests live in their own CodeSpace.SandboxTests project
# (Category=Sandbox) and run in the dedicated sandbox-isolation workflow — never here.
#
# Category=RealBucket is excluded so this lane stays infra-free: those cases live in this project only
# because they inherit the shared artifact-storage driver conformance kit, and they drive a REAL object
# store over the network. They run only from the real-bucket workflow, on demand — never on a PR.
on:
push:
branches: [main]
paths:
- 'backend/**'
- '.github/workflows/backend-unit.yml'
# The real-model lane guards live here as scripts, and their self-tests are the ONLY place a PR can see them
# regress. Without this path a change to a guard merges unverified and is discovered by the lane it protects.
- '.github/scripts/**'
pull_request:
paths:
- 'backend/**'
- '.github/workflows/backend-unit.yml'
# The real-model lane guards live here as scripts, and their self-tests are the ONLY place a PR can see them
# regress. Without this path a change to a guard merges unverified and is discovered by the lane it protects.
- '.github/scripts/**'
workflow_dispatch:
concurrency:
group: backend-unit-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
DOTNET_NOLOGO: 'true'
DOTNET_CLI_TELEMETRY_OPTOUT: 'true'
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true'
jobs:
unit:
name: dotnet test (UnitTests)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Set up .NET 10
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: nuget-unit-${{ runner.os }}-${{ hashFiles('backend/**/*.csproj') }}
restore-keys: nuget-unit-${{ runner.os }}-
- name: Restore
run: dotnet restore backend/tests/CodeSpace.UnitTests/CodeSpace.UnitTests.csproj
- name: Test
run: >
dotnet test backend/tests/CodeSpace.UnitTests/CodeSpace.UnitTests.csproj
--no-restore
--filter "Category!=RealBucket"
--logger "console;verbosity=normal"
--logger "trx;LogFileName=unit.trx"
--results-directory backend/TestResults
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: backend-unit-trx
path: backend/TestResults/*.trx
if-no-files-found: ignore
# Proxy-packaging smoke: publish the API and assert the codespace-mcp proxy binary landed at the path
# LocalProcessRunner.McpProxyBinaryPath() resolves (next to the API assembly). Without this the MCP endpoint —
# even when enabled — fails closed to a tool-less run because the proxy was in no publish path. The unit suite
# also asserts File.Exists from the test bin (same ProjectReference mechanism); this proves the PUBLISH output.
# No --no-restore here: this job's restore targets the unit test project, which does NOT reference the API, so
# the API has no assets file yet — the publish must restore it (and its build-only CodeSpace.Mcp reference).
- name: Proxy packaging smoke (publish output)
run: >
dotnet publish backend/src/CodeSpace.Api/CodeSpace.Api.csproj -c Release -o backend/publish-smoke
&& test -f backend/publish-smoke/codespace-mcp
&& echo "codespace-mcp proxy is packaged in the API publish output"
|| (echo "::error::codespace-mcp proxy MISSING from the API publish output — the CopyMcpProxyToOutput/PublishMcpProxy target or the CodeSpace.Mcp ProjectReference regressed" && exit 1)
- name: Native launch host packaging smoke (publish output)
shell: bash
run: |
set -euo pipefail
version="$(backend/publish-smoke/runner-host/codespace-runner-host --protocol-version)"
test "$version" = "1"
# The real-model lanes gate on a shell script, so that script needs its own teeth checked somewhere a PR can
# see. It runs here rather than on the real-model lanes themselves because those only fire on push:main — a
# guard that regresses would then be discovered after the merge that broke it, by which point the lane it
# protects has already been reporting green over nothing.
- name: Real-model lane guard self-test
run: bash .github/scripts/assert-every-filter-clause-ran.test.sh
# Same reasoning for the artifact redaction: a redaction that fails OPEN still ships the secret while the step
# name claims it was handled, and only a PR-visible self-test catches that before the lane uploads again.
- name: Real-model artifact redaction self-test
run: bash .github/scripts/collect-real-model-verdicts.test.sh