Merge branch 'main' into feat/training-studio-app

This commit is contained in:
Luis Rojas
2026-09-11 16:27:40 -04:00
343 changed files with 22094 additions and 2201 deletions
+2 -2
View File
@@ -6,14 +6,14 @@ All controllers/nodes rendered inside the `<AccordionLayout label="Advanced">` s
|---|-----------|-------|-----------------|-------------|-------------|
| 1 | `cfgScale` | CFG Scale | `SliderInput` | Controls how closely generation follows the text prompt | — |
| 2 | `sampler` | Sampler | `SelectInput` | Sampling method — each produces different results | — |
| 3 | `scheduler` | Scheduler | `SelectInput` | Controls the noise schedule during generation | SdCpp ecosystems |
| 3 | `scheduler` | Scheduler | `SelectInput` | Controls the noise schedule during generation | Anima, Flux2Klein, ZImage |
| 4 | `steps` | Steps | `SliderInput` | Number of iterations spent generating | — |
| 5 | `movementAmplitude` | Movement Amplitude | `SegmentedControlWrapper` | Camera movement and subject action scale | Vidu |
| 6 | `seed` | Seed | `SeedInput` | Random seed for reproducibility | — |
| 7 | `clipSkip` | CLIP Skip | `SliderInput` | Skip CLIP layers | SD only |
| 8 | `denoise` | Denoise Strength | `SliderInput` | Denoising strength for img2img | img2img only (renders `null` when no meta) |
| 9 | `vae` | VAE | `ResourceSelectInput` | Additional color and detail improvements | SD only |
| 10 | `enhancedCompatibility` | Enhanced Compatibility | `Checkbox` | Toggle enhanced compatibility mode | — |
| 10 | `enhancedCompatibility` | Enhanced Compatibility | `Checkbox` | Off (default) runs sdcpp; on runs comfyui | SD1, SDXL — txt2img only |
| 11 | `usePro` | Pro Mode | `Checkbox` | Higher quality generation (more credits) | Sora |
| 12 | `fluxUltraRaw` | Raw Mode | `Checkbox` | More natural, less processed look | Flux Ultra |
| 13 | `transparent` | Transparent Background | `Checkbox` | Generate image with transparent background | OpenAI |
+1 -1
View File
@@ -180,7 +180,7 @@ The type "lies" — it claims every flag is present and boolean, when at runtime
- The wire payload is still sparse (Phase 2 stays — half the win was the bytes)
- **The flag-removal safety net still works**: `FeatureFlagKey` is the keyspace, so removing a flag from the registry shrinks the union and produces a type error at every consumer (including destructure sites)
**What we lose:** the type doesn't enforce write safety (`features.X = false` compiles even though wire payload never produces `false`). Acceptable — no consumer writes to the cache except [SettingsCard.tsx:334](../src/components/Account/SettingsCard.tsx#L334), and that one assignment is internal optimistic-cache state, not the wire payload.
**What we lose:** the type doesn't enforce write safety (`features.X = false` compiles even though wire payload never produces `false`). Acceptable — no consumer writes to the cache except [SettingsCard.tsx:335](../src/components/Account/SettingsCard.tsx#L335), and that one assignment is internal optimistic-cache state, not the wire payload.
### Phase 4 — Benefits realized
+47 -5
View File
@@ -41,7 +41,9 @@ install. Each app is served from its own platform-owned subdomain
## Tokens
- RS256, signed by `BLOCK_TOKEN_PRIVATE_KEY`, verified via JWKS.
- 15-minute lifetime by default; 5-minute lifetime for `block:settings:*` scopes.
- 15-minute lifetime by default; 5-minute lifetime for `block:settings:*` scopes
— a RETIRED scope family (see the Scopes table), so a manifest can no longer
declare it and that shorter lifetime is unreachable today.
- Claims: `iss`, `aud`, `sub` (`user:<id>` or `anon`), `iat`, `nbf`, `exp`,
`jti`, `blockId`, `appId`, `blockInstanceId`, `ctx`, `scopes`,
`buzzBudget?`.
@@ -57,12 +59,12 @@ check at request time (`enforceContextBinding`).
| Scope | Bind | Notes |
| -------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `models:read:self` | `query.id == ctx.modelId` | |
| `media:read:owned` | non-anon `sub` | |
| `buzz:read:self` | non-anon `sub` | |
| ~~`media:read:owned`~~ | — | **REMOVED** from the scope registry (purely decorative — no endpoint ever checked it). A manifest declaring it is REJECTED. The OAuth `MediaRead` bit is unaffected |
| `buzz:read:self` | non-anon `sub` | **required for EVERY host-mediated buzz read**, `blocks.getMyBuzzBalance` included — it is no longer scope-free. A token without it gets `block lacks buzz:read:self scope` (FORBIDDEN) |
| `social:tip:self` | non-anon `sub` | |
| `user:read:self` | non-anon `sub` | viewer identity — read via the `useViewer()` hook (`GET_VIEWER` bridge → `blocks.getMyViewer`). Also gates the **deprecated** `/api/v1/blocks/me` REST route (retiring) |
| `ai:write:budgeted` | positive `buzzBudget` | |
| `block:settings:read` / `:write` | `query.blockInstanceId == claims.blockInstanceId` | + caller-is-installer at issuance; `SKIP_OAUTH_CHECK` |
| ~~`block:settings:read` / `:write`~~ | — | **REMOVED** from the scope registry (no runtime capability ever verified them; the settings paths authorize on valid-token + app-developer + installer-resolution). A manifest declaring either is REJECTED |
| `apps:storage:read` / `:write` | scope present on `claims.scopes` per op | per-app KV store (App Storage); no OAuth bit (`SKIP_OAUTH_CHECK`) — gated by the approved-scope snapshot + `resolveStorageContext` |
Unknown scopes are rejected at runtime (deny-by-default in middleware).
@@ -111,7 +113,9 @@ fine-grained tool for ops.
- **Ownership escalation**: `block:settings:*` tokens require caller
is the install's `installedByUserId` at issuance. The check is
authoritative at issue time; deleted-publisher installs (FK SET NULL)
fail closed.
fail closed. ⚠️ The scope family is RETIRED (see the Scopes table), so this
check still exists in `block-tokens/index.ts` but nothing can reach it —
the scope cannot be declared, approved or minted.
## BLOCK_INIT contract
@@ -310,6 +314,11 @@ Civitai Buzz is split into spendable pools — **blue** (purchased), **green**
`blocks.getMyBuzzBalance` mutation, which returns `{ blue, green, yellow }` for
the token's subject (other account types — red / cash / creator-program — are
omitted). This backs the SDK `useBuzzBalance()` hook + the account picker.
**Declare `buzz:read:self`** — this read requires it, like every other
host-mediated buzz read. It used to be scope-free (gated on an authoring
capability instead); that capability gate was removed from the runtime, and the
user's own scope grant is the authority now. A token without the scope gets
`block lacks buzz:read:self scope`.
- **Choose the funding pool**: a workflow submit body may carry `accountType`
(`blue | green | yellow`). It is honored **preferred-first** while the maturity
policy clamp still applies (a SFW-domain block can't widen to a mature currency);
@@ -319,6 +328,39 @@ Civitai Buzz is split into spendable pools — **blue** (purchased), **green**
`spentAccountType` — the `accountType` of the largest _realized_ debit — so a
block can attribute spend after the fact (internal-only accounts are omitted).
### The user's per-app spend limit (consent budget)
A viewer who grants `ai:write:budgeted` may also set a **daily Buzz limit for that
one app**, stored on their grant row (`app_user_scope_grants.buzz_budget_per_day`).
It is the only one of the three spend ceilings the user chooses:
| Ceiling | Scope of the key | Who set it |
| --- | --- | --- |
| Platform per-user daily cap | one user, ALL their apps | the platform |
| Per-app aggregate cap | one app, ALL its users | the platform |
| **Consent budget** | one (user, app) pair, per UTC day | **the user** |
- **Both apply; the tighter one binds.** The consent budget is bounded above by the
platform per-user daily cap, so it can only ever narrow. `null` (the default, and
the state of every grant made before the field existed) means "no limit of my own"
and behaves exactly as it did before.
- **Set at consent time** in the permission modal (shown only when the scope being
granted is `ai:write:budgeted` — a limit next to "read your username" bounds
nothing), and **changed, cleared or simply read afterwards** on
**Apps → Permissions** (`/apps/activity`). Both write through
`blocks.grantScopes`, whose `buzzBudgetPerDay` input has three distinct states: a
number sets/replaces, `null` clears, and an **omitted** key leaves the stored value
alone (so re-consenting to an unrelated scope can never wipe a limit).
- **What an app sees when it binds.** The submit is refused before any spend with a
`failed` snapshot whose error names the user's own number — e.g. `app Buzz limit
reached: 400 already spent today by this app on your behalf, this generation may
cost up to 150, your limit for this app is 500`. Unlike the platform per-app cap
(a platform secret), this ceiling is the user's own setting, so telling the app is
what makes the rejection actionable: surface it and let the user raise the limit.
- **Post-paid jobs reserve the CEILING and settle to actual**, on this counter exactly
as on the platform one — so a job that reserves 5,000 and bills 200 gives back 4,800
when it reaches a terminal state.
## Publish / review / deploy lifecycle (no trust on push)
The build + deploy of new iframe code is gated entirely on **moderator
+15 -4
View File
@@ -146,8 +146,17 @@ every measured number are in [paid-model-loading-coverage.md](paid-model-loading
model with a loadable file. The LORA/TI/VAE/LoCon/DoRA/Upscaler branch is unchanged.
- [x] drop the `CoveredCheckpoint` conjunct, and allow `Diffusers` while keeping Core ML and ONNX
excluded — [the numbers](paid-model-loading-coverage.md#what-changes-in-numbers)
- [x] **checkpoints require a SafeTensor weight file**
`20260909180000_generation_coverage_next_safetensor_checkpoints`, 2026-09-09. Narrows the
2026-09-08 view: Diffusers stays loadable for every type *except* checkpoints, and
`CoveredCheckpoint` returns as a disjunct excusing 6 auction-resident versions.
**Written, not yet applied to any environment.**
- [ ] 🔴 keep `EcosystemCheckpoints` — 62 of 63 checkpoint defaults depend on it
- [x] diffed against production 2026-09-08 — nothing loses coverage; [the numbers](paid-model-loading-coverage.md#what-changes-in-numbers)
- [x] diffed against production 2026-09-08 — nothing lost coverage *at that point*; [the numbers](paid-model-loading-coverage.md#what-changes-in-numbers)
- [ ] 🔴 **2,242 covered checkpoints lose coverage when the SafeTensor migration is applied**
(33,811 -> 31,569; 834 with generation history, 6.5M lifetime generations). A narrowing, so
there is no safe window — apply it when the readers of `covered` are ready.
*Closes when:* applied to production and the covered-checkpoint count reads 31,569.
- [ ] **Set `usageControl = 'ExternalGeneration'` on the 36 mislabelled API versions.** All
published, none POI, coverage preserved 36/36. Mod-only to set via the app, so it is a direct
DB write.
@@ -239,9 +248,11 @@ the platform second.
- [ ] **C11 — retire auctions.** ([868ktt5b2](https://app.clickup.com/t/868ktt5b2)) Do not scope
until 868gtq1kt (splitting featuring out of auctions) has an answer — auctions do two jobs
and paid loading replaces one. ~89 files under `src/`.
- [x] the `CoveredCheckpoint` conflict is resolved by removing it from coverage (Phase 1.6), so
the auction job can no longer un-cover a paid checkpoint. What remains is deciding whether
that job should keep writing rows nothing reads.
- [x] the `CoveredCheckpoint` conflict is resolved by removing it as a coverage *conjunct*
(Phase 1.6), so the auction job can no longer un-cover a paid checkpoint. It survives as a
disjunct covering 6 auction-resident versions that lack a SafeTensor file — those would lose
coverage on the next auction prune, but none is loadable, so none can have been paid for.
What remains is deciding whether that job should keep writing rows nothing else reads.
---
+20 -3
View File
@@ -55,7 +55,9 @@ This is the thing an earlier reading of these docs got wrong, and it inverted a
| `CoveredCheckpoint` | 514 rows | Auction-won community checkpoints — a **residency proxy**. Written and pruned weekly by `handle-auctions.ts`. **This is what paid loading replaces.** (638 versions are covered *as checkpoints* — the rest come from `EcosystemCheckpoints`.) |
| `EcosystemCheckpoints` | 125 | The generator's **default model per ecosystem**. **62 of the 63 checkpoint defaults are covered through it — and zero through `CoveredCheckpoint`.** Not a loophole; the registry that keeps the generator working. |
Dropping `CoveredCheckpoint` is the feature. Dropping `EcosystemCheckpoints` would remove the
Dropping `CoveredCheckpoint` **as a conjunct** is the feature — it no longer gates anything. It
survives as a *disjunct* excusing 6 auction-resident checkpoints from the SafeTensor requirement, and
is deleted when the auction stops writing rows. Dropping `EcosystemCheckpoints` would remove the
default model from half the ecosystems the generator supports — see
[the defaults audit](#the-defaults-audit).
@@ -89,8 +91,23 @@ contributes. Earlier drafts of these docs used 514 for both, which is what made
fail to add up.
155 published, licensed, standard checkpoints on supported base models were blocked **only** by file
format: 132 Diffusers, 21 Core ML, 2 ONNX. Diffusers is loadable (Justin, 2026-09-08); Core ML and
ONNX are inference-runtime formats rather than servable weights and stay excluded.
format under `GenerationCoverage`: 132 Diffusers, 21 Core ML, 2 ONNX.
⚠️ **Diffusers was ruled loadable (Justin, 2026-09-08) and then narrowed back out for CHECKPOINTS on
2026-09-09.** The loader serves SafeTensor only, so the checkpoint branch of `GenerationCoverageNext`
now requires a SafeTensor weight file (migration
`20260909180000_generation_coverage_next_safetensor_checkpoints`) and `checkLoadable` in
`resource-load.service.ts` refuses everything else with `unsupported-format`. Diffusers remains
accepted for **every other model type** — the shared `EXISTS` is unchanged, so the Core ML / ONNX
deny-list still governs LoRA/TI/VAE/LoCon/DoRA/Upscaler.
🔴 **The SafeTensor narrowing took 2,242 checkpoints back out.** Measured 2026-09-09 against the
production replica: covered checkpoints **33,811 -> 31,569**, total view rows **933,851 -> 931,609**
(every row of the delta a checkpoint; textual inversions unchanged at 6,299, all 514 auction rows
retained). 834 of the 2,242 have any generation history — 6.5M lifetime generations, 0.43% of all
checkpoint generation. Scoping matters: putting the rule on the shared `EXISTS` instead would have
removed 3,287 textual inversions carrying **1.39 billion** generations, more than every SafeTensor TI
combined.
### The loader population, split by bucket
@@ -169,6 +169,25 @@ is dead code. Removing it widens covered checkpoints by roughly two orders of ma
must stay**, because 62 of 63 checkpoint defaults are covered through it and none through
`CoveredCheckpoint`. See [coverage](paid-model-loading-coverage.md#the-two-tables-do-opposite-jobs).
⚠️ **Amended 2026-09-09.** `CoveredCheckpoint` is no longer a conjunct — Justin's condition holds —
but it returns as a **disjunct** in `20260909180000_generation_coverage_next_safetensor_checkpoints`,
excusing 6 auction-resident checkpoints from the new SafeTensor requirement. Auction membership no
longer decides coverage; it stands in for residency until C11 retires the job, and is deleted with it.
### 2.7 ⚠️ Diffusers is loadable — except for checkpoints
Justin ruled Diffusers loadable on 2026-09-08, and the first `GenerationCoverageNext` migration
removed it from the excluded-format list for every type. The loader serves **SafeTensor only**, so
the checkpoint branch was narrowed back on 2026-09-09 — 174 Diffusers checkpoints sit among the
2,242 versions that lose coverage. Diffusers is untouched for LoRA/TI/VAE/LoCon/DoRA/Upscaler.
**Open:** whether Justin accepts the narrowing as an implementation constraint, or wants the loader
to grow Diffusers support. *Decides:* Justin. *Closes when:* he answers here, or the migration is
applied to production with the narrowing intact.
@dev: The loader can only serve SafeTensor today. OK to drop Diffusers/GGUF/PickleTensor checkpoints
from coverage (2,242 versions, 0.43% of checkpoint generation), or should the loader learn them?
### 2.4 ✅ The C4 webhook — not now
**Closed 2026-09-08: no.** Both reasons to build it went away on the same day.
+10 -5
View File
@@ -240,15 +240,18 @@ The premise of the feature is that the generator stops being restricted to a cur
2026-09-08 this is scoped and decided; the full model, the audit and every measured number live in
[paid-model-loading-coverage.md](paid-model-loading-coverage.md). In short:
- **`CoveredCheckpoint` goes away.** It is the auction's residency proxy, it has four uses and all
four are generation, and dropping it widens covered checkpoints by roughly two orders of magnitude
([the numbers](paid-model-loading-coverage.md#what-changes-in-numbers)).
- **`CoveredCheckpoint` stops gating.** It is the auction's residency proxy, it has four uses and all
four are generation, and removing it *as a conjunct* widens covered checkpoints by roughly two
orders of magnitude ([the numbers](paid-model-loading-coverage.md#what-changes-in-numbers)). It
remains as a *disjunct* excusing 6 auction-resident checkpoints from the SafeTensor rule, and is
deleted with the auction.
- **`EcosystemCheckpoints` stays.** It is the generator's default model per ecosystem — 62 of the 63
checkpoint defaults are covered through it and none through `CoveredCheckpoint`. Removing it would
strip the default model from half the supported ecosystems.
- **`GenerationBaseModel` stays as the gate.** It marks the base models where the orchestrator has
extended checkpoint/diffuser support, i.e. where community models can run.
- **Diffusers becomes loadable**; Core ML and ONNX stay excluded.
- **Checkpoints must carry a SafeTensor weight file** (2026-09-09); GGUF, PickleTensor, Diffusers,
Core ML, ONNX and unset are all unloadable. Diffusers stays accepted for every other type.
- **File-less models never touch the loader**, and "file-less" means *no loadable file*, not *no file
row* — 36 API models carry a `Training Data` archive and would otherwise read as loadable.
@@ -343,7 +346,9 @@ deciding anything.
- **`CoveredCheckpoint` stops gating generation**; `EcosystemCheckpoints` and `GenerationBaseModel`
stay. Coverage means *allowed to generate*; residency is the orchestrator's axis.
- **Only base models in `GenerationBaseModel` are loadable.** Everything else is out of scope for v1.
- A checkpoint needs a **correct model file** to be loadable; file-less API models never are.
- A checkpoint needs a **SafeTensor** weight file to be loadable (2026-09-09); file-less API models
never are, and a GGUF/PickleTensor/Diffusers checkpoint gets a different refusal —
`UNLOADABLE_MESSAGES` in `resource-load.service.ts` is the single source of both.
- A load that never finishes is **refunded**.
- The purchase path refuses anything **not in `GenerationCoverageNext`** (composed with ecosystem
type support by `isGenerationEligible`), which is how the `RentCivit` rule is enforced without
@@ -61,8 +61,8 @@ Mapping each input type to the ecosystem(s) whose handler produces it (router: `
| Input type | Ecosystems (ECO keys) | Handler |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `TextToImageInput` | `SD1`, `SD2`, `SDXL`, `Pony`, `Illustrious`, `NoobAI`, `Flux1`, `FluxKrea`, `Chroma`, `HiDream`, `PonyV7` | `stable-diffusion.handler.ts`, `flux.handler.ts`, `chroma.handler.ts`, `hi-dream.handler.ts`, `pony-v7.handler.ts` |
| `ComfyImageGenInput` | `Anima`, `Ernie`, `Lens`, `HiDream-O1` + SD-family img2img/face-fix/hires-fix (already covered by the SD ecosystems above) | `anima/ernie/lens/hi-dream-o1.handler.ts`, `comfy-input.ts` |
| `SdCppImageGenInput` | `ZImageTurbo`, `ZImageBase`, `Qwen` | `z-image.handler.ts`, `qwen.handler.ts` |
| `ComfyImageGenInput` | `Anima`, `Ernie`, `Lens`, `HiDream-O1`, `ZImageTurbo`, `ZImageBase`, `Qwen` + SD-family img2img/face-fix/hires-fix (already covered by the SD ecosystems above) | `anima/ernie/lens/hi-dream-o1/z-image/qwen.handler.ts`, `comfy-input.ts` |
| `SdCppImageGenInput` | _(none — ZImage and Qwen moved to comfy; see the `ComfyImageGenInput` row)_ | — |
| `Flux2KleinImageGenInput` | `Flux2Klein_9B`, `Flux2Klein_9B_base`, `Flux2Klein_4B`, `Flux2Klein_4B_base` | `flux2-klein.handler.ts` |
| `ComfyVideoGenInput` | _(no active ecosystem — see note)_ | — |
| `ComfyLtx2VideoGenInput` | `LTXV2` | `ltx.handler.ts` |
@@ -74,7 +74,7 @@ Mapping each input type to the ecosystem(s) whose handler produces it (router: `
### Traps — lookalike ecosystems that are EXTERNAL (must NOT be gated)
- **`Flux2`** (plain) → external (`flux2` engine). Only **`Flux2Klein*`** is self-hosted.
- **`Qwen2`** → external (`fal`). Only **`Qwen`** (sdcpp) is self-hosted.
- **`Qwen2`** → external (`fal`). Only **`Qwen`** (comfy) is self-hosted.
- **All `Wan*` ecosystems** → external (FAL) today. Out of scope.
> **Decision 1 — RESOLVED: clean ecosystem-key granularity.** Every self-hosted ecosystem is all-or-nothing at the ecosystem-key level. No flag-conditional cases, no version-level lists. The static `selfHosted: true` flag fully describes the set.
+4 -4
View File
@@ -285,8 +285,8 @@ per-graph scopes. The lib grew `defineGraph({ scope })` (graph-level default sco
field `scope` — including `[]`, the bare-key opt-out — wins; mounted children
keep their own fn). The layout, mirroring v1's groups: every family graph and
branch member carries `defineGraph({ scope: familyScope })` (ecosystem group id, else key —
wan versions and klein variants share buckets); `SEED` and `controlNetsDef`
opt out to bare keys (v1 stores them globally); images/video wrap their def fns
wan versions and klein variants share buckets); `SEED`, `controlNetsDef` and
`controlVideoDef` opt out to bare keys (v1 stores them globally); images/video wrap their def fns
in `workflowScoped` (per-workflow buckets); the hubs scope `ecosystem` per
output type, `quantity` per workflow only on draft, `enhancedCompatibility`
per family bucket; and the turbo-variant families (zimage/boogu/krea2/anima/ernie/lens/mage-flow — all seven ported
@@ -464,7 +464,7 @@ home); full suite + typecheck + lint green; Briant reviews the final diff.
| video: sora2 | DONE | DONE | AR options per resolution (txt2vid only), usePro, durations 4/8 |
| video: hunyuan (HyV1) | DONE | DONE | cfg/steps presets, familyResources, 480p AR set |
| video: flux3-video | DONE | DONE | First/Last frame slots on img2vid; v1's draft→resolution forward dep is dead, resolution unconditional (probed) |
| video: minimax (MiniMaxH3, api/comfy) | DONE | DONE | tagged branch on version: comfy carries loras/seed/turbo-shaped steps, api is bare; ref2vid takes up to 9 refs (`variantOf`, NOT a prefix match — bit us) |
| video: minimax (MiniMaxH3, api/comfy) | DONE | DONE | tagged branch on version: comfy carries loras/seed/turbo-shaped steps, api is bare; ref2vid takes up to 9 refs (`variantOf`, NOT a prefix match — bit us). `controlVideo` (H3 Fun ControlNet Union) is comfy + txt2vid only — the control operation REPLACES imageToVideo, so there is no frame/reference slot to share it with; its five preprocessor keys are the `preprocessVideo` set, not the image ControlNet set |
| video: happy-horse (v1.0/v1.1) | DONE | DONE | AR family keyed `resolution|version` (v1.1 widens the set); vid2vid:edit carries video + refs + audioSetting |
| video: veo3 (fast/standard) | DONE | DONE | workflowVersions inert (same list both workflows); ref2vid pins duration to 8s at the boundary; version enum defaults '3.1' (3.0 endpoints retired) |
| video: vidu (Q1/Q3) | DONE | DONE | image-driven workflows emit NO aspectRatio (v1 hides the node; handler derives from source — probed); Q3 ref2vid rewrites to img2vid in `reconcile.ts`; Q3 resolution-scaled AR dims |
@@ -475,7 +475,7 @@ home); full suite + typecheck + lint green; Briant reviews the final diff.
| model3d: polygen (Meshy v6/v7) | DONE | DONE | `polygenVersion` flag-gated (meshyV7Generator) AND workflow-clamped (v7-on-text → v6) in both input and output transforms; v7-only knobs null out per version/image-count; v7 has no seed |
| model3d: tripo / hunyuan3d / pixal3d / trellis2 | DONE | DONE | image-to-3D only; pixal3d and trellis2 are field-identical (one factory, two instances for their own family scopes); hunyuan keeps its `hunyuan*` field prefixes, mapped back in the handler |
| model3d hub | DONE | DONE | ecosystem scoped 'model3d', default PolyGen; the four newer 3D ecosystems are flag-hidden fail-closed via the shared getEcosystemStates |
| standalone workflows (img2img:upscale / remove-background / preprocess, vid2vid:upscale / interpolate, img2meta, prompt:enhance) | DONE | DONE | seven arms on a state-only `workflowKind` dispatch at the root (the oracle wire has no such key); priority/outputFormat moved to the ROOT gated on image output, matching v1 — they apply to standalone image workflows too. The upscale batch reset (v1 transform) is a `correct`; preprocess kind specs import from the v1 module (they mirror @civitai/client, not the engine). The two empty panels (img2meta, prompt:enhance) are bare graphs. Step creation stays in the submit service keyed on workflow — data parity covers it, no lane handlers needed |
| standalone workflows (img2img:upscale / remove-background / preprocess, vid2vid:upscale / interpolate / preprocess, img2meta, prompt:enhance) | DONE | DONE | eight arms on a state-only `workflowKind` dispatch at the root (the oracle wire has no such key); priority/outputFormat moved to the ROOT gated on image output, matching v1 — they apply to standalone image workflows too. The upscale batch reset (v1 transform) is a `correct`; preprocess kind specs import from the v1 module (they mirror @civitai/client, not the engine). The two empty panels (img2meta, prompt:enhance) are bare graphs. Step creation stays in the submit service keyed on workflow — data parity covers it, no lane handlers needed |
---
@@ -4,6 +4,9 @@
This plan addresses the migration to support multiple sub-domains where each supports one primary Buzz currency (Yellow or Green) while allowing Blue Buzz everywhere. The implementation enforces currency restrictions at both transaction and UI levels.
> **Shipped — with a different hook signature than the blocks below.** `useAvailableBuzz(baseTypes: BuzzSpendType[] = [])` takes an array, not an `includeBlue` boolean, and blue is **not** included by default: `useQueryBuzz()` with no argument totals the domain's own type alone. The Phase 2 code blocks are the original proposal; read `src/components/Buzz/useAvailableBuzz.ts` and `src/components/Buzz/useBuzz.ts` for the shipped shape.
## Current Architecture Analysis
### Current Buzz Implementation
@@ -63,6 +63,9 @@ new code. Recorded because two are repeats of things this file already documents
- [x] **`Images to Ingest` is `informational`** — the page has no actions and the count is upload
throughput, so summing it into the Images badge reads as a review backlog whenever the scanner
stalls.
- The flag reached the dashboard total only; the sidebar's `rollupFor` kept summing it until the
stuck-scan change (`feat/image-scan-stuck-alert`), which also switched the badge to count stuck
scans (`stuckIngestion`) instead of every pending upload from the last 5 days.
- [x] **The Most reported rewrite evaluated its seventeen subplans below the sort**, i.e. for every
qualifying report rather than the twenty kept — Postgres cannot project through a `Sort`, and the
comment claimed the opposite. The LIMIT is taken in a CTE and the ids resolved outside it.
+1 -1
View File
@@ -32,7 +32,7 @@ Default resolution 1024x1024 (2K capable). Bilingual (CN/EN) text rendering.
```
Base-model flip (Other -> Boogu) script: `<local-path>/AppData\Local\Temp\boogu-flip.mjs` (dry-run default; `--execute` to write). Validated via dry-run; run after the v5.0.1868 deploy is live in prod.
3. **Engine string + edit operation contract — orchestrator's call.** ZImage uses `engine: 'sdcpp', ecosystem: 'zImage'`. Boogu's engine (comfy? sdcpp? a new one?) and whether edit is `operation: 'editImage'` vs image-presence-inferred is whatever the orchestrator implements. Confirm with orchestrator team.
3. **Engine string + edit operation contract — orchestrator's call.** ZImage uses `engine: 'comfy', ecosystem: 'zImage'`. Boogu's engine (comfy? sdcpp? a new one?) and whether edit is `operation: 'editImage'` vs image-presence-inferred is whatever the orchestrator implements. Confirm with orchestrator team.
## Gating mechanism (answer to "Flipt or ecosystem mgmt?")