## AndrewDryga/emisar — v0.49.0…v0.50.0

_160+ commits._

### Features
- **feat(packs): add an EMQX broker pack with reads and gated writes** (a21b502)
- **feat(accounts): let a person detach their login from an SSO workspace seat** (ad77f5c)
- **feat(portal): unlink directory-created seats from personal logins** (111b3f8)
- **feat(accounts): invitations create a workspace member, not a personal login** (59debec)
- **feat(sso): create workspace members, never personal logins, from SSO and SCIM** (d4ea521)
- **feat(auth): let a member link a personal login by proving the mailbox** (265ac71)
- **feat(auth): let a workspace member exist without a personal login** (2b2c879)
- **feat(audit): name the workspace member, not the personal login** (96c0a2e)
- **feat(sso): let a member invited back move their SSO identity themselves** (a5cffce)
- **feat(packs): add a read-only EMQX broker pack** (b7d7f0f)
- **feat(packs): add a read-only SuperTokens core pack** (7f21fbc)
- **Require same-session new-mailbox proof before changing sign-in email** (e93f52a)
- **Satisfy Credo readability rules in two new v1-audit tests** (3d89ae1)

### Fixes
- **fix(ci): compile the portal from scratch and bring the SSO e2e to members** (82471db)
- **fix(sso): an identity a person moves by step-up is theirs, not an admin's** (5023af9)
- **fix(sso): keep members who come back through SSO able to sign in** (02ff74d)
- **fix(web): undo what the Tailwind 4 move broke** (93c05ab)
- **fix(packs): close three leaks the release review found** (62475c7)
- **fix(ci): restore the checks the v0.49.0 window broke** (c970443)
- **fix(billing): manage only this workspace's own Paddle subscription** (04252ec)
- **fix(runs): bound how many stale runs one dispatch call refuses** (c2413ee)
- **fix(accounts): refuse a workspace switch whose route ended mid-switch** (54d15a7)
- **fix(accounts): detach a login only from a seat SSO can still sign in to** (13602b7)
- **fix(runs): refuse only a still-pending run and drain every stale one** (6dd2db0)
- **fix(accounts): accept an invitation only when the invited mailbox proves it** (869c7e6)
- **fix(sso): end a login-less member's keys when its last sign-in goes** (9d0bbfe)
- **fix(runs): refuse a queued run whose initiator lost access** (538330f)
- **fix(web): count member-link email requests against signup's hourly cap** (227bd57)
- **fix(packs): retire postgres, mysql and victorialogs versions before the re-tier** (a0ca3df)
- **fix(audit): record how the destination was reached on a workspace switch** (f06c4e3)
- **fix(web): show the no-access message after a magic-link sign-in** (b27c305)
- **fix(tooling): make ./run test packs -h print usage instead of running packs** (ec701ef)
- **fix(mail): also drop the Arabic letter mark from workspace names** (1af9604)
- **fix(auth): harden the member-link emails** (2918145)
- **fix(portal): keep link requests matching pending invitations in the backfill** (cf6c91d)
- **fix(auth): send a distinct member-link email and a notice after linking** (1e241db)
- **fix(portal): keep pending invitations out of the identity seat backfill** (ef2e271)
- **fix(auth): audit a member-only session's sign-out** (94ea61e)
- **fix(sso): prefer the current seat's identity when a person holds two** (e885bbf)
- **fix(sso): open a sibling workspace only for the same IdP subject** (712aa09)
- **fix(portal): require a seat for every SSO identity in the unrun migration** (fae8a45)
- **fix(packs): make action descriptions state the contract, not instructions** (dbcbb9a)
- **fix(mcp): state the contract facts the tool descriptions left out** (962e3b5)
- **fix(skills): match the public skills to current runner, MCP and installer behavior** (a230527)
- **fix(mcp): wait 45 seconds by default so Slack's 60-second limit never cuts a call** (6df9148)
- **fix(clickhouse): keep raw SQL, errors and source URLs out of low reads** (9b8fe05)
- **fix(infra): make the restored-clone check runnable before cutover** (a09920f)
- **fix(mcp): keep an operator's Grok rules when disconnecting Emisar** (628fb9b)
- **fix(sso): hold a re-invited member's sign-in for admin approval** (ece8546)
- **fix(runs): settle a queued run whose action the runner withdrew** (e814f58)
- **fix(portal): keep inactive accounts out of global maintenance heads** (ae157ab)
- **fix(consul): keep raw check output out of low-risk health reads** (7f9982f)
- **fix(scim): decline non-string User filters instead of listing users** (3599652)
- **fix(portal): add the member profile column instead of renaming it** (6953770)
- **fix(portal): split the compile-time authorizer kit from the live gate** (3c4240e)
- **fix(sso): apply sign-in's same-person rule to step-up; correct its docs** (12c5d2a)
- **fix(portal): keep self-approval separation for requests written mid-deploy** (c432b5d)
- **fix(portal): backfill member profiles from what workspaces already showed** (5a16af9)
- **fix(portal): preserve exact administrative member receipts** (eb38142)
- **fix(portal): preserve exact enrollment key member history** (d66a6be)
- **fix(portal): bind approval authority to exact members** (21da6e3)
- **fix(portal): attribute runbook authorship to exact members** (2e6e5ee)
- **fix(portal): bind workspace access to proved session grants** (dd76a82)
- **fix(audit): let SIEM collectors drain export receipts** (75c1ee5)
- **fix(portal): seed memberships with explicit authentication context** (d4fe8be)
- **fix(mcp): preserve accepted operations when observation loses access** (16dc782)
- **fix(runner): reload packs after partial and JSON updates** (26221b0)
- **fix(tooling): honor native prerequisites and DB-only startup** (2cdff2f)
- **fix(runner): consume static registry update artifacts** (2636365)
- **fix(runner): align local action JSON and recovery guidance** (648ec95)
- **fix(runner): release completed dispatch contexts** (5045268)
- **fix(runner): serialize shared audit journal writers** (ee72ae7)
- **Walk the Mint HTTP/1 smuggling patch through the release-age gate** (6fc9859)

