334 Commits
Author SHA1 Message Date
blacksmith-sh[bot] aa46003581 .github/workflows: Migrate workflows to Blacksmith runners (#9802) 2026-10-10 20:54:59 -06:00
Alexander Eichhorn 71aeb7909f feat(db): move every query into one database layer and support MySQL and MariaDB (#9702) 2026-10-09 22:40:06 -06:00
Lincoln Stein a6b0ff66fc ci(docs): deploy main's docs to v7.invoke.ai
Build for https://v7.invoke.ai and force-push the site to invoke-ai/docs-v7's gh-pages branch with a deploy key; invoke.ai now deploys from v6-bugfixes.
Pushes to main always rebuild so a non-docs push cannot cancel an earlier docs deploy.
2026-10-07 21:47:31 -04:00
Lincoln Stein 49b57912a5 test(docs): unit-test sidebar ordering, cross-listing and pagination
Move the route middleware's sidebar logic into src/lib/sidebar.mjs and cover prefix ordering, alsoListedIn cross-listing, draft/hidden exclusion and prev/next with node --test.
Run the tests in the docs CI job.
2026-09-30 22:37:56 -04:00
Josh Corbett 2a45334b6c ci(frontend): retire legacy gates and share contract tooling
Run UI quality checks on webv2 and generate contracts with an independent locked API package.

Retain legacy type imports and bundle packaging; update generation commands, tests and ownership docs.
2026-09-29 18:47:06 -06:00
Josh Corbett 3033b535ef fix(frontend): use webv1 for legacy launch and tooling
Update legacy fallback, shared static assets, package data, build loops, CI filters, and developer commands.

Keep generated contracts and frontend storage identities unchanged; align guidance and launch fixtures.
2026-09-29 17:32:04 -06:00
Josh Corbett b50e0b1403 feat(frontend): make webv2 the default through call sites
Select webv2 for launches, frontend tooling, wheels, containers and dependency installation while preserving both source paths.

Retain explicit legacy fallback, shared API artifact ownership and deployment-scoped browser worker cleanup.
2026-09-29 14:19:20 -06:00
Lincoln Stein ed55540563 Merge branch 'main' into fix/windows-pytest-worker-count 2026-09-24 14:26:35 -04:00
Lincoln Stein b43adaf121 Merge remote-tracking branch 'origin/main' into fix/windows-pytest-worker-count 2026-09-24 12:14:19 -04:00
Lincoln Stein 47d98e76d3 Merge remote-tracking branch 'origin/main' into ci/rocm-container-build-timeout 2026-09-24 12:14:18 -04:00
Alexander Eichhorn 3bdcf99431 chore: drop python 3.11 support
Raise requires-python to >=3.12, <3.13 and regenerate uv.lock, which drops
the 3.11 resolution forks, the cp311 wheels, tomli and backports-tarfile.
No package version or source changes.
CI runs 3.12 only: the test matrix loses its 3.11 dimension, and deploy-docs,
openapi-checks and typegen-checks move off the 3.11 interpreter they pinned.
flake.nix moves python310 -> python312, which was already below the old floor.
2026-09-23 04:11:38 +02:00
Lincoln SteinandClaude Opus 5 b8dcb4adb4 ci: stop the rocm container build from timing out
The rocm leg of `build container image` has timed out four times
(2026-07-28, 2026-09-17 x2, 2026-09-22). It is not a regression: run
35724289637 (42m37s, timed out) and run 35724304187 (16m25s, green) were
pushed ten seconds apart on near-identical trees. Every phase of the slow
run was ~2.4x slower than the fast one - apt 59s->125s, `uv sync`
296s->529s, sbom 44s->178s, layer export 386s->927s. It is runner
quality, and the job had no headroom to absorb it.

It has no headroom because the rocm image is big: its venv layer is
7.2GB compressed (cuda 4.5GB, cpu 0.8GB), BuildKit gzips a single layer
on one thread, and there is no build cache, so ~6.5 min of the budget is
one gzip stream even on a healthy runner. A ~17 min median against a 40
min cap dies at a 2.3x slowdown.

So: raise the cap to 90 min, and drop the export from BuildKit's default
gzip -6 (~19MB/s here) to gzip -1, which is 2-3x faster for ~15% larger
layers. The cap is what actually fixes this - gzip -1 attacks the single
largest slice, but the build phases ahead of the export are untouched by
it.

Setting a compression level means using `outputs` instead of `push`, so
the condition `push` carried moves into the expression. It does not move
verbatim: `github.event.inputs.*` is always a string and every non-empty
string is truthy, so the bare reference the old expression ended in
evaluated as TRUE for an unchecked box. `push:` absorbed that because the
action ran it through core.getBooleanInput, which maps "false" to false.
`outputs:` is read with getInputList and passes any non-empty string
straight to --output, so the reference needs an explicit `== 'true'` or a
manual run from a non-main branch with the box unchecked would publish
that branch to ghcr. All seven trigger combinations were checked against
the old push decision and match.

Also fix the paths filter, which listed `workflows/build-container.yml`
without the `.github/` prefix - a path that does not exist, so edits to
this workflow never triggered it. Without this the change would not run
until some unrelated push happened to touch `invokeai/**` or the
Dockerfile.

`force-compression` stays off, so base-image layers keep their existing
compression and only newly built layers are affected.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-22 11:32:57 -04:00
Lincoln SteinandClaude Opus 5 0d69a0fc8c ci: run the windows python tests on two xdist workers
Windows ran one worker per vCPU, leaving no headroom for the helper
processes some tests spawn, and the deadline-sensitive tests missed their
budgets non-deterministically. The worker count and the job timeout are now
per-platform; linux and macos are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-21 22:32:40 -04:00
Lincoln Stein 3c19714da5 feat(ltx2): generate video and audio with LTX-2.5
Adds the single-stage text-to-video and image-to-video path: an inference
package, six invocations, and LTX-2 support in the webv2 Video panel. One
transformer produces both modalities at every step, so the soundtrack is
generated with the picture rather than dubbed onto it.
2026-09-19 22:26:04 -04:00
Josh Corbett eb5c98b917 fix(webv2): honor reviewed performance baselines in CI
Update five frontend dependencies and run the full release gate in CI.
Accept recorded byte growth while preserving request and structural limits.
Stabilize accessibility journeys and retain failure screenshots.
2026-09-15 03:26:43 -06:00
Alexander Eichhorn 2ae9fdd996 fix(architectures): backend owns VAE and scheduler policy; clear capability outage states
- Anima VAE nodes accept both Wan 2.1 VAE layouts; loaders derive VAE bases and validation from VaeFacet
- Z-Image Base scheduler set declared per variant; Ideogram 4 bounds pinned to the node
- Control layers and the Generate retry handle a missing capability table without false warnings or lost focus
2026-09-14 08:51:03 +02:00
Alexander Eichhorn a0c49ba93d Merge remote-tracking branch 'origin/main' into refactor/invocations-by-architecture 2026-09-14 04:44:00 +02:00
Lincoln Stein 8462753000 ci(webv2): judge byte budgets as a delta against the base branch
- Ceilings are derived at check time: the lower of max(1%, 4 KB) over the
  base-branch reference and max(10%, 32 KB) over the committed baseline;
  request counts take the lower count. `limits` blocks leave both baselines.
- Every push to main caches versioned build/browser reference files by SHA;
  PRs into main restore their base's entry (or the latest main) and fall
  back to the committed baseline, logged and annotated, when none applies.
- The re-record remedy is appended only for byte/request failures; source
  owners stay pinned exactly. ARCHITECTURE.md documents the derivation.
2026-09-13 15:52:10 -04:00
Alexander Eichhorn 70c852e896 fix(architectures): pin the latent space per base, and bound guidance from the node
The declaration this series exists to protect was itself checked for four of
sixteen bases: swapping FLUX_16 for SD3_16 in the FLUX declaration passed every
committed test and corrupted every FLUX preview at generation time. A 16-row
identity table now pins each base against the pre-refactor dispatch, and each of
the nine spaces has a hand-derived preview pixel. The smoothing-kernel test was
seeding after it drew its sample, so it had never been deterministic.

The guidance control's bounds now come from the architecture too, the way the
dimension grid already does. FLUX.2 accepts at most 20 and four architectures
reject below 1, while the input allowed 0 to 100 for every model -- so a value
the UI offered was rejected at enqueue. Pinned against the ge/le of the field
each denoise node actually validates.

Also: Ideal Size is no longer titled for SD, since it answers for every
architecture; the contributor docs describe the layout this branch created,
including the defs module whose absence refuses boot; and the docs-export test
no longer depends on pytest's working directory.
2026-09-12 05:17:14 +02:00
Alexander Eichhorn f538f2261a fix(architectures): report a variant's own latent compression, and gate the contracts in CI
A variant row reused its architecture's primary latent space, so Wan TI2V-5B
was served grid 32 next to compression 8 while it denoises in the 48-channel
Wan2.2 space at 16x. `LatentSpaceFacet` now names the space a variant uses --
checked to be one the facet already declares, so the two resolvers cannot
disagree -- and a variant that differs only there gets a row of its own.

The Python change filter skipped the two cross-stack generation contracts: a
frontend-only change could regenerate them, pass vitest, and never run the
backend half that validates them against the registries.
2026-09-12 03:27:35 +02:00
Josh Corbett 7fbe92fdb2 ci: cancel superseded PR runs in every check workflow
- Each PR workflow now has a concurrency group keyed by PR number, so a new push cancels the stale run; main pushes and merge groups fall back to the run id.
- Groups use a literal workflow name: `github.workflow` is the caller's name inside a reusable workflow, and release.yml calls several at once.
2026-09-11 14:57:48 -06:00
Josh Corbett 376c33e561 ci: let the pytest matrix finish when one platform fails
A single flaky runner no longer cancels the other five jobs, so a rerun repeats only the failed one.
2026-09-11 14:54:09 -06:00
Josh Corbett d4a00283f4 test(fp8): use float32 on CPU in the scaled-dequant fallback test
- The bf16 forward faulted with an illegal instruction (0xC000001D) in the Windows CPU torch build's GEMM on some runner CPUs, crashing the xdist worker in 8 of the last 60 runs.
- CPU inference is float32 in the product; the CUDA branch keeps bf16 and the assertion still catches a dropped scale.
2026-09-11 14:51:12 -06:00
Josh Corbett 91bc7065fd test: keep generation_devices copy check inside the Python tree
- The test only asserts the config field description now; the docs workflow's check-docs-data gate covers the generated settings, and UI/guide copy belong to their packages.
- python-tests no longer re-includes the legacy locale or docs files, so translation and docs edits skip pytest.
2026-09-11 14:16:36 -06:00
Josh Corbett 5ddd6744d2 ci: skip Python checks on frontend-only PRs
- Exclude invokeai/frontend/webv2 from the pytest, ruff, openapi, and typegen change filters; only legacy web was excluded before.
- Re-include the non-Python files pytest reads (webv2 workflow fixtures, legacy en.json, two docs files) and .py files under both frontend trees.
- python-checks now filters on **/*.py, matching what ruff lints from the root.
2026-09-11 14:04:41 -06:00
Alexander Eichhorn 78cb781b98 ci: give each xdist worker a single compute thread
Torch sizes its thread pools to the whole machine, so four workers on a four-vCPU
runner ask for sixteen compute threads. The Windows CPU build crashed a worker in
the fp8 tests under that contention, twice in two runs.
2026-09-09 17:56:32 +02:00
Alexander Eichhorn 90a8979de6 fix(tests): keep the guards the slow marker would have removed
Nothing in this repository runs `-m slow`, so marking a test removes it from CI
rather than moving it to a slower tier. Three guards go back to running:

- Loop-scheduler linearity now measures CPU time, which a worker losing its core
  does not inflate, so the ratio no longer has to be a benchmark. Its absolute
  sibling budget stays slow.
- bcrypt's work factor is read from the hash instead of timed; every other
  assertion in that file holds at cost factor 4.
- test_flux2_scaled_fp8_keys.py drops to 0.90GB from 1.96GB by expanding one
  element to the exact captured extents -- capping breaks it, because the fused
  qkv is split into thirds.

Each xdist worker now reports its peak RSS and a dead worker fails the run at
once, so the next memory blow-up is a number in the log rather than a runner
that vanishes mid-run. The extent helper moves to the state_dicts utils the four
copies of it should have used.
2026-09-09 17:34:54 +02:00
Alexander Eichhorn 49b40a7dfa perf(ci): run the python test suite in parallel
CI spent 21-26 min per matrix job entirely in pytest. Running it under xdist
(`-n logical`, one worker per vCPU) takes the full suite from 1083s to 271s at
four workers locally. `--dist loadfile` lives in addopts so it also holds when
`-n` is passed by hand.

Fixes test_client_state_multiuser.py, which inherited its JWT secret from a file
that happened to run earlier and errored on any worker that scheduled it first.
Wall-clock and throughput benchmarks move behind the existing `slow` marker;
their behavioral assertions stay in the default run.
2026-09-09 09:08:11 +02:00
Josh Corbett b338d0938f chore: merge upstream/main
Brings in upstream through ef832d1aa5 (v6.14.1 prep, diffusers 0.40, transactional image deletion, model cache shutdown eviction, streaming video upload, custom fonts).
- Video upload: upstream's streaming multipart parser now carries the fork's video/audio classification and ffmpeg ingest.
- Model cache: upstream's first-use claims replace the fork's grace holder; paced VRAM loading kept and releases the claim after the stream settles.
- uv.lock regenerated from the merged pyproject; openapi.json and schema.ts regenerate unchanged.
2026-09-07 17:59:57 -06:00
Josh Corbett d3c2fe7d07 ci(webv2): gate on check:architecture like main
- The accessibility journeys stay a local check:release step until they are re-authored against the current UI
- Journey locators updated for the Gallery center view and the Create widget rail
2026-09-07 12:35:12 -06:00
Josh Corbett 43cf0411b4 feat(agents): add codebase agent instructions
also updates gitignore to exclude planning files
2026-09-05 03:48:40 -06:00
Josh Corbett ae6a8813ad Merge origin/main and align persistence CI artifacts
Preserve settings changes from both branches, regenerate queue receipt API contracts and measured performance baselines, and format the enqueue regression. Allow the complete browser architecture gate to finish without reducing its coverage or sampling.
2026-09-04 18:18:34 -06:00
8dec0ffb57 chore(deps): remove dependency on Jupyter Notebook (and update uv) (#9409)
* chore(deps): remove dependency on Jupyter Notebook

* chore: update uv version to 0.11.28

(the version currently used by launcher)

* chore(deps): use the global form of exclude-dependencies, and finish the uv bump

Two fixes to how the Jupyter exclusion is declared and checked.

1. `exclude-dependencies = ["notebook"]` instead of the per-package table form.
   The table form is only understood by uv >= 0.11.25; on uv 0.10.0 - 0.11.24 it
   is a hard `Failed to parse: pyproject.toml / invalid type: map, expected a
   string`, which kills every uv command (sync, run, lock) for anyone whose uv is
   a few weeks old -- including contributors following the `uv sync --frozen` in
   docs/development/Setup/dev-environment.mdx. The global form has been accepted
   since uv 0.9.8, older uv merely warns and ignores it, and it resolves to
   exactly the same set: the regenerated lockfile differs only in the `[manifest]
   excludes` line, and the resolved package set is identical (63 packages
   removed, no version changes). No `required-version` is added on purpose -- it
   would hard-fail the uv 0.6.12 bundled in launcher <= 1.8.1, which today
   installs fine and, because the launcher syncs `--frozen`, already gets the
   trimmed environment straight from the lockfile.

2. typegen-checks.yml was the one workflow left on uv 0.6.10. That uv does not
   know `exclude-dependencies` at all, and on an unknown key it discards the
   *entire* `[tool.uv]` settings table -- `index-strategy = "unsafe-best-match"`
   and all four `[[tool.uv.index]]` definitions included -- with only a warning.
   Bumped to 0.11.28 like the other five.

Verified with real uv binaries: `uv lock --locked` passes on 0.9.8, 0.10.3,
0.11.24, 0.11.25 and 0.11.28 (0.10.3 and 0.11.24 could not even parse the file
before); `uv export --frozen` under 0.6.10 yields 131 packages with zero
Jupyter-chain entries; scripts/check_aarch64_lock.py, check_pins.py and
check_classifiers.py all pass.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JdJB9VXy5o6o7tfY1JSBCM

---------

Co-authored-by: Lincoln Stein <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-09-04 00:17:59 +00:00
Josh Corbett 6a8c9269ee Merge upstream/main into v7/main
# Conflicts:
#	invokeai/app/services/image_records/image_records_sqlite.py
#	tests/app/services/gallery/test_gallery_default.py
#	tests/app/services/image_records/test_image_records_sqlite.py
2026-08-07 19:38:04 -06:00
Kobi HikriandLincoln Stein 9a721fda6d ci: attach provenance and SBOM attestations to the published container (#9398)
* ci: attach provenance and SBOM attestations to the published container

* ci: restore trailing newline at end of file

---------

Co-authored-by: Lincoln Stein <[email protected]>
2026-08-07 17:01:35 +00:00
8486d47b7f ci: keep pins.json in sync with pyproject.toml (#9351)
* ci: add pins.json consistency check, bump ROCm index to 7.1

pins.json is consumed only by the Invoke Launcher (fetched at the release
tag) to pick the torch wheel index for legacy installs. Nothing in-repo
references it, so it silently drifted from pyproject.toml: its Linux ROCm
index stayed at rocm6.3 after the torch-rocm index moved to rocm7.1,
causing the launcher to install ROCm 6.3 wheels (#9328, launcher#131).

- Add scripts/check_pins.py, which fails if any torchIndexUrl entry in
  pins.json differs from the matching [[tool.uv.index]] URL in
  pyproject.toml.
- Run it from the uv-lock-checks workflow, triggered by changes to any of
  pyproject.toml, uv.lock, pins.json, or the check script.
- Bump pins.json rocm index to rocm7.1 (matches #9337) so the check
  passes.
- Bump the workflow's uv from 0.6.10 to 0.11.28: uv.lock is already lock
  format revision 3, which 0.6.x cannot parse.

Co-Authored-By: Claude Fable 5 <[email protected]>

* fix: cap torch below 2.12 on linux/windows

torch 2.12.x+rocm7.1 breaks generation (#9328; 2.11 works, and 2.10 is
what the rocm extra pins). The cap only matters for legacy (pre-6.14)
launcher installs, which resolve the base range live against the pytorch
wheel indexes instead of using uv.lock — with the range open to <3.0,
AMD users could land on the broken 2.12.x. Lockfile-based installs are
unaffected: uv.lock stays at 2.7.1 / 2.10.0+rocm7.1 (no locked versions
changed, only the recorded specifier).

Remove the cap once the 2.12 ROCm incompatibility is diagnosed.

Co-Authored-By: Claude Fable 5 <[email protected]>

* ci(check_pins): validate an explicit required platform/backend matrix

Addresses JPPhoto's review. The checker only iterated the entries that
already existed in pins.json, so deleting torchIndexUrl.linux.rocm still
exited 0 — recreating the exact silent-fallback failure the guardrail was
meant to prevent (the launcher only passes --index when the entry exists,
and its schema makes every backend key optional).

- Validate pins.json against REQUIRED_BACKENDS, an explicit matrix of the
  platform/backend combinations the launcher can select and Invoke supports.
  Missing entries, missing platform sections, unknown platforms and
  unsupported backends are now all errors, alongside the existing URL check.
- Split the logic into check_pins(), with main() taking a repo root, so the
  exit code is directly testable.
- Add tests/test_check_pins.py: removes each required entry in turn and
  asserts a nonzero exit, plus stale-URL, unknown-platform and
  unsupported-backend cases.
- pins.json: add the win32.cpu entry the matrix exposes as missing. Without
  it, a Windows "no dedicated GPU" legacy install gets no --index and pulls
  the CUDA-bundled PyPI torch wheel instead of the +cpu build. Linux already
  had this entry.
- python-tests: trigger on scripts/** and pins.json so these tests actually
  run when the checker or the pins change.
- Revert the uv 0.6.10 -> 0.11.28 bump in uv-lock-checks: 0.6.10 parses the
  revision-3 lock fine (verified), so the stated justification was wrong and
  the bump left this workflow out of step with python-tests.

* fix(deps): drop the blanket torch <2.12 cap; scope the ROCm caveat to docs

Addresses JPPhoto's second review. The cap was applied to the base
`sys_platform != 'darwin'` requirement, so it landed in published package
metadata for every Linux and Windows install — CUDA, CPU-only and Linux
ARM64 included — despite #9328 only ever reporting a ROCm 7.1 failure.

My original justification ("only affects legacy pre-6.14 launcher installs")
was wrong in both directions:

- It never protected legacy launcher installs. Those install an
  already-released version, resolving against that release's frozen PyPI
  metadata, not this pyproject.
- It never protected bootstrap (6.14+) launcher installs either. Those pass
  `invokeai[cpu|cuda|rocm]`, and every one of those extras pins torch
  exactly, so the base range is never consulted.
- What it did affect is manual installs, which per docs/start-here/manual
  use `--torch-backend=<x>` with no extra and therefore resolve the base
  range directly — on every platform, not just ROCm.

There is no environment marker for "resolving against the rocm7.1 index", so
the cap cannot be scoped in metadata. Constrain it where it can actually be
targeted instead: the `rocm` extra already pins torch==2.10.0+rocm7.1, and
the manual install docs now carry a ROCm-specific caution with the
`"torch<2.12"` workaround for users following the `--torch-backend=rocm7.1`
path.

pyproject.toml returns to `torch>=2.7.0,<3.0`, so uv.lock is untouched by
this PR again.

* docs: point the ROCm torch-2.12 caveat at an open tracking issue

#9328 was closed as completed once pins.json was corrected to the rocm7.1
index; the separate torch 2.12.x generation failure reported in that thread
had no open tracking issue, so the caveat had no removal condition. Filed
#9410 for it and link there instead.

Also narrow the cross-platform claim: we have no torch 2.12 smoke tests on
CUDA/CPU/Windows/ARM64/MPS, so say only that the workaround applies to the
reported ROCm case rather than asserting other backends are unaffected.

* ci(pins): validate pins.json's python pin against requires-python

The launcher's zod schema declares `python: z.string()` (required) and passes
pins.python to `uv venv --python` on both the bootstrap and legacy install
paths, before anything is installed. Bumping project.requires-python without
bumping pins.json therefore builds a venv the package metadata then rejects -
and the check passed, because it only looked at torchIndexUrl.

check_pins.py now also checks that pins.json's python satisfies
project.requires-python. It stays stdlib-only (CI runs it with a bare python3),
so the specifier handling is hand-rolled and deliberately narrow: ==, !=, >=,
<=, > and < against dotted numeric versions, zero-padded so 3.12 == 3.12.0.
Anything it cannot evaluate is reported rather than guessed at. Differentially
tested against packaging over 1014 version/operator/bound combinations with no
divergences.

Hardening found while attacking the above:

- check_python never raises. requires-python is optional in PEP 621 and can be
  mistyped as a bare TOML float; either used to throw out of check_pins(),
  which runs before the torchIndexUrl loop and so suppressed the ROCm drift
  check this script exists for.
- A present-but-null platform section ("linux": null) passed silently, because
  .get() cannot tell it from an absent one.
- Version components are bounded, so a pin like 3.12.99999999 - which satisfies
  every specifier but which uv cannot resolve to an interpreter - is rejected.
- A trailing comma in requires-python is no longer read as an empty clause.

Also drop the unverified 'isn't needed for the other torch backends' clause
from the ROCm caveat, per review: nothing on CUDA/CPU/Windows/ARM64/MPS was
smoke-tested with torch 2.12.

* ci(pins): reject unreal python pins by shape, not by digit count

The python pin was validated with a bounded regex, which made a bogus
version merely unlikely rather than impossible: "3.12.9999" passed, and
`uv python find 3.12.9999` finds no interpreter, so CI stayed green
while the launcher's install broke at the last step.

Replace the heuristic with two checks that make the bad values
unrepresentable:

- The pin must be exactly major.minor. `uv venv --python 3.12` already
  resolves to the newest 3.12.x, `--python 3.12.7` demands one exact
  build that can leave uv's index, and the launcher's reinstall check
  compares only major()/minor() of this field anyway. That removes the
  whole 3.12.<anything> family by shape.
- Its major.minor must appear in project.classifiers. requires-python
  says which versions the metadata allows; the classifiers say which
  ones we ship for. Without it, an unreal version inside an open-ended
  requires-python (">=3.11" and a "3.99" pin) satisfies every clause and
  no digit bound catches it.

Also fix the module docstring: only the path handed to python is
location-independent, not the working directory it is typed in.

Hardening found by attacking the above:

- Bound the classifier pattern's digits like its two siblings. int()
  refuses a string of more than 4300 digits, so an unbounded pattern let
  a classifier raise straight out of check_python - which runs first and
  would have taken the torchIndexUrl checks with it.
- Guard the pins.json top level. A non-object raised AttributeError from
  pins.get(), with the same suppressing effect (pre-existing).
- Reject leading zeros, so the pin has exactly one spelling.
- Report dynamic classifiers as dynamic rather than as absent.
- De-duplicate classifier versions so a repeat is not listed twice.

Tests assert the reason a patch pin is rejected, not just the exit code:
the classifier check rejects those too, so without that a loosened
version pattern would leave the suite green while advising the user to
add a classifier for "3.12.7".

---------

Co-authored-by: Claude Fable 5 <[email protected]>
Co-authored-by: Jonathan <[email protected]>
2026-08-05 12:36:40 -04:00
Stella WangandLincoln Stein d9443e9813 ci: check aarch64 dependency resolution in uv-lock-checks (#9357)
* ci: assert uv.lock keeps torch installable on linux/aarch64

Nothing in CI covered aarch64, so a dependency bump could silently re-break the
PyPI fallback that linux/aarch64 relies on for torch and torchvision. That
already happened once, when a ROCm bump narrowed tool.uv.environments.

Check the lockfile rather than re-resolving: tool.uv.environments must still
admit aarch64, every torch extra must resolve torch and torchvision there, and
the pinned versions must ship linux/aarch64 wheels for each supported Python.
Narrowing tool.uv.environments or dropping the extras' aarch64 fallback pins
both leave uv lock --locked green, so neither was caught before.

* fix(ci): survive percent-encoded wheel URLs in aarch64 lock check

The PyTorch WHL indexes percent-encode the `+` of local versions in
wheel URLs, so a marker regression that pins aarch64 torch to a WHL
index crashed `parse_wheel_filename` with a raw traceback instead of a
verdict -- in exactly the still-locks-cleanly state the check exists
for. Unquote the filename, and turn any remaining unparseable name into
a one-line failure instead of a traceback.

Also from review: look up version-less dependency entries (uv omits
version/source when a package resolves to a single version across the
lockfile), check every dependency entry matching the aarch64
environment rather than the first, and cap `--with packaging` below 26
so a parsing-strictness bump can't change the verdict on its own.

---------

Co-authored-by: Lincoln Stein <[email protected]>
2026-08-05 12:09:22 -04:00
joshistoast 0ab567244f chore: merge upstream/main into v7 integration
Brings in 18 upstream commits: video generation (#9163), Krea-2 (#9304),
Ideogram 4 (#9303), Wan 2.2, pressure-dependent brush opacity (#9232), GGUF
T5 / Qwen3 tokenizer support, and a queue-status performance refactor (#9355).

Nine files conflicted. Seven were the fork's wildcard_records service landing
on the same lines as upstream's videos/gallery services — both sides kept.

session_queue_sqlite.get_queue_status took upstream's lightweight 4-column
current-item query (which avoids deserializing the session graph on every
status poll) and carries the fork's origin_prefix filter into it, so an
origin-scoped caller still cannot see another scope's current item. Added a
negative-path test for that: the existing origin-scope test only covered a
matching item, so it would have passed with the filter dropped.

test_session_queue_status_event_isolation lost the get_current monkeypatch
race test, per upstream — the single-snapshot read makes the race structurally
impossible, and the monkeypatch would have become a silent no-op.

diffusers moves 0.37 -> 0.39 and imageio[ffmpeg] / psutil are new, so this
needs `uv sync`.
2026-07-29 18:53:03 -06:00
Lincoln SteinandClaude Fable 5 7e95c5f593 ci: raise python-tests job timeout to 30 minutes (#9391)
The pytest matrix jobs already run 9-11 minutes per platform on main, and
heavier PRs (e.g. #9163) push windows-cpu past the 15-minute cap, cancelling
the run mid-pytest. Raise the cap to 30 minutes to give feature branches
headroom.

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-27 16:42:46 -04:00
joshistoast 6dbb1c90af fix(ui): address architecture review blockers 2026-07-19 20:28:15 -06:00
joshistoast 566b17cc98 refactor(webv2): restructure state architecture into app/platform/workbench/features
Establish the four-group module architecture: app owns boot, providers, and
composition roots; platform owns domain-neutral transport, state, query, i18n,
and UI foundations; workbench owns the project aggregate, shell, and widget
runtime; eight vertical features (queue, gallery, generation, workflow, upscale,
identity, models, nodes) sit behind registered public entry modules. Dependency
direction app -> workbench/features -> platform is enforced by an executable
dependency policy with zero migration exceptions. Includes deriving the
workbench aggregate command interface from the reducer intent union.

Claude-Session: https://claude.ai/code/session_019CLrxZcNUq3vT6CLpJB4ju
2026-07-19 01:26:06 -06:00
joshistoast 545db32cf6 test(canvas): add real-browser acceptance coverage
Run Canvas2D and React lifecycle checks in headless Chromium, wire the suite into CI, and remove the unused fflate dependency.
2026-07-16 04:41:30 -06:00
joshistoast b8d6980e7f ci(webv2): add lint build and test gates 2026-06-14 00:59:07 -06:00
Lincoln SteinandClaude Fable 5 ec0b1e7e7e ci: run pytest via uv run to fix venv PATH breakage (#9286)
PR #9214 switched dependency installation from 'uv pip install' (which
honored UV_SYSTEM_PYTHON=1 and installed into the system Python) to
'uv sync', which always installs into a project-local .venv. The bare
'pytest' invocation in the next step never saw that venv, failing with
'pytest: command not found' (exit 127) on every matrix job.

- Run pytest via 'uv run --no-sync pytest'. The --no-sync flag is
  required: a plain 'uv run' would re-sync without '--extra test' and
  uninstall pytest before running it.
- Drop UV_SYSTEM_PYTHON=1, which is dead config now that nothing uses
  the 'uv pip' interface.
- Drop the actions/setup-python step; setup-uv is already given the
  matrix python-version and uv sync provisions its own interpreter.

Co-authored-by: Claude Fable 5 <[email protected]>
2026-06-11 16:12:09 -04:00
837a87779a ci: use uv.lock when running tests (#9214)
Co-authored-by: Jonathan <[email protected]>
Co-authored-by: Alexander Eichhorn <[email protected]>
Co-authored-by: Lincoln Stein <[email protected]>
2026-06-11 19:56:23 +00:00
Lincoln SteinandClaude Opus 4.8 0df229f2fc fix(ci): repair wrapped ENABLE_ANALYTICS expression in deploy-docs workflow (#9271)
* fix(ci): repair wrapped ENABLE_ANALYTICS expression in deploy-docs workflow

The `${{ ... }}` expression for ENABLE_ANALYTICS was wrapped across two
lines (splitting mid-expression after `||`), producing a YAML syntax
error. Join it back onto a single line.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* fix(docs): remove broken anchor link to aside in fp8-storage page

The link to #for-full-precision-models-only targeted a Starlight
:::caution callout, which doesn't generate a heading anchor. This
failed starlight-links-validator and broke the docs build. Drop the
anchor link, keep the cross-reference prose.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 21:25:00 -04:00
Kevin Turner 81c6104210 chore(ci): update cached-lfs-checkout from deprecated node 20 version (#9261)
Follow-up to #9149. Missed this one because it wasn't directly named in the deprecation notice; it's a transitive use of other old actions.
2026-06-01 15:16:44 -04:00
Lincoln Stein 32b672f6df fix(ci/cd): fix typegen test failure introduced by PR 9209 (#9260) 2026-05-31 19:12:39 -04:00
307d79386b chore(github): update actions from deprecated node-20 versions (#9149)
* chore(github): update actions from deprecated node-20 versions

* fix(deploy-docs): use sync to address "no virtual environment found"

---------

Co-authored-by: Kevin Turner <[email protected]>
Co-authored-by: Alexander Eichhorn <[email protected]>
Co-authored-by: Jonathan <[email protected]>
2026-05-31 22:36:06 +00:00
Alexander EichhornandJosh Corbett 993c68102f docs: load Plausible on invoke.ai (custom), not ghpages (#9161)
* docs: load Plausible on invoke.ai (custom), not ghpages

Plausible was being injected on the ghpages target, which redirects to
invoke.ai and therefore never serves analytics. Flip the conditional so
the script loads on the actual production custom-domain build.

* docs: gate Plausible on ENABLE_ANALYTICS env var

Only inject the tracking script when ENABLE_ANALYTICS=true, which the
deploy workflow sets exclusively on main-branch pushes. Keeps local
builds, PR builds, and manual workflow_dispatch runs analytics-free.

* Update .github/workflows/deploy-docs.yml

Co-authored-by: Josh Corbett <[email protected]>

---------

Co-authored-by: Josh Corbett <[email protected]>
2026-05-18 17:18:48 -04:00