Compare commits

...
6 Commits
Author SHA1 Message Date
dev-agent 572bd9f8eb Merge pull request 'M1.5 accepted: tests over a published image' (#118) from image-accept into main
CI / checks (push) Successful in 2m40s
CI / e2e (push) Skipped
2026-10-07 23:14:45 +00:00
dongarandClaude Opus 5.5 d7e4fd0938 M1.5 accepted: the tests run over a published image
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 2m10s
CI / e2e (pull_request) Successful in 2m54s
- The Dockerfile's test stage stacks on TEST_BASE: this build's agent by
  default, or a published image. It adds only the test tools (uv export
  of the dev group into the image's environment), never reinstalling the
  agent, so the suite tests the image as published.
- scripts/e2e.sh --image passes NISSE_E2E_MODEL into the container.
- The plan marks M1.5 done: v0.1.0's published image passed the whole e2e
  suite (9 of 9, 11m37s), with the release's own tests over it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
2026-10-07 23:09:08 +00:00
dev-agent 13efa54f16 Merge pull request 'Test levels: smoke e2e on PRs, full set on e2e:full and before a release' (#117) from test-tiers into main
CI / checks (push) Successful in 2m42s
CI / e2e (push) Skipped
2026-10-07 22:55:15 +00:00
dongarandClaude Opus 5.5 28092194fe E2E on qwen3.8-27b without thinking
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 2m14s
CI / e2e (pull_request) Successful in 3m6s
The e2e roles move to qwen3.8-27b-nothink, a LiteLLM alias for the same
model with chat_template_kwargs enable_thinking false. With thinking, a
growing share of answers ran to 2-8k tokens (two hit the 8192 cap), which
took one test from 3.5 to 20 minutes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
2026-10-07 22:49:13 +00:00
dongarandClaude Opus 5.5 ff5a7a644f CI: install sshd from a fast mirror, or not at all
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 2m10s
CI / e2e (pull_request) Successful in 9m32s
archive.ubuntu.com has been crawling (a few KB/s), taking the sshd install
in every job from 8 seconds to 3.5-9.5 minutes (another agent measured it;
the runner and inference-4090 were healthy). scripts/ci-sshd.sh skips the
install when the image has sshd, and otherwise points apt at
mirrors.edge.kernel.org first (both source layouts, 22.04 and 24.04).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
2026-10-07 22:29:41 +00:00
dongarandClaude Opus 5.5 e35aea5045 Test levels: smoke e2e on PRs, the full set on e2e:full and before a release
- Every PR: lint, unit tests across the runner's cores (pytest-xdist), 16
  property walks from a seed that moves with the run number, integration
  tests, and the end-to-end smoke tests (the slice, a conversation filed
  as work, a question; `smoke` marker).
- A PR labelled e2e:full, a push to main, or a manual run: all 48 walks and
  the whole end-to-end suite. Adding e2e:full to a PR runs it; any other
  label runs nothing.
- A published release runs the full set before its image is built.
- The walk's seeds come from NISSE_WALK_SEEDS / NISSE_WALK_FIRST (48 from 0
  by default).

Measured here: the unit tier on 2 workers took 3m49s against 6-8 minutes
serially.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
2026-10-07 22:29:41 +00:00
11 changed files with 174 additions and 39 deletions

No files matched your search

+42 -20
View File
@@ -1,4 +1,10 @@
name: CI name: CI
# Three levels of testing:
# - every PR: lint, unit tests (16 property walks), integration tests, and
# the smoke end-to-end tests (`smoke` marker);
# - a PR labelled e2e:full, a push to main and a manual run: all 48 walks
# and the whole end-to-end suite;
# - a published release: the full set again before its image (release.yml).
on: on:
# Only main on push. A PR branch is already covered by the pull_request # Only main on push. A PR branch is already covered by the pull_request
# event, and running both fired two identical suites concurrently — which # event, and running both fired two identical suites concurrently — which
@@ -7,11 +13,18 @@ on:
push: push:
branches: [main] branches: [main]
pull_request: pull_request:
# labeled: adding e2e:full runs the full set; any other label, nothing.
types: [opened, synchronize, reopened, labeled]
# Manual re-run, e.g. after rotating a credential or raising a budget cap. # Manual re-run, e.g. after rotating a credential or raising a budget cap.
workflow_dispatch: workflow_dispatch:
env:
# Full on e2e:full, and outside PRs.
FULL: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'e2e:full') }}
jobs: jobs:
checks: checks:
if: github.event.action != 'labeled' || github.event.label.name == 'e2e:full'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -26,12 +39,10 @@ jobs:
- name: Install sshd - name: Install sshd
# The tests reach "the build VM" over real SSH, through a throwaway # The tests reach "the build VM" over real SSH, through a throwaway
# sshd the test fixture starts (nisse_dev/testing.py). # sshd the test fixture starts (nisse_dev/testing.py). Skipped when the image has it; otherwise from
run: | # a kernel.org mirror: archive.ubuntu.com has been slow enough to add
SUDO=$(command -v sudo || true) # minutes to every job.
$SUDO apt-get update -qq run: scripts/ci-sshd.sh
$SUDO apt-get install -y -qq openssh-server openssh-client > /dev/null
$SUDO mkdir -p /run/sshd
- name: Lint - name: Lint
run: uv run ruff check . run: uv run ruff check .
@@ -40,7 +51,12 @@ jobs:
run: uv run ruff format --check . run: uv run ruff format --check .
- name: Unit tests - name: Unit tests
run: uv run pytest -m "not integration and not e2e" # Across the runner's cores (pytest-xdist). On a PR, 16 property
# walks from a seed that moves with the run number; all 48 otherwise.
env:
NISSE_WALK_SEEDS: ${{ env.FULL == 'true' && '48' || '16' }}
NISSE_WALK_FIRST: ${{ env.FULL == 'true' && '0' || github.run_number }}
run: uv run pytest -n auto -m "not integration and not e2e"
- name: Integration tests - name: Integration tests
# Everything but the secrets is in tests/integration/nisse-test.yaml, # Everything but the secrets is in tests/integration/nisse-test.yaml,
@@ -58,12 +74,15 @@ jobs:
e2e: e2e:
# The end-to-end suite (scripts/e2e.sh): the whole agent against real # The end-to-end suite (scripts/e2e.sh): the whole agent against real
# services, every role on a local model, so it spends nothing but keeps # services, every role on a local model, so it spends nothing but keeps
# the RTX 4090 busy for ~25 minutes. On PRs only, and only after the # the RTX 4090 busy: ~10 minutes for the smoke tests, ~25+ for all. On
# checks pass: a PR that's red already doesn't spend the GPU. There is # PRs and manual runs, and only after the checks pass: a PR that's red
# one runner and Gitea doesn't honour cancel-in-progress, so a run a # already doesn't spend the GPU. There is one runner and Gitea doesn't
# newer push supersedes holds the runner until it's cancelled by hand. # honour cancel-in-progress, so a run a newer push supersedes holds the
# Locally, run only what you're writing (-k) or diagnosing (--lf). # runner until it's cancelled by hand. Locally, run only what you're
if: github.event_name != 'push' # writing (-k) or diagnosing (--lf).
if: >-
github.event_name != 'push'
&& (github.event.action != 'labeled' || github.event.label.name == 'e2e:full')
needs: checks needs: checks
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 90 timeout-minutes: 90
@@ -79,12 +98,10 @@ jobs:
run: uv sync --all-packages run: uv sync --all-packages
- name: Install sshd - name: Install sshd
# The build VM is a throwaway sshd here (scripts/e2e.sh --local). # The build VM is a throwaway sshd here (scripts/e2e.sh --local). Skipped when the image has it; otherwise from
run: | # a kernel.org mirror: archive.ubuntu.com has been slow enough to add
SUDO=$(command -v sudo || true) # minutes to every job.
$SUDO apt-get update -qq run: scripts/ci-sshd.sh
$SUDO apt-get install -y -qq openssh-server openssh-client > /dev/null
$SUDO mkdir -p /run/sshd
- name: End-to-end tests - name: End-to-end tests
env: env:
@@ -93,4 +110,9 @@ jobs:
NISSE_GITEA_TOKEN: ${{ secrets.NISSE_GITEA_TOKEN }} NISSE_GITEA_TOKEN: ${{ secrets.NISSE_GITEA_TOKEN }}
NISSE_OPERATOR_TOKEN: ${{ secrets.NISSE_OPERATOR_TOKEN }} NISSE_OPERATOR_TOKEN: ${{ secrets.NISSE_OPERATOR_TOKEN }}
NISSE_E2E_RUNS: /tmp/nisse-e2e-runs NISSE_E2E_RUNS: /tmp/nisse-e2e-runs
run: scripts/e2e.sh --local -v run: |
if [ "$FULL" = true ]; then
scripts/e2e.sh --local -v
else
scripts/e2e.sh --local -v -m "e2e and smoke"
fi
+41 -1
View File
@@ -3,7 +3,8 @@ name: Release
# registry (Development Plan M1.5, X4): gitea.dongar.net/dev/nisse-dev # registry (Development Plan M1.5, X4): gitea.dongar.net/dev/nisse-dev
# tagged with the version (the release tag without its v) and latest. Cut a # tagged with the version (the release tag without its v) and latest. Cut a
# release in Gitea (Releases → New release, tag vX.Y.Z); a tag pushed for any # release in Gitea (Releases → New release, tag vX.Y.Z); a tag pushed for any
# other reason builds nothing. # other reason builds nothing. The full test set runs first: no image without
# it passing.
# #
# The registry needs a personal access token with write:package # The registry needs a personal access token with write:package
# (REGISTRY_TOKEN, an organization secret of `dev`, belonging to the # (REGISTRY_TOKEN, an organization secret of `dev`, belonging to the
@@ -23,7 +24,46 @@ env:
IMAGE: gitea.dongar.net/dev/nisse-dev IMAGE: gitea.dongar.net/dev/nisse-dev
jobs: jobs:
tests:
# Everything, before an image exists: lint, unit tests with all 48
# property walks, integration tests and the whole end-to-end suite.
runs-on: ubuntu-latest
timeout-minutes: 150
env:
NISSE_LLM_TOKEN: ${{ secrets.NISSE_LLM_TOKEN }}
NISSE_MATRIX_TOKEN: ${{ secrets.NISSE_MATRIX_TOKEN }}
NISSE_GITEA_TOKEN: ${{ secrets.NISSE_GITEA_TOKEN }}
NISSE_OPERATOR_TOKEN: ${{ secrets.NISSE_OPERATOR_TOKEN }}
NISSE_E2E_RUNS: /tmp/nisse-e2e-runs
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Sync workspace
run: uv sync --all-packages
- name: Install sshd
run: scripts/ci-sshd.sh
- name: Lint
run: uv run ruff check . && uv run ruff format --check .
- name: Unit tests
run: uv run pytest -n auto -m "not integration and not e2e"
- name: Integration tests
run: uv run pytest -m "integration and not e2e" -rs
- name: End-to-end tests
run: scripts/e2e.sh --local -v
build-and-push: build-and-push:
needs: tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: read
+13 -8
View File
@@ -10,6 +10,12 @@
# docker build -t nisse-dev . the agent # docker build -t nisse-dev . the agent
# docker build --target test -t nisse-dev:test . plus the tests, for # docker build --target test -t nisse-dev:test . plus the tests, for
# scripts/e2e.sh --image # scripts/e2e.sh --image
# docker build --target test --build-arg TEST_BASE=<published image> \
# -t nisse-dev:test . the tests over a release as
# published (M1.5 acceptance)
# What the test stage stacks on: this build's agent, or a published image.
ARG TEST_BASE=runtime
FROM python:3.12-slim AS build FROM python:3.12-slim AS build
COPY --from=ghcr.io/astral-sh/uv:0.12.10 /uv /usr/local/bin/uv COPY --from=ghcr.io/astral-sh/uv:0.12.10 /uv /usr/local/bin/uv
@@ -40,9 +46,10 @@ VOLUME /var/lib/nisse-dev
USER nisse USER nisse
ENTRYPOINT ["nisse-dev"] ENTRYPOINT ["nisse-dev"]
# The image's own package plus the tests, so the end-to-end suite runs # The tests over an image's own package (this build's, or a published one,
# against what was built, not the source tree. # TEST_BASE): only the test tools are added, never the agent reinstalled, so
FROM runtime AS test # the end-to-end suite runs against what was built, not the source beside it.
FROM ${TEST_BASE} AS test
USER root USER root
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends git openssh-server \ && apt-get install -y --no-install-recommends git openssh-server \
@@ -57,11 +64,9 @@ COPY nisse-ops nisse-ops
COPY tests tests COPY tests tests
COPY scripts scripts COPY scripts scripts
COPY conftest.py ./ COPY conftest.py ./
ENV UV_PROJECT_ENVIRONMENT=/opt/nisse ENV UV_PROJECT_ENVIRONMENT=/opt/nisse UV_NO_SYNC=1
# Test tools too, all installed (not editable), and `uv run` never re-syncs: RUN uv export --frozen --only-group dev --no-hashes --no-emit-project > /tmp/dev.txt \
# the tests import the package as built, not the source tree beside them. && uv pip install --quiet --python /opt/nisse/bin/python -r /tmp/dev.txt
RUN uv sync --frozen --all-packages --no-editable --inexact
ENV UV_NO_SYNC=1
ENTRYPOINT [] ENTRYPOINT []
# The default target: the agent itself. # The default target: the agent itself.
+15 -6
View File
@@ -73,10 +73,14 @@ Only `nisse-dev` has real code; `nisse-core` and `nisse-ops` are placeholders.
`CLAUDE.md`. A milestone marked **needs discussion** starts with a design `CLAUDE.md`. A milestone marked **needs discussion** starts with a design
discussion first. discussion first.
- **Every change comes with tests,** through `scripts/check.sh`. - **Every change comes with tests,** through `scripts/check.sh`.
- **The end-to-end test runs on every PR** (M1.6): the real agent, every role on a - **Testing has three levels** (M1.6): every PR runs the checks (unit tests across
local model (so it costs nothing per call), a repository of the run's own and a the runner's cores, 16 property walks from a moving seed, integration) and the
real build host, driven by a scripted operator. CI runs it as its own job on pull end-to-end **smoke** tests; a PR labelled `e2e:full`, a push to `main` and a
requests, after the checks pass. There is one runner, and a run a newer push manual run add all 48 walks and the whole end-to-end suite; a published release
runs that full set before its image is built. The end-to-end tests drive the
real agent, every role on a local model (so they cost nothing per call), in a
repository of the run's own, with a scripted operator; CI runs them after the
checks pass. There is one runner, and a run a newer push
supersedes has to be cancelled by hand. Locally only the tests being written supersedes has to be cancelled by hand. Locally only the tests being written
(`-k`) or diagnosed (`--lf`); `scripts/e2e.sh` reports what a run spent. Manual (`-k`) or diagnosed (`--lf`); `scripts/e2e.sh` reports what a run spent. Manual
live runs are for the new loop's first runs and phase ends. Findings are filed as live runs are for the new loop's first runs and phase ends. Findings are filed as
@@ -271,8 +275,9 @@ in prose, asking mid-work (L5, #42, #77).
- Deferred: config reload without a restart (with M2.5's entry step if wanted); - Deferred: config reload without a restart (with M2.5's entry step if wanted);
the trust dial's configuration (M3.3). the trust dial's configuration (M3.3).
**M1.5 The agent as a container image.** *Pre-approved.* **Built** (this PR); **M1.5 The agent as a container image.** *Pre-approved.* **Done** (#115; accepted
accepted once a tag's image passes the e2e suite. 2026-10-07: `v0.1.0`'s published image passed the whole e2e suite, 9 of 9, run with
the release's own tests over it).
- A Dockerfile for `nisse-dev`, stateless with a volume for state; a Gitea Actions - A Dockerfile for `nisse-dev`, stateless with a volume for state; a Gitea Actions
workflow that builds it and pushes to Gitea's registry on each release tag (X4). workflow that builds it and pushes to Gitea's registry on each release tag (X4).
- `bringup.sh` runs the image instead of a venv. - `bringup.sh` runs the image instead of a venv.
@@ -283,6 +288,10 @@ accepted once a tag's image passes the e2e suite.
package, for `scripts/e2e.sh --image REF`. Images are built only on release: package, for `scripts/e2e.sh --image REF`. Images are built only on release:
`release.yml` pushes `gitea.dongar.net/dev/nisse-dev:<version>` and `:latest` `release.yml` pushes `gitea.dongar.net/dev/nisse-dev:<version>` and `:latest`
on a published release (`REGISTRY_TOKEN`, the `dev` organization's). on a published release (`REGISTRY_TOKEN`, the `dev` organization's).
- Acceptance runs the tests over a published image: `docker build --target test
--build-arg TEST_BASE=gitea.dongar.net/dev/nisse-dev:<version>` from the
release's checkout, then `scripts/e2e.sh --image`; the test stage adds only the
test tools, so the agent under test is the one published.
- The live bring-up's switch to the image waits for the next live test (it needs - The live bring-up's switch to the image waits for the next live test (it needs
its own test repository too); `bringup.sh plan` shows what it will run. its own test repository too); `bringup.sh plan` shows what it will run.
+9 -2
View File
@@ -8,6 +8,7 @@ checks every property after every step. A failure prints
the seed and the steps, so it replays exactly. the seed and the steps, so it replays exactly.
""" """
import os
import random import random
import re import re
import subprocess import subprocess
@@ -46,8 +47,14 @@ from nisse_dev.tools import Workspace
from nisse_dev.transport import InboundMessage, InMemoryTransport from nisse_dev.transport import InboundMessage, InMemoryTransport
from nisse_dev.worker import InlineWorker from nisse_dev.worker import InlineWorker
SEEDS = range(32) # How many walks, and from which seed: all 48 by default; CI runs fewer on a
TWO_PROJECT_SEEDS = range(100, 116) # PR, from a seed that moves with the run number, so PRs still cover new
# ground (NISSE_WALK_SEEDS, NISSE_WALK_FIRST). Two thirds walk one project,
# a third two.
_WALKS = int(os.environ.get("NISSE_WALK_SEEDS") or 48)
_FIRST = int(os.environ.get("NISSE_WALK_FIRST") or 0)
SEEDS = range(_FIRST, _FIRST + _WALKS * 2 // 3)
TWO_PROJECT_SEEDS = range(100 + _FIRST, 100 + _FIRST + _WALKS - _WALKS * 2 // 3)
STEPS = 30 STEPS = 30
+2
View File
@@ -4,6 +4,7 @@ members = ["nisse-core", "nisse-dev", "nisse-ops"]
[dependency-groups] [dependency-groups]
dev = [ dev = [
"pytest>=8", "pytest>=8",
"pytest-xdist>=3",
"ruff>=0.6", "ruff>=0.6",
] ]
@@ -19,6 +20,7 @@ addopts = "--strict-markers --ignore=tests/integration/seed"
markers = [ markers = [
"integration: end-to-end tests that exercise installed entry points or external services", "integration: end-to-end tests that exercise installed entry points or external services",
"e2e: the whole agent against real services, run after each milestone (scripts/e2e.sh)", "e2e: the whole agent against real services, run after each milestone (scripts/e2e.sh)",
"smoke: the end-to-end tests every PR runs; the rest on e2e:full and before a release",
] ]
[tool.ruff] [tool.ruff]
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# The throwaway sshd the tests need (nisse_dev/testing.py), in a CI job.
# Skipped when the job's image already has it. Otherwise apt fetches from a
# kernel.org mirror rather than archive.ubuntu.com, which has been slow
# enough (a few KB/s) to add minutes to every job.
set -euo pipefail
SUDO=$(command -v sudo || true)
if command -v /usr/sbin/sshd > /dev/null && command -v ssh > /dev/null; then
echo "sshd already installed"
else
MIRROR=${APT_MIRROR:-http://mirrors.edge.kernel.org/ubuntu}
# Both layouts: deb822 (ubuntu.sources, 24.04+) and sources.list (older).
for f in /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list; do
[ -f "$f" ] && $SUDO sed -i -E \
"s#https?://(archive|security)\.ubuntu\.com/ubuntu/?#$MIRROR/#g" "$f"
done
$SUDO apt-get update -qq
$SUDO apt-get install -y -qq openssh-server openssh-client > /dev/null
fi
$SUDO mkdir -p /run/sshd
+2
View File
@@ -23,6 +23,8 @@ if [ "${1:-}" = "--image" ]; then
mkdir -p "$runs" mkdir -p "$runs"
secrets=() secrets=()
[ -f .env ] && secrets=(--env-file .env) [ -f .env ] && secrets=(--env-file .env)
# The model, if overridden here, reaches the tests inside too.
[ -n "${NISSE_E2E_MODEL:-}" ] && secrets+=(-e "NISSE_E2E_MODEL=$NISSE_E2E_MODEL")
# Host networking: the suite reaches Matrix, Gitea and LiteLLM as here. # Host networking: the suite reaches Matrix, Gitea and LiteLLM as here.
exec docker run --rm --network host "${secrets[@]}" \ exec docker run --rm --network host "${secrets[@]}" \
-e NISSE_E2E_RUNS=/runs -v "$runs:/runs" \ -e NISSE_E2E_RUNS=/runs -v "$runs:/runs" \
+4 -2
View File
@@ -15,8 +15,10 @@ from nisse_dev.llm import RoleMap
# The end-to-end tests run every role on a local model, which costs nothing # The end-to-end tests run every role on a local model, which costs nothing
# per call; NISSE_E2E_MODEL overrides it (e.g. claude-haiku-4-5 for a quick, # per call; NISSE_E2E_MODEL overrides it (e.g. claude-haiku-4-5 for a quick,
# paid run). # paid run). The no-thinking alias (LiteLLM: chat_template_kwargs
E2E_MODEL = "qwen3.8-27b" # enable_thinking false): with thinking, some answers ran to 6-8k tokens,
# minutes each, and stretched a test from 3.5 to 20 minutes.
E2E_MODEL = "qwen3.8-27b-nothink"
def e2e_roles() -> RoleMap: def e2e_roles() -> RoleMap:
@@ -239,6 +239,7 @@ class Operator:
return self.transport.outbound[-1].text if self.transport.outbound else "" return self.transport.outbound[-1].text if self.transport.outbound else ""
@pytest.mark.smoke
def test_the_slice_end_to_end( def test_the_slice_end_to_end(
running: tuple[RunningLoop, InMemoryTransport, str], running: tuple[RunningLoop, InMemoryTransport, str],
) -> None: ) -> None:
@@ -501,6 +502,7 @@ def test_a_two_milestone_feature(
operator.tidy(issues, prs) operator.tidy(issues, prs)
@pytest.mark.smoke
def test_a_conversation_becomes_filed_work( def test_a_conversation_becomes_filed_work(
running: tuple[RunningLoop, InMemoryTransport, str], running: tuple[RunningLoop, InMemoryTransport, str],
) -> None: ) -> None:
@@ -636,6 +638,7 @@ def test_a_conversation_becomes_a_new_project(
assert any(f.startswith("docs/plans/") for f in files), files assert any(f.startswith("docs/plans/") for f in files), files
@pytest.mark.smoke
def test_a_question_leaves_the_restatement_up( def test_a_question_leaves_the_restatement_up(
running: tuple[RunningLoop, InMemoryTransport, str], running: tuple[RunningLoop, InMemoryTransport, str],
) -> None: ) -> None:
Generated
+23
View File
@@ -12,6 +12,7 @@ members = [
[manifest.dependency-groups] [manifest.dependency-groups]
dev = [ dev = [
{ name = "pytest", specifier = ">=8" }, { name = "pytest", specifier = ">=8" },
{ name = "pytest-xdist", specifier = ">=3" },
{ name = "ruff", specifier = ">=0.6" }, { name = "ruff", specifier = ">=0.6" },
] ]
@@ -46,6 +47,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
] ]
[[package]]
name = "execnet"
version = "2.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" },
]
[[package]] [[package]]
name = "h11" name = "h11"
version = "0.16.0" version = "0.16.0"
@@ -177,6 +187,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" },
] ]
[[package]]
name = "pytest-xdist"
version = "3.8.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "execnet" },
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" },
]
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "6.0.3" version = "6.0.3"