### Backend
- **release: v0.50.0 — Workspace-owned members and per-workspace billing** (e5c2291)
- **Packs: repair Nomad snapshots and expose read-scoped plan logs** (dfdfd8f)
- **revert(packs): hold the SuperTokens pack until the founder publishes it** (1a5c79a)
- **revert(packs): hold the EMQX pack until its key decision** (cc0d88f)
- **Bind SSO identities and approvals to exact workspace members** (0c88a11)
- **Omit the output-gap flag from runs that never reached a runner** (1e59342)
- **Let an agent cancel its own run while it waits for approval** (6a348e5)
- **Keep workspace profiles and attribution account-local** (92afe86)
- **Require personal provenance for profile and session controls** (14b827c)
- **Run the SSO development stack on Keycloak 26.7.3** (5762f2b)
- **Move the random provider to 3.9.1 and lock it for every platform** (94546d7)
- **Move the portal host image to the current 121 LTS build** (234b30b)
- **Disclose the Paddle customer record every workspace gets** (205ecba)
- **Scope an SSO session to the accounts that federate with its IdP** (0e86f24)
- **Align the email lockup and give every email one visible container system** (b2d0628)
- **Give the zot pack a behavior plan** (6e93c1f)
- **Keep the host image on the monthly bump cadence and note the secret alert** (4da5446)
- **Tidy four billing edges from the v1 audit** (42d0137)
- **Make the MCP bridge and its installer composable again** (bea928b)
- **Tidy four MCP boundary edges from the v1 audit** (caa58dd)
- **Keep the MCP tool contracts inside their frozen schemas** (d03122a)
- **Give three Subject-gated mutations their own denial case** (854e7b1)
- **Sharpen three docs claims from the v1 audit** (972f718)
- **Drop request logs for secret-bearing auth paths** (880fc6f)
- **Fail closed when production boots without a mailer** (ef21375)
- **Scope the invoice ledger to the account's subscription** (5b044e9)
- **Portal minor and nit fixes from the v1 audit** (bdcdd45)
- **Harden pack manifests and scripts from the v1 audit** (b501c4f)
- **Anchor a validation pattern to the whole argument value** (258c699)
- **Score exec/command position in the pack curl lints** (112b415)
- **Correct public docs and claims from the v1 audit** (cbfdb12)
- **Scope an SSO session to the account whose IdP minted it** (366867f)
- **Write the restored-clone promotion procedure the RTO rests on** (a6b791d)
- **Revoke a member's pending approve votes with their membership** (59d4a7f)
- **Keep elasticsearch actions to one index and tier the cancel actions high** (0e3347c)
- **Deny the run-mutating HCP Terraform actions on the admin runner** (6c96a19)
- **Make the runner non-dumpable and protect its own /proc entry** (527c3ea)
- **Key the per-route body caps on the path the router matches** (40610f0)
- **Let the Windows installer follow the redirect GitHub assets answer with** (36e9e2b)
- **Retire the nomad, nginx, and pfsense versions whose tiers skipped approval** (e97e020)
- **Fail a checkout reservation whose Paddle create never landed** (50d22a3)
- **Budget invitation sends per workspace and keep the inbox lines fixed** (1567cb9)
- **Keep a member's MFA reset inside the only workspace they belong to** (6e937f4)
- **Require the local second factor on the staff console gate** (447e73a)

