Repository navigation
Vault: Nastavení → Trezor and the Správci of the Environment's own vault (DEV-6631 tasks 648, 638b) - #402
Conversation
… and a request's page shows alone The Trezor page (DEV-6631 task 648, #402) leaves the slot `<section class="group" id="vault-requests" hidden>` above its vault. The requests' panel now fills that slot with its head and rows instead of a group of its own, and this change's scaffold of the section is the same element, so the panel works with either markup. On a request's page the panel marks the Trezor section (`data-request`) and only `#vault-request` shows of it, whatever else the Trezor page holds. The settings comment and the section's page-action rule match the Trezor page's lines, so both changes merge there without a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rezor page's change The Trezor page's change (#402) extracts the same function under this name; with one name both changes merge there without a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ac51c73 to
bdb33cc
Compare
… and a request's page shows alone The Trezor page (DEV-6631 task 648, #402) leaves the slot `<section class="group" id="vault-requests" hidden>` above its vault. The requests' panel now fills that slot with its head and rows instead of a group of its own, and this change's scaffold of the section is the same element, so the panel works with either markup. On a request's page the panel marks the Trezor section (`data-request`) and only `#vault-request` shows of it, whatever else the Trezor page holds. The settings comment and the section's page-action rule match the Trezor page's lines, so both changes merge there without a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rezor page's change The Trezor page's change (#402) extracts the same function under this name; with one name both changes merge there without a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty — CHANGES_REQUESTED on bdb33cc (stacked on #391 at 3425e71).
P1 — The claimed immediate withdrawal of a pending invitation is not failure-safe. In src/vault/members.ts:293-321 and :329-332, settlePerson first creates an Admin invitation for an SSO account without a master password, then tries to delete it. If the DELETE fails (e.g. a 503 or process interruption), underLock returns unreachable but leaves the status-0 member/invitation in Vaultwarden. With SSO_ONLY off, that address remains registrable by anyone who knows it; subsequent confirmation can grant the organization key and all passwords to the wrong account. A disposable HTTP fixture probe on this exact checkout made only the withdrawal DELETE return 503 and observed vault-member-unknown/unreachable, member status 0, and registerable(address) === true. The existing happy-path test checks only successful withdrawal. This is a security gate, not a UI retry condition: do not create such invitations on a network where unauthenticated registration through pending invitations is possible. Require the network-side SSO_ONLY/registration gate first, or establish a safe pre-invite existence/master-password check and a recovery strategy for interrupted withdrawals; add a failure/interruption regression test before approval.
Local evidence: 24 focused tests pass, static checks/typecheck/public guard/proof build and smoke pass, CI run 38487371020 green. The added probe was disposable and is not part of the PR. The new diff names no client Organization or person (the sole Organization repository reference is the product-team prototypes-lazurio). I did not merge.
|
P1, invite-then-withdraw is not failure-safe: agreed, fixed on The registration paths (fork source at
So "SSO declared +
The gate ( Behind the gate an invitation to an account without a master password stays Invited ( Evidence on
What this costs: until a network runs |
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty — APPROVED on a73cf45, stacked on #391 at 3425e71. The earlier P1 is resolved: the invite-then-withdraw path is gone; invitation and confirmation are gated on the vault token endpoint rejecting a password grant for this specific address with "SSO sign-in is required". I checked the pinned Vaultwarden fork source: this predicate is is_sso_required(address) before other token fields; both registration entry points reject that same predicate, whereas a passwordless-account invitation stores an Invitation row regardless of INVITATIONS_ALLOWED. The pending invitation stays Invited and later confirmation follows acceptance. The gate fails closed without SSO_ONLY and removal on reassignment is unaffected. Local isolated exact-head evidence: 19 focused tests passed; lint, typecheck, public guard, proof build and smoke passed; git diff --check clean. Exact-head CI run 38530218420 succeeded, no unresolved threads or competing review requests. Operational dependency: keep SSO_ONLY enabled while pending invitations exist, as F52 point 5 records. No merge performed.
3425e71 to
7eab155
Compare
a73cf45 to
fa60777
Compare
The base branch was changed.
…n answer The admission already revalidates the exact session cookie against the gateway's configured /oauth2/auth. That same answer now also yields the admitted session's subject, read from the gateway's X-Auth-Request-User (Machines renders oauth2-proxy with set_xauthrequest and the user claim sub) and accepted only as a lowercase UUID; anything else names nobody. It is cached with the admission, keyed by the session. A header of the request itself never names anyone. This is the narrow amendment of decision F11 for the membership of the Environment's own vault (root decision 0198 point 2, DEV-6631 task 638b): vault access is access to the Environment, which is exactly the admission fact. It is never a repository right, an operator or a role. Tests: the existing admission contract now states `subject: null`; a new test proves the gateway's subject is taken, forged request headers (X-Auth-Request-User, X-Forwarded-User/-Email, ...) are ignored for named, anonymous and denied sessions, only an exact lowercase UUID names someone, and the subject is kept with the cached admission. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…own vault Root decision 0198 point 2 (DEV-6631 task 638b, contract C4): whoever has access to the Environment is an Admin of its vault. src/vault/members.ts, under the account's lock, as the vault's only Owner: - the person is `<subject>@vaultwarden-identity.lazurio.ai`, the address Lazurio Auth's vault client issues; bw lists the members, the vault's API invites them as Admin (type 1) with one API-key sign-in only when needed, "User does not exist" is `no-account`, an accepted member is confirmed with `bw confirm org-member`; - an invitation to an account without a master password is withdrawn at once (`awaiting-password`) and made again once the password is set: while such an invitation is pending, Vaultwarden lets anyone who knows the address register it with a master password unless the network requires SSO of people (SSO_ONLY), and the Environment would then confirm that account; - a work Environment keeps the fingerprint of the assignment its Správci were added under (`lazurio-assignment.json`, a SHA-256 of the Organization and the assignment's kind and GitHub id, never a person); when it differs, or cannot be read, every Admin-type member leaves. The Owner and User, Manager and Custom members are never touched. A personal Environment never removes; a Team or Automated Environment neither adds nor removes until a live answer of who may enter exists; - `vaultAudience` is the removal alone, for the Launchpad's start and its periodic look; `vaultSignIn` asks the vault's public /identity/sso/prevalidate whether it takes the Lazurio sign-in. The vault's membership is the only list; nothing returns, logs or journals an address, a member id or a token. The fake Vaultwarden and the fake bw learn the members, the invitation, the removal, the confirmation and the SSO prevalidation with Vaultwarden's shapes and messages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vironment's own vault
Root decision 0198 point 5 and the published wireframe (DEV-6631 task
648): a Settings section after Tools at /settings/vault with the rule
"Kdo má přístup do Prostředí, má všechna jeho hesla.", one row with the
vault's name and its state (the item count, "Zakládání trezoru…" while a
setup runs, "Neodpovídá"), and the actions the person's membership
decides: "Přidat položku" (the vault filtered to its collection Agenti,
where the web vault's New preselects them) and "Otevřít trezor", or
instead "Vytvořit účet v trezoru" (the vault's sign-in) while the person
has no account there, offered only where the vault takes the Lazurio
sign-in. A 0197 pilot opens its collection; a workstation and an
Environment without a vault say so in one line; a Team or Automated
Environment says that only its agents use the vault. The Launchpad never
lists items or shows a value. A hidden slot above the row waits for the
agents' secret requests (task 651).
Routes, behind the admission of every route: GET /api/vault (the
recorded state, the running setup's step, the kind of Environment) and
POST /api/vault/membership {} (where the admitted person stands, after
the Environment adds them; with `signIn` while they have no account).
The person is the gateway's subject from the request's own admission.
An installed hosted Launchpad looks at the audience once its start's
setup ends and every five minutes, so a reassigned work Environment's
Správci leave without anyone opening the page.
Tests over HTTP against startLaunchpad behind a fake gateway, the fake
Vaultwarden and the fake bw: no identity means no membership action;
forged identity headers are ignored; no-account, awaiting-password
(withdrawn, then added once the password is set), accepted, confirmed
and member; reassignment removes only Admin-type members, also at the
start; a personal Environment never removes; a Team Environment does
nothing; SSO off means no account button; the links carry the exact
organization and collection ids; no value, token or address reaches the
logs, the journal, bw's argv or an answer; a workstation's page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests/vault-page-view.test.ts states the page's rules on answers of the server's shapes: answers read only in their exact form; the links by the vault's exact ids and nowhere else (a 0197 pilot to its collection, a non-https or non-bare origin to none); a member adds and opens, a person without an account (or without a master password) gets only the sign-in and only where the vault takes it; the item count in Czech plural, the creation line, "Neodpovídá" with the recorded links kept, a gone vault without a way in; this computer, an Environment without a vault, a 0197 pilot, a Team and an Automated Environment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e and its Správci decisions.md: F11 gains one narrow use of the admission's own answer, the admitted session's subject (X-Auth-Request-User, a lowercase UUID), only for the membership of the Environment's own vault, whose access is access to the Environment (root decision 0198 point 2); never a repository right, an operator or a role. F53's addendum records Nastavení → Trezor (the page, its routes, the links), the Správci (add on presence on personal and work Environments, an invitation never left pending, removal of every Admin-type member when a work Environment's assignment changes, no stored list) and the known gaps: Team and Automated Environments, sharing withdrawn without a reassignment, INVITATIONS_ALLOWED=true on the network's vault. hosted-entry.md, environment-access.md, environment-tools.md and launchpad-development.md say the same where they describe admission, access, the vault and the Settings routes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gap of its own The empty live region took a slot of the section's 28 px column gap, so the vault's row stood far below the rule. Inside the head block it keeps its place for announcements with the block's small gap. Seen in the browser check of the page (decision 0178). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The admission already accepts only a lowercase UUID as the gateway's subject; the core no longer relies on its caller for that. Anything else (an uppercase UUID, a login, an address, an empty string) is nobody: no invitation, no confirmation, only the audience look that needs nobody. tests/vault-members.test.ts also states that a vault which is not set up is asked nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… creation is not confirmed #391 gained the state `creating` (the organization's creation was asked for and is not confirmed yet; the next setup looks for it again, and the Launchpad's start runs that setup). The page's row now says the vault is being created, as for a running setup, with no way in until the vault is the Environment's; it said "Not available here" before, through a default branch. The row's words are now an exhaustive switch over the states, so a state added later fails to compile instead of falling through. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… path of the person's address Review of 2026-10-14 (P1): withdrawing an invitation the vault left Invited was not failure-safe; a DELETE that failed left a pending invitation through which anyone who knew the address could register it. The withdrawal is gone. Instead the Environment invites and confirms only behind a gate: the network's vault must refuse every password path of the person's address (SSO_ONLY, the address not exempt). Why that gate and not "SSO declared": Vaultwarden 1.37.4's send_invite keeps an invitation row with every invitation to an account without a master password (SMTP off, whatever INVITATIONS_ALLOWED says), and while a password can be registered for an address, register takes that row. Proven against the real 1.37.4-lazurio.1 image: with SSO declared, INVITATIONS_ALLOWED=false and SIGNUPS_ALLOWED=false (Machines #508's contract) an invited stub's address registered (HTTP 200); with SSO_ONLY it did not (HTTP 400). The vault says which itself: its token endpoint refuses a password grant naming only the address with "SSO sign-in is required" exactly when SSO_ONLY covers it, before any account is looked up and before its rate limit or sign-in events (`signInRequired`, the fixed code `sso-required` in vaultRequest). Elsewhere, or when the vault does not answer, nobody is invited or confirmed (`sign-in-not-required`; the page says that only the agents use the vault); removal needs no gate. Behind the gate an invitation to an account without a master password stays Invited (`awaiting-password`); the vault accepts it when the person sets the password, and the next look confirms. A vault that is not set up is asked nothing. Tests: the fake Vaultwarden models SSO_ONLY (password grant and registration refused for person addresses, exactly Vaultwarden's order) and an invitation that fails before or after it is made. New and changed contract tests: a pending invitation kept, unregistrable and confirmed once the password is set; nobody invited or confirmed with SSO declared alone or without SSO (an accepted member is not confirmed there); a failed or interrupted invitation leaves nothing registrable and the next look goes on from the vault. Mutations: no gate fails 2 tests, a gate on prevalidate alone fails the SSO-declared case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the network's SSO_ONLY The Správci are invited and confirmed only where the network's vault refuses every password path of the person's address (SSO_ONLY), measured by the vault's own token endpoint; the evidence from the real image (registrable under Machines #508's settings alone, not under SSO_ONLY); nobody added until a network runs SSO_ONLY; SSO_ONLY never to be turned off with pending invitations; the replaced invite-then-withdraw and the rejected prevalidate-only gate in the alternatives. environment-tools.md says the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#391 renumbered the Environment's own vault from F52 to F53 when it was rebased onto main, where F52 is the module generator (#394). This pull request's references follow it: the addendum of 2026-10-14 is F53's in decisions.md, hosted-entry.md, environment-access.md, environment-tools.md and launchpad-development.md (with their anchors), and in the comments of server.ts, members.ts and the vault page's HTTP tests. No reference to the module generator's F52 changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fa60777 to
adbaafa
Compare
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty — APPROVED on adbaafa against main dace17d. Re-review after #391 rebase merge: the new head tree d1756746c6af4b68d6f38ca0f491ff5fb71ffb55 is byte-identical to fa60777; range-diff maps all 11 PR commits one-for-one. The final change corrects vault-decision references to F53 in the F11 amendment, five docs, code comments and the HTTP test; F52 still identifies the module generator, and this PR does not touch src/folder. The earlier security P1 remains resolved by the SSO_ONLY password-path gate. Independent isolated exact-head check: 40 focused tests passed; lint, typecheck, public guard, proof build and smoke passed; git diff --check clean. Exact-head CI run 38574972736 succeeded; no unresolved review threads or competing review requests. The reported local full-suite launchpad-prompts race (#413) is outside this diff; I did not repeat that broad suite. Deployment still depends on keeping SSO_ONLY enabled while invitations remain pending and qualifying the live gateway subject on a canary. No merge performed.
Motivation
Root decision 0198 points 2, 3 and 5 (plan DEV-6631 tasks 648 and 638b): every Environment owns its vault (#391), whoever has access to the Environment is a Správce (an Admin) of its vault and has all of its passwords, and people enter the vault from the Launchpad's Nastavení → Trezor. Until now nobody but the Environment's own account was a member of its vault, and the Launchpad had no way into it besides the Tools row's link.
Target state
/settings/vault, a Settings section after Nástroje), following the published wireframe (EnvVaultof prototypes-lazurio 794f3735): the rule "Kdo má přístup do Prostředí, má všechna jeho hesla.", one row with the vault's name (vault.name) and its state (the item count, "Zakládání trezoru…" while a setup runs, "Neodpovídá" when the vault does not answer), and the actions the person's membership decides:<server_url>/#/vault?organizationId=<vault>&collectionId=<Agenti>(phase 1: the web vault's New then preselects both) and "Otevřít trezor" →<server_url>/#/vault?organizationId=<vault>;<server_url>/#/login, and only where the network's vault takes the Lazurio sign-in (its publicGET /identity/sso/prevalidateanswers with a token, kept a minute); otherwise no account button;creating): "Zakládání trezoru…" and no way in yet;vault: one line; a Team or Automated Environment: "Trezor tohoto Prostředí zatím používají jen jeho agenti.";/oauth2/auth; that same answer now yields the admitted session's subject from the gateway's ownX-Auth-Request-User(oauth2-proxy withset_xauthrequest = true, user claimsub; Caddy strips onlyX-Auth-Request-Access-Tokenthere). Only a lowercase UUID counts; a header of the request never names anyone. This is a narrow amendment of decision F11 ("admission is not identity"), recorded indocs/decisions.md: used only for vault membership, never for repository rights, an Operator or a role.src/vault/members.ts, under the vault lock, as the vault's only Owner): the person is<sub>@vaultwarden-identity.lazurio.ai. On a personal or work Environment,POST /api/vault/membershiplists the members (bw list org-members), invites an absent person as Admin (type 1) through the vault's API (one API-key sign-in only when needed), maps "User does not exist" tono-account, keeps an invitation to an account without a master password Invited (awaiting-password; the vault accepts it when the person sets the password), confirms an accepted member (bw confirm org-member) and reportsmember.SSO_ONLY, the address not exempt). The vault itself answers this: a password grant naming only the address gets "SSO sign-in is required". Elsewhere, or when the vault doesn't answer, nobody is invited or confirmed (sign-in-not-required, and the page says only the agents use the vault). Removal needs no gate.owner.assignmentits Správci were added under (lazurio-assignment.json, a SHA-256 of the Organization and the assignment's kind and GitHub id, never a person); when it changes (or the file is lost), every Admin-type member leaves; the Owner and User/Manager/Custom members are never touched. Checked at every membership look and, in the installed hosted Launchpad, after its start's setup and every five minutes (local reads; the vault is asked only after a change). A personal Environment never removes; a Team Environment neither adds nor removes.What changes
src/launchpad/hosted-trust.ts:Admissionis{ok: true, subject: string | null}; the subject from the auth endpoint's answer, cached with the admission.src/vault/members.ts(new):vaultMembership,vaultAudience,vaultSignIn,personAddress.src/vault/bw.ts:orgMembers(bw list org-members --organizationid),confirmMember(bw confirm org-member <id> --organizationid),parseOrgMembers(only id, email, status, type are kept).src/vault/register.ts: fixed reasonsno-account("User does not exist"),already-memberandsso-required("SSO sign-in is required").src/vault/context.ts:VaultContext.assignment(assignmentOf);src/vault/store.ts:lazurio-assignment.json;src/vault/flow.ts: exportsconnectedAccount,deviceOf, the journal operationmembers.vault-page-routes.ts(GET /api/vault,POST /api/vault/membership),vault-page-view.ts(pure),vault-page-panel.ts(DOM),routes.ts(sectionvault),index.html(first-paint list, hide rules, nav item, section, slot),ui.ts,messages.ts(en, cs formal),server.ts(subject passed from the admission, routes, the audience look),vault-routes.ts(running()).docs/decisions.md),hosted-entry.md,environment-access.md,environment-tools.md,launchpad-development.md.Deviation from the shaping (please decide)
The invitation gate is
SSO_ONLYfor the person's address, not "SSO declared". The review asked for a network-side registration gate. The coordinator's design gated on/identity/sso/prevalidate(SSO declared) plus Machines #508'sINVITATIONS_ALLOWED=falseandSIGNUPS_ALLOWED=false. That rested on "an org invite to an existing SSO stub creates noInvitationrow", which the fork source and the real image contradict:send_invitesaves anInvitationrow for every existing account without a master password (SMTP off), whateverINVITATIONS_ALLOWEDsays.registertakes that row.SSO_ONLYit did not (HTTP 400).So the gate is the vault's own
is_sso_requiredanswer. Consequence: until a network runsSSO_ONLY, its Environments add nobody; people use the vault through the agents. The earlier invite-then-withdraw is gone: a failed withdrawal left a registrable invitation (review P1). Details and evidence are in the PR comment replying to the review.Other choices to note:
POST /api/tools/bitwarden/refresh) for the fresh count and "Neodpovídá" rather than a new route.What deliberately does not change
running()is exposed).Verification
Full gate
bun run checkon headadbaafa6f7e1948185060429350986e43481eaa3(onmaindace17d7): Biome (693 files),tsc, the public guard (850 files), the proof build and smoke, then 3511 pass, 8 skip, 1 fail (601 s). The one failure is the known race of Flaky: launchpad-prompts expects no GitHub call before admission, but the Launchpad's start peeks the Personalspace holder in the background #413:tests/launchpad-prompts.test.tsasserts no GitHub call before its first 401, while the Launchpad's start peeks the Personalspace holder in the background. It is untouched here, passes alone 5/5 and next to this PR's tests 3/3, and failed in both sequential full runs on this machine. GitHub CI on this head (run 38574972736): static checks, tests 1/2 and 2/2, and the ubuntu check all pass.Contract tests on the real consumer:
tests/launchpad-vault-page.test.ts(13), run againststartLaunchpadover HTTP behind a fake gateway auth endpoint. The fake Vaultwarden and fake bw cover org members, invite, delete, confirm, SSO prevalidate, andSSO_ONLYin Vaultwarden's own order. Covered:X-Auth-Request-User,X-Auth-Request-Email,X-Forwarded-User/-Email) are ignored;Also:
tests/launchpad-hosted-trust.test.ts(the subject; forged headers for named, anonymous and denied sessions),tests/vault-page-view.test.ts(5, includingcreatingand the closed gate),tests/vault-members.test.ts(only a lowercase UUID names a person; a vault not set up is asked nothing),tests/vault-context.test.ts(the fingerprint), routes and first-paint.Mutation checks (each reverted): no gate → 2 tests fail; a gate on prevalidate alone → the SSO-declared case fails; trusting a forwarded
X-Auth-Request-User→ 2 fail; removing every non-Owner → 1 fails; Team adding → 1 fails; never removing → 3 fail.The premise, on the real image
ghcr.io/lazurio/vaultwarden:1.37.4-lazurio.1@sha256:68da93bb…f492(amd64 under Rosetta, own container prefix, port and TLS CA):client_id cannot be blankSSO_ONLYSSO sign-in is requiredEnd to end on the real image with the real pinned bw 2026.7.0, driving this branch's core (run on
a73cf45; since then the vault code is unchanged, only the base, comments and docs moved) in phases on one data volume:SSO_ONLY: "User does not exist" maps tono-account; a password account is invited, accepted and confirmed by the realbw confirm org-member; the stub is invited and kept at status 0 and cannot be registered (400); no second invitation; a reassignment removes only Admins and keeps the User and the Owner; the person with access is re-added; no address, subject or secret in 17 bw argv lists or 8 journal entries;SSO_ONLY, the confirmed person decrypts the organization key bw encrypted to them, down to "Agenti".In a browser (decision 0178): a throwaway hosted Launchpad of this branch per scenario (fixtures, Czech) behind a stand-in gateway proxy, driven in the installed Chrome (playwright-core). Scenarios: a work member (name, "12 položek", "Přidat položku" + "Otevřít trezor" with the exact hrefs), no account ("Vytvořit účet v trezoru" →
#/login), no account with SSO off (no buttons), Team (agents-only line, no buttons), creating ("Zakládání trezoru…"), no vault, workstation, and a 390 px viewport. 40/40 checks onadbaafa, no page errors (creatingwithout a running setup, and the closed gate, are covered bytests/vault-page-view.test.ts, not in the browser). A real Remote Environment, a live gateway and a live SSO sign-in are not part of it.Risks, open questions, follow-ups
organization-host/proofs/oidc-consumer:X-Auth-Request-Useris the opaque OIDC subject) and by reading the workspace-vm config; it has not been read on a live Environment gateway yet. Please verify on a canary: the page's membership must answer for the person, notno-identity.suband the vault client'ssubmust come from the same realm (workspace, contract C1); otherwise people stayno-account(fails closed).SSO_ONLY(Machines turns it on per network; DEV-6631's staged rollout). Qualification: the canary of v0.1.9-rc.6 and its evidence (DEV-6668) #508'sINVITATIONS_ALLOWED=falsekeeps "User does not exist" for a person without an account. Withtrue, an invitation creates an empty account, which is safe underSSO_ONLYand is taken over at the person's first sign-in.SSO_ONLYmust never be turned off on a network with pending invitations: that reopens their addresses to registration. The gate then stops confirming, but the account is lost to its person.Issue draft (Lazurio/LazurioPlatform)
Base
#391 is merged into
main(rebase-merge,dace17d7), and this pull request now targetsmainwith only its own 11 commits:main's F52 is the module generator of Modules: one module generator in the Platform, with the personal form (M2 1/3, #359) #394), so this pull request's addendum is F53's everywhere: decisions.md, the other docs and their anchors, code comments, tests and commit messages. No reference to the module generator's F52 changed.creatingis handled by the page through an exhaustive switch, so the next new state fails to compile instead of reading "Not available".Plan and work context
HumanAndMachine-ai_GEN3/.worktrees/productionspace/LazurioPlatform/DEV-6631-trezor-page, branchagent/DEV-6631-trezor-page.b643d1c5-bc04-44a8-a2c5-d80707571628(claude --resume b643d1c5-bc04-44a8-a2c5-d80707571628).Status: ready for review
🤖 Generated with Claude Code