All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Planning milestones vs Hex releases

This changelog uses Semantic Versioning headings like [0.2.0] for published Hex releases. Separately, maintainers track planning milestones labeled v1.0–v1.4 in .planning/MILESTONES.md — those v1.x labels describe shipped tranches of work, not a second installable version axis on Hex (this repo remains 0.x on Hex until a real 1.0.0). Each dated release below may include a Roadmap traceability subsection (H3) linking back to the milestone narrative. When in doubt, treat MILESTONES.md as canonical for dates and archive paths.

Unreleased

1.20.0 (2026-04-28)

Summary

  • v1.20.0 GA Launch: Sigra reaches General Availability. This release finalizes the audit completeness evidence and production UAT documentation, providing operators the guarantees needed to deploy with confidence.

Changed

  • planning: Phase 85 / AUD-21 closes the impersonation audit-atomicity gap: the default Ecto session store now co-fates impersonation session writes with admin.impersonation.start / admin.impersonation.stop, while non-Ecto stores keep the legacy create / delete + log_safe path.
  • planning (Phase 87 / GAUAT-03..06 verification-approach correction): v1.20 GAUAT OAuth slice (gen smoke + Google register/login + provider linking + email-match confirmation) reshaped from "human runs mix sigra.gen.oauth + clicks real Google + captures screenshots" to a fully automated end-to-end harness — Sigra.Testing.OAuthIssuer (TestServer-backed in-process OIDC issuer mirroring Assent's own OIDCTestCase) drives Sigra's real HTTP stack from three Playwright specs (oauth-register / oauth-link / oauth-email-match) on every PR. Generator smoke extends scripts/ci/install-smoke.sh to add mix test on the freshly-generated host. Adopter-side real-credential check ships as mix sigra.oauth.smoketest --provider=google + docs/oauth-google-setup.md. 0 human UAT for v1.20 launch — matches Auth.js / Spring Security / Assent / pow_assent / Devise+omniauth ecosystem convention. REQUIREMENTS.md GAUAT-03..06, ROADMAP.md Phase 87, and docs/uat-ci-coverage.md SEED-001 row updated in the same commit (Phase 86 D-86-08 precedent).

0.2.5 (2026-04-25)

Summary

  • Several audit-backed MFA, JWT, account, and API-token flows now succeed or fail as one unit instead of risking a data change without the matching audit row.
  • Malformed refresh tokens fail earlier with {:error, :invalid_token} instead of going through the normal hash-and-lookup path first.
  • Most apps do not need new upgrade steps for this release; it is mainly a safety, correctness, and observability improvement.

Changed

  • mfa: When :audit_schema is configured, Sigra.MFA.confirm_enrollment/5 writes mfa.enroll.failure for invalid TOTP (pre-enrollment DB work) inside Repo.transaction/1 via Ecto.Multi + Sigra.Audit.log_multi_safe/3, using the same commit_ad_hoc_mfa_audit/5 shell as other MFA ad-hoc audits (AUD-20-01 / AUD-04-022). The caller still receives {:error, :invalid_code} regardless of audit insert outcome; audit failures emit [:sigra, :audit, :log_safe_error]. Evidence: test/sigra/mfa_audit_atomicity_test.exs.
  • jwt: When :audit_schema is configured, Sigra.JWT.refresh/3 (and Sigra.Auth.refresh_jwt/2) runs refresh-token user_tokens persistence and api.jwt_refresh / api.jwt_refresh_reuse audit inserts in a single Repo.transaction/1 via Ecto.Multi + Sigra.Audit.log_multi_safe/3 (persistence + audit co-fate / AUD-08 for the guided path). Any step failure in that transaction returns {:error, :jwt_refresh_aborted} instead of issuing new tokens without a matching audit row. Evidence: test/sigra/jwt_refresh_audit_cofate_test.exs.
  • jwt: Refresh-token classify/revoke paths now base64url-decode the raw refresh token before hashing, so malformed or non-decodable inputs return {:error, :invalid_token} instead of hashing the encoded wrapper bytes.
  • audit: When :audit_schema is configured, Sigra.APIToken.audit_jwt_refresh/2 and audit_jwt_refresh_reuse/2 write api.jwt_refresh / api.jwt_refresh_reuse inside Repo.transaction/1 via audit-only Ecto.Multi + Sigra.Audit.log_multi_safe/3 (audit-row atomicity only — standalone helpers; prefer JWT.refresh/3 for co-fate so audit is not double-emitted).
  • audit: When :audit_schema is configured, Sigra.Account.clear_password_change_requirement/3 clears must_change_password and writes account.password_change (metadata: %{forced: true}) in one Repo.transaction/1 via Ecto.Multi + Sigra.Audit.log_multi_safe/3. Sigra.Account.audit_forced_password_change/2 is deprecated for that path — do not call both or you may duplicate audit rows.
  • audit: When :audit_schema is configured, Sigra.APIToken.verify/2 now writes api.token_verify.failure audit rows inside Repo.transaction/1 via Ecto.Multi + Sigra.Audit.log_multi_safe/3 (invalid, revoked, and expired branches). Success remains telemetry-only (D-27). Insert failures emit [:sigra, :audit, :log_safe_error] (:invalid_changeset or :constraint_violation) while the caller still receives {:error, reason}.

Documentation

Added

  • tests: test/sigra/jwt_refresh_audit_cofate_test.exs covers Sigra.JWT.refresh/3 persistence + audit co-fate (happy path, audit-off, reuse + audit, CHECK fault injection on happy and reuse branches).
  • tests: test/sigra/api_token_audit_atomic_test.exs covers api.jwt_refresh / api.jwt_refresh_reuse (happy path, audit-off, CHECK fault injection + log_safe_error telemetry).
  • tests: test/sigra/api_token_audit_atomic_test.exs covers api.token_verify.failure for invalid / revoked / expired paths plus audit-table fault injection (constraint / telemetry parity).
  • tests: test/sigra/account_audit_atomicity_test.exs exercises Sigra.Account.request_email_change/4, confirm_email_change/3, and cancel_email_change/3 with Postgres CHECK fault injection so domain mutations roll back when the paired account.email_change_* audit insert is rejected — complements AUD-04-035..037 C-1 evidence alongside change_password.
  • tests: test/sigra/account_audit_atomicity_test.exs covers Sigra.Account.clear_password_change_requirement/3 (happy path, audit-off branch, and account.password_change CHECK rollback) for AUD-04-043 / AUD-17.

0.2.4 (2026-04-24)

Summary

  • MFA backup-code regeneration and trust-browser audit writes are now more durable when audit logging is enabled.
  • A database-level audit insert failure now falls back to the same telemetry-first behavior as other safe audit helpers instead of surfacing a rougher failure mode.
  • This release is mostly operational hardening and docs polish; most host apps do not need a new install or migration step.

Changed

Fixed

  • audit: commit_ad_hoc_mfa_audit/5 rescues Ecto.ConstraintError (and related DB constraint failures) when the audit insert is rejected at the database layer without a matching changeset constraint, preserving log_safe/3-class behavior: emit [:sigra, :audit, :log_safe_error] with reason: :constraint_violation and return :ok.

Documentation

  • planning: v1.11 adoption stabilization — triage notes (.planning/v1.11-TRIAGE.md), upgrading-to-v1.11.md, ExDoc extras, intro upgrade cross-links, and MAINTAINING.md milestone pause guidance (STAB-01..STAB-04).
  • planning: v1.12 trust bundle — upgrading-to-v1.12.md (ExDoc extra), docs/uat-ci-coverage.md (v1.12 launch evidence subsection), and milestone UAT index on GitHub (TRN-01..TRN-03 doc polish).

Roadmap traceability

0.2.3 (2026-04-23)

Summary

  • Release automation and maintainer docs are clearer, especially around token setup for Release Please and downstream CI behavior.
  • No new library features or upgrade steps for host apps.

Bug Fixes

  • ci: document RELEASE_PLEASE_TOKEN for downstream CI on release PRs (#24) (324b036)

0.2.2 (2026-04-23)

Summary

  • Hex package metadata was trimmed to satisfy Hex.pm limits.
  • No runtime behavior change for host apps.

Bug Fixes

  • hex: shorten Hex package description (300 char limit) (#22) (3d8acfe)

0.2.1 (2026-04-23)

Summary

  • Sigra became easier to discover and evaluate on Hex: docs links, package metadata, and first-pass release presentation all improved.
  • This was mostly a packaging and documentation release around the existing 0.2.0 line.

Features

  • 053-01: add Hex docs link and ExDoc publish reminder (3362bf0)
  • 053-01: refresh Hex description for PUB-01 (acd275e)
  • 06-01: add MFA deps, config, error types, and Credential struct (52a25f4)
  • 06-01: implement MFA orchestrator, BackupCodes, Trust, and Lockout modules (e913806)
  • 06-02: add MFA-aware authenticate flow and complete_mfa_verification (db192a1)
  • 06-02: add RequireMFA and RequireMFAEnrolled plugs with mfa_pending session type (d3bb45b)
  • 06-03: add MFA telemetry event catalog and integration (826945c)
  • 06-03: add MFA testing helpers and TokenCleanup mfa_pending extension (bf17b7c)
  • 06-04: add MFA email templates, Auth context delegation, and test fixtures (8a93edb)
  • 06-04: add MFA migration tables and generated Ecto schemas (e66b8f4)
  • 06-05: add MFA challenge page templates (controller + HTML + LiveView) (8efd59d)
  • 06-05: add MFA settings templates, require_mfa plug, and generator wiring (89cc608)
  • 07-01: APIToken module and RequireScopes plug with full test coverage (953adbe)
  • 07-01: config extensions, StringList type, ScopeRegistry, error types, telemetry events (e1e0e39)
  • 07-02: add Joken dependency, ClaimsBuilder behaviour, and Signer module (8c79f0c)
  • 07-02: add JWT module and RefreshToken with family-based reuse detection (2d00c6e)
  • 07-03: add Auth delegation, TokenCleanup extension, Testing helpers, Email notification (611e5f6)
  • 07-03: rewrite FetchBearer with auto-detection and scope assignment (425527a)
  • 07-04: add API controllers, email template, injector, and install task (86f9be4)
  • 07-04: add API token migration and schema templates (9b13525)
  • 08-01: add config extensions, email templates, and data export behaviour (cd3ef15)
  • 08-01: implement hooks engine with Ecto.Multi integration and tests (b635995)
  • 08-02: add Account orchestrator with unified delegation API (44ea30a)
  • 08-02: implement Account Deletion module with 3 strategies (cd31c37)
  • 08-02: implement EmailChange and PasswordChange modules (601d35f)
  • 08-03: add telemetry events and Auth module lifecycle delegation (34e6f2b)
  • 08-03: implement RequirePasswordChange plug and AccountDeletion Oban worker (6c26dce)
  • 08-04: add 7 account lifecycle email templates (36363df)
  • 08-04: auth context lifecycle delegation and hooks stub module (ada92fb)
  • 08-04: migration template, user schema, and token TTL for account lifecycle (21332d3)
  • 08-05: add generator injector for lifecycle routes, plugs, and tests (ba5d3c5)
  • 08-05: add settings LiveView, reactivation page, and lifecycle testing helpers (61112c9)
  • 09-01: add audit_events migration template (02ae340)
  • 09-01: add AuditEvent schema template and wire install task (bd3f69f)
  • 09-02: add Sigra.Audit changeset, cursor, query submodules (01f75de)
  • 09-02: add Sigra.Audit public API (ce6dc7c)
  • 09-03: integrate audit logging into auth + session + security subsystems (0724d96)
  • 09-03: integrate audit logging into mfa + oauth + api_token + account (68e222c)
  • 09-04: add Sigra.Workers.AuditCleanup Oban worker and startup warning (a01a25c)
  • 10-01: add audit test helpers and section headers to Sigra.Testing (d891e2b)
  • 10-02: add scenario fixtures to AuthFixtures template (24ecd7c)
  • 10-03: add :cookie_domain config + Sigra.MFA.Trust.cookie_opts/1 (080fd4f)
  • 10-03: runtime remember_me_options in UserAuth + MFA trust cookie + boot warning (4aa7030)
  • 10-05: add pure helpers + doctests to Config/Auth/Testing (fa57f1e)
  • 10-06: scaffold test/example Phoenix app with Sigra installed (2f1790e)
  • 10.1.1-03: unify example app on Sigra canonical user_sessions store (B6, D-06/D-07) (ddf7b94)
  • 10.1.1-05: flip installer default to binary_id (uuid) PKs (D-10) (d1d2c40)
  • 10.1.1-06: add --yes non-interactive flag to sigra.install (2b15e81)
  • 10.1.1-06: add install_smoke + example_http_smoke CI jobs (ae37e78)
  • 10.1.1-06: add install-smoke.sh and http-smoke.sh CI drivers (c082ab3)
  • 10.1.1-07: add data-testid hook to MFA TOTP secret (7dd8e25)
  • 10.1.1-07: scaffold Playwright golden-path browser smoke harness (24e8c7c)
  • 41: TOTP-gated backup code rotation and GA-01 regression (e5f399e)
  • 43-02: atomic auth.register.success audit via register_user_multi (d2e6efb)
  • 43-03: atomic magic-link and password-reset request audits via Multi (149ab89)
  • 43-04: atomic auth.login.success audit with lockout Multi (3bc7811)
  • 49-01: add mix ci.audit_45 alias for AUD-08 merge gate (3adb5fe)
  • 50-01: add mix ci.install_golden alias for install golden tests (ba8ca30)
  • audit: add audit_multi_step for multi-row Multi audits (a642496)
  • mfa: atomic audit Multis for AUD-06 (MFA) (3d5abf1)
  • uat: add Docker UAT environment + runbook for milestone v1.0 manual gates (812eca0)

Bug Fixes

  • 05: enforce sudo mode on link_provider and unlink_provider (T-05-12) (802b2da)
  • 05: WR-04 remove dead code branch in detect_context_name (77f61b5)
  • 05: WR-05 document encrypted_* field naming convention in get_tokens (fa53680)
  • 06: add Code.ensure_loaded! to function_exported? tests for isolation safety (61826f8)
  • 06: add settings_url binding to email template test for MFA emails (86f9759)
  • 06: correct struct syntax for Ecto.Changeset.cast in MFA enrollment (b968a86)
  • 06: CR-01 use Ecto cast to trigger cloak_ecto encryption for TOTP secrets (3c74dc8)
  • 06: CR-02 eliminate modulo bias in backup code and confirmation code generation (66f1d3b)
  • 06: WR-01 wrap MFA enrollment and cleanup in Ecto.Multi transactions (41b3899)
  • 06: WR-02 combine lockout increment and lock into single atomic query (59f6d78)
  • 06: WR-03 align MFA pending state checks between controller, LiveView, and library plugs (84fd485)
  • 06: WR-04 add missing settings_url binding for mfa_disabled_email template (a73c46a)
  • 06: WR-05 pass required options to setup_totp and simulate_mfa_lockout in fixtures (d8bf183)
  • 06: WR-06 handle trailing slashes in RequireMFA path comparison (c1f5e89)
  • 07: revise plans based on checker feedback (2fd57a5)
  • 08-05: update migration test to match partial unique index from Plan 04 (6037d26)
  • 08: CR-01 add missing callback fns to email change request and cancel flows (befa404)
  • 08: CR-02 add missing callback fns to email change confirm flow (d8f7d08)
  • 08: CR-03 add missing validate_password_fn to password change flow (9903b78)
  • 08: WR-01 execute hook multi instead of discarding it (4152725)
  • 08: WR-02 document TTL-based cleanup for orphaned email change tokens (5285e68)
  • 08: WR-03 include email and hashed_password in deletion_changeset for anonymize strategy (6b775d0)
  • 08: WR-04 validate deletion strategy against known values with safe default (debe7fc)
  • 09: CR-01 harden validate_metadata_size against non-map and unencodable metadata (58120a9)
  • 09: WR-02 raise in Sigra.Audit.stream/2 when repo.stream/1 is unavailable (78a3474)
  • 09: WR-06 WR-07 honor configured retention and batch cleanup deletes (065076f)
  • 09: WR-08 WR-01 sanitize log_safe error telemetry + surface missing repo (41ec4a0)
  • 10-review: CR-01 guard Mix.env() in generated UserAuth remember_me_options (7a922e7)
  • 10-review: WR-01 correct MFA guide function references (fc43f52)
  • 10-review: WR-02 preserve false/nil in assert_audit_event metadata lookup (138777c)
  • 10-review: WR-03 make Sigra.MFA.Trust.cookie_opts/0 raise to prevent silent cookie_domain drop (009d424)
  • 10-review: WR-04 oauth_enabled? requires at least one configured provider (1aae029)
  • 10.1 IN-01,IN-02: robust migration timestamp offsets and pad/1 cleanup (8d031be)
  • 10.1 IN-03: route password reset through Sigra.Auth.reset_password/4 (90d7adb)
  • 10.1 IN-05: stop passing :secret_key_base to verify_confirmation_code/3 (7eef6d8)
  • 10.1 IN-06 follow-up: move helper after handle_event clauses to satisfy --warnings-as-errors (d64177f)
  • 10.1-01: build proper UserToken structs in request_password_reset and request_magic_link (10c7cf9)
  • 10.1-02: backport installer template fixes #1-8 (0ab0d04)
  • 10.1-02: backport installer template fixes #9-16 (b19bdf3)
  • 10.1-03: eliminate mix docs --warnings-as-errors @doc reference warnings (b1f49d3)
  • 10.1-05: scenario/2 raises ArgumentError with valid atoms on unknown scenarios (95987e2)
  • 10.1-06: delete aspirational cursor_portability_test (182edbf)
  • 10.1-06: generator_reset_test stale alias assertion (81d66fd)
  • 10.1-06: sigra.install_test bindings — stale after plan 10.1-02 (32dbae1)
  • 10.1.1-02: fix /users/sudo KeyError on render (B7, D-08) (388856f)
  • 10.1.1-02: wire confirmation email in RegistrationLive (B5, D-05) (fbdc743)
  • 10.1.1-04: replace LoginLive with plain SessionController + SessionHTML (B9/D-12) (ba66d76)
  • 10.1.1-05: flip test/example to uuid PKs end-to-end (B8 root fix) (949f182)
  • 10: revise plans per checker iteration 1 feedback (c70ec28)
  • 44: document APIToken.revoke/2 changeset error in typespec (8df3957)
  • 49-01: scope ci.audit_45 to one multi-path mix test (c658a74)
  • docs: include Nyquist matrix extra for ExDoc link validation (cac5a01)
  • example: JS bundle + endpoint socket + router auth pipeline (58b7122)
  • mfa: correct Ecto.Multi.merge arity for lockout audit Multis (09e2263)
  • MFA: handle cleanup Multi errors in disable flows (2e1d309)

Unreleased

  • Chore: Root .formatter.exs no longer scans test/example/_build (and other generated trees) where Hex-copied *.ex install templates are not valid Elixir — restores reliable mix format --check-formatted for contributors.
  • Human GA (v1.4): see .planning/v1.4-GA-UAT.md
  • AUD-04: Auth log_safeEcto.Multi migration inventory for Sigra.Auth (prioritized AUD-05 batches B1–B3, exclusions, grep evidence) in 43-AUD-04-INVENTORY.md (tag snapshot).
  • AUD-04 (continuation): MFA + Account + API token inventory (AUD-04-020+, AUD-06 / AUD-07 batches) in 44-AUD-04-INVENTORY.md (tag snapshot).
  • AUD-08 / Phase 45: OAuth + ops + worker AUD-04 slice (AUD-04-050+) in 45-AUD-04-INVENTORY.md (tag snapshot).
  • AUD-05 (Auth): When :audit_schema is configured, success audits for auth.register.success, magic-link and password-reset request/verify flows, and confirmed-password auth.login.success (including lockout reset and optional hash upgrade) are written in the same Repo transaction as the associated data changes via Ecto.Multi and Sigra.Audit.log_multi_safe/3.

Roadmap traceability

Planning milestone v1.4 (GA readiness & audit trail completeness; not a Hex version): shipped 2026-04-22 per .planning/MILESTONES.md — see .planning/milestones/v1.4-ROADMAP.md, .planning/milestones/v1.4-REQUIREMENTS.md, .planning/milestones/v1.4-MILESTONE-AUDIT.md, and the GA matrix framing in .planning/v1.4-GA-UAT.md (Executed / Waived language; do not duplicate the matrix here).

0.2.0 - 2026-04-19

Roadmap traceability

Planning milestone v1.3 (cleanup & hardening tranche; not a Hex version): shipped 2026-04-19 per .planning/MILESTONES.md — see .planning/milestones/v1.3-ROADMAP.md, .planning/milestones/v1.3-REQUIREMENTS.md, and .planning/milestones/v1.3-MILESTONE-AUDIT.md.

Added

  • docs/NEXT-STEPS-MANUAL.md — short post-merge checklist (PR merge, Hex, GitHub Release) for maintainers.
  • docs/audit-semantics.md — public note on log / log_multi / log_safe, C-1 hybrid status, and pointers to testing helpers (linked from README).
  • Sigra.Audit.Assertions — ordered latest_audit_event/3 + assert_audit_fields/3 for tests; see guides/recipes/testing.md.
  • Atomic api.token_create audit via Ecto.Multi / Sigra.Audit.log_multi_safe/3 in Sigra.APIToken (telemetry from emit_telemetry_from_changes/1 on successful commit only).
  • Example app smoke tests assert login and MFA enrollment audit rows; host get_user_by_email_and_password/2 now delegates to Sigra.Auth.authenticate/2 with full Sigra.Config so auth.login.* audit runs.
  • Human GA matrix in v1.3-HUMAN-UAT.md closed via machine substitutes; see .planning/uat-evidence/v1.3.0/INDEX.md for CI anchors and per-item evidence.
  • GA UAT shift-left: docs/uat-ci-coverage.md maps SEED-001 items to CI and documents residual human checks; test/example/priv/playwright/tests/ga-uat-shift-left.spec.ts covers invitation email-lock and MFA regenerate UI reachability; example app gains EmailsLifecycleHtmlTest; scripts/ci/getting-started-contract.sh plus getting_started_uat_contract CI job validate getting-started links/commands.
  • Generated and example MFASettingsLive regenerate form uses an explicit type="submit" on the regenerate button so LiveView phx-submit fires reliably.
  • Published to Hex.pm as 0.2.0 (initial package listing).

0.1.0 - 2026-04-17

First library version line with Hex-oriented mix.exs packaging; upgrade to 0.2.0 for the Hex listing and additions above.

Roadmap traceability

Planning milestone v1.2 (admin dashboard tranche; not a Hex version): shipped 2026-04-17 per .planning/MILESTONES.md — see .planning/milestones/v1.2-ROADMAP.md, .planning/milestones/v1.2-REQUIREMENTS.md, and .planning/milestones/v1.2-MILESTONE-AUDIT.md.

Changed

  • BREAKING (behavior): session.create audit now fires AFTER select_active_organization during login, so the very first audit event of a successful login carries the real organization_id rather than a nil one. Previously, session.create fired before the active-org selection step and always had a null org, meaning the v1.2 impersonation anchor would have no tenant to pin against. If you were relying on the old ordering (e.g. a log scraper keyed on null-org events for login detection), update your consumers to match the new ordering.
  • BREAKING (API): Sigra.Audit.Query.build/2 now raises ArgumentError on unknown filter keys instead of silently ignoring them. If your host app was passing an unknown key (e.g. actor: instead of actor_id:) the query previously returned unfiltered results — now it fails loudly. Rationale: silent-ignore on an audit query is a security-adjacent bug; audit systems must be loud about misconfiguration.
  • BREAKING (installer): Sigra.Workers.AccountDeletion job args now require five additional stringified keys at enqueue time: "organization_id", "actor_id", "scope_module", "organization_schema", and "audit_schema". Host apps that use the Sigra installer to generate the account-deletion Oban enqueue site should regenerate that site (or manually add the new args). The worker validates presence of all five via fetch_arg!/2 up front BEFORE any Module.safe_concat call so the KeyError surfaces with the actual missing key.

Fixed

  • Hex package files list includes priv/ (installer, upgrade, and OAuth generator templates) so mix sigra.install / mix sigra.upgrade work when the dependency is pulled from Hex.

Added

  • Sigra.Audit.log_safe/3 accepts a scope as the second positional argument. The scope is duck-typed on %{user, active_organization, impersonating_from}; pass nil explicitly for pre-authentication or truly anonymous call sites. log_safe/2 remains as a thin shim that delegates to log_safe/3 with a nil scope.
  • Sigra.Audit.Query supports :organization_id, :effective_user_id, and :organization_scope filters. :organization_scope accepts {:only, org_id} or {:including_global, org_id} tagged tuples. The composite index (organization_id, inserted_at) is created on audit_events by the new alter migration to keep org-scoped queries off seq-scan plans at scale.
  • Sigra.Scope.build/3 library constructor for the host-app %Scope{} struct, used by login-time scope synthesis and by Sigra-aware workers. Also adds Sigra.Scope.from_opts/2 and Sigra.Scope.from_config/2 convenience constructors.
  • Sigra.Workers behaviour — single @callback perform(scope, args) contract for Oban workers requiring tenant context. Sigra.Workers.new/3 fails fast when required "organization_id" / "actor_id" arg keys are absent; Sigra.Workers.fetch_arg!/2 is a belt+suspenders helper for worker perform/1 implementations. Sigra.Workers.AccountDeletion is the reference implementation — it reconstructs the scope inside perform/1 and delegates to perform/2 with a real %Scope{}.
  • Sigra.Testing.assert_audit_logged/2 helper — a thin alias for assert_audit_event/2 with the REQ DX-02 naming convention. Signature is (map, keyword) to match assert_audit_event/2 exactly.
  • Custom Credo check Sigra.Credo.NoLogSafe2InLib that forbids arity-2 Sigra.Audit.log_safe calls in lib/sigra/** (with an exception for the shim definition itself and for test/**). Registered in .credo.exs via the requires: field so host apps pulling Sigra as a dep are not forced to take a Credo dependency.
  • New migration alter_audit_events_add_org_columns.exs adds organization_id :binary_id (nullable, FK with on_delete: :nilify_all so historical rows survive organization deletion) and effective_user_id :binary_id (nullable, v1.2 impersonation anchor) columns to audit_events, plus the composite index (organization_id, inserted_at). On Postgres, the migration uses @disable_ddl_transaction true + create index(..., concurrently: true) for zero-downtime deploy on production audit tables. On SQLite/MySQL, a plain change/0 migration emits the same shape non-concurrently.