### Tests
- **test(emqx): start the helper subscriber only after EMQX imports its login** (42b56db)
- **test(api_keys): pin that a key mint re-reads its session grant** (87f552f)
- **test(runs): expect a stale queued run to be refused, not left pending** (6fbb78a)
- **test(auth): cover switched_subject_options/2 in its own describe** (921aa86)
- **test(runner): pin why secret-named colon values stay redacted** (d9f2493)
- **test(portal): never hand a test a TOTP code about to go stale** (f94e9a9)
- **test(sso): a sibling workspace needs the same identifier claim** (5db105a)
- **test(tooling): bound the pack-test cancel fixture by run start, not 1s** (ac84558)
- **test(seeds): drop dev-only edge-case seed tests** (f9df710)
- **test(installer): await fake service readiness** (c0a5b8c)

### Docs
- **docs: correct the auth, SSO and privacy pages for this release** (d6f08d4)
- **docs(infra): restart Livebook after a restored-clone cutover** (d9edc6b)
- **docs(infra): move the Cloud SQL rows with the instance in a clone cutover** (5c7a764)
- **docs(agents): fix stale facts in the manuals, skills and KB** (630b841)
- **docs(packs): make the pack guide start from research and go deep** (b142943)
- **docs(nomad): drop the host volume raw_exec cannot mount** (fa999e0)
- **docs(containers): make the mounted runner config boot with the image's limits** (cfcf09a)
- **docs(packs): make authoring and static registry examples accurate** (793aafc)

### Chore
- **chore: release-prep fixes for the dependency gate, infra and runner notes** (1bea955)
- **refactor(sso): key workspace authority and SSO identities on the member** (09eb9e7)
- **refactor(auth): resolve sessions from the bearer's grant, not the user id** (b8e3388)
- **chore(mcpeval): default the weekly Claude lane to claude-sonnet-5** (edef57b)
- **refactor(portal): drop the rolling-deploy handling from today's changes** (e25810a)
- **refactor(auth): reference SSO route identities by id alone** (e044a8f)
- **refactor(sso): bind existing identities to the live seat; drop Restore sign-in** (31bcfb8)
- **refactor(portal): drop the approval migration's preflight refusal** (f71ce99)
- **refactor(auth): drop MFA mutation fences and repeated session re-checks** (e6e64a5)
- **refactor(sso): drop the reviewed-snapshot fence on link approvals** (4610134)
- **refactor(portal): drop approval fail-closed states and key-rotation locking** (9e14907)
- **refactor(portal): drop support-tool ambiguity branch and dead profile paths** (437013f)
- **refactor(auth): drop email-change cancel API and unreachable proof fences** (e43313f)
- **refactor(mcp): drop between-reads guards and the cancel re-lock ladder** (9f1dd46)
- **refactor(runner): drop duplicated index checks and edge-case tests** (d207650)

_Recap by [Repo Wrapped](https://repowrapped.com/gh/AndrewDryga/emisar?utm_source=github-action)._