Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
5f6e62e
docs: open v1.15 milestone — AUD-14 planning truth + phase 78
szTheory Apr 24, 2026
d6c7536
chore: archive v1.15 milestone files
szTheory Apr 24, 2026
117012b
chore: remove REQUIREMENTS.md for v1.15 milestone
szTheory Apr 24, 2026
ff1ba24
feat(audit): v1.16 transactional api.token_verify.failure (phase 79 A…
szTheory Apr 24, 2026
f849938
chore: archive v1.16 milestone files
szTheory Apr 24, 2026
7aeef4d
chore: remove REQUIREMENTS.md for v1.16 milestone
szTheory Apr 24, 2026
cca65d7
docs: start milestone v1.17 forced-change audit atomicity
szTheory Apr 24, 2026
17c3c71
docs: define milestone v1.17 requirements
szTheory Apr 24, 2026
d59ccee
docs: create milestone v1.17 roadmap (1 phase)
szTheory Apr 24, 2026
baf7211
docs(80): capture phase context and audit defaults
szTheory Apr 24, 2026
c0816bf
docs(state): record phase 80 context session
szTheory Apr 24, 2026
24ddfa4
docs(phase-80): research, validation strategy, and executable plans
szTheory Apr 24, 2026
ef5cf66
feat(80-01): add clear_password_change_requirement/3 and deprecate au…
szTheory Apr 24, 2026
e24b0c9
test(80-01): add Postgres atomicity tests for clear_password_change_r…
szTheory Apr 24, 2026
caedcb8
docs(phase-80): complete v1.17 AUD-17 — inventory, C-1, CHANGELOG, mi…
szTheory Apr 24, 2026
40cd660
chore: archive v1.17 milestone
szTheory Apr 24, 2026
3410c0f
docs: start milestone v1.18 JWT refresh audit atomicity
szTheory Apr 24, 2026
07d3c27
docs: define milestone v1.18 requirements
szTheory Apr 24, 2026
c06ddda
docs: create milestone v1.18 roadmap (1 phase)
szTheory Apr 24, 2026
b3aaee6
docs(81): capture phase context + audit defaults shift-left
szTheory Apr 24, 2026
5bcd50c
docs(state): record phase 81 context session
szTheory Apr 24, 2026
c6ffd6f
docs(81): research, validation strategy, and executable plans for JWT…
szTheory Apr 24, 2026
03c1cf0
feat(81-01): transactional Multi audit for JWT refresh and reuse
szTheory Apr 24, 2026
66eaff3
docs(81-01): plan summary for JWT Multi audit
szTheory Apr 24, 2026
3e38125
test(81-02): ExUnit coverage for JWT refresh Multi audit paths
szTheory Apr 24, 2026
b856d02
docs(81-03): AUD-18 planning truth and phase 81 verification
szTheory Apr 24, 2026
dc5d75e
docs(81-02): plan summary for JWT audit ExUnit coverage
szTheory Apr 24, 2026
7e442c0
docs(81-03): plan summary for AUD-18 planning alignment
szTheory Apr 24, 2026
7b6d575
docs(phase-81): complete milestone tracking and verification status
szTheory Apr 24, 2026
e195da7
docs(09-03): document status line for phase 81 AUD-18
szTheory Apr 24, 2026
e96ea37
docs(phase-81): add/update security threat verification
szTheory Apr 24, 2026
dc97a19
docs(phase-81): add/update validation strategy
szTheory Apr 24, 2026
bbdfbca
docs: start milestone v1.19 JWT persistence audit co-fate + MFA 022
szTheory Apr 24, 2026
0c84351
docs(82): capture JWT refresh persistence audit co-fate context
szTheory Apr 24, 2026
87b1660
docs(state): record phase 82 context session
szTheory Apr 24, 2026
c0c9c54
docs(state): fix resume path after phase 82 discuss
szTheory Apr 24, 2026
ecbb7a4
docs(phase-82): research, validation strategy, and executable plans (…
szTheory Apr 24, 2026
675ced1
docs(phase-82): drop spurious PLANNING COMPLETE markers from plans
szTheory Apr 24, 2026
1d7a693
feat(phase-82): JWT refresh persistence + audit co-fate (AUD-19)
szTheory Apr 24, 2026
6953ab3
docs(83): phase context, discuss log, D-AUD-12, GSD discuss prefs
szTheory Apr 24, 2026
173036f
docs(state): record phase 83 discuss session
szTheory Apr 24, 2026
bafb87c
docs(83): research, validation strategy, and executable plans for AUD…
szTheory Apr 24, 2026
da76385
feat(83-01): route confirm_enrollment invalid TOTP audit through comm…
szTheory Apr 24, 2026
53d616b
test(83-02): cover confirm_enrollment invalid TOTP audit matrix
szTheory Apr 24, 2026
8900995
docs(83-03): AUD-20 planning truth for confirm_enrollment 022
szTheory Apr 24, 2026
324ae69
docs(phase-83): complete phase execution — ROADMAP, STATE, REQUIREMEN…
szTheory Apr 24, 2026
ed09505
docs(84-01): reconcile live routing surfaces
szTheory Apr 25, 2026
e70581d
docs(84-01): add routing cleanup verification artifact
szTheory Apr 25, 2026
6367344
docs(84-01): complete routing honesty reconciliation plan
szTheory Apr 25, 2026
aea70a0
docs(phase-84): verify and finalize routing honesty reconciliation
szTheory Apr 25, 2026
24b075f
chore(release): prepare 0.2.5
szTheory Apr 25, 2026
3bb1134
docs: start milestone v1.20 GA Launch — SEED closure + public release
szTheory Apr 25, 2026
a781113
docs: define milestone v1.20 requirements (AUD-21 + GAUAT + LAUNCH, 2…
szTheory Apr 25, 2026
72dc12e
docs: create milestone v1.20 roadmap (6 phases, 85-90)
szTheory Apr 25, 2026
4869c5b
test(85-01): add impersonation atomicity coverage
szTheory Apr 25, 2026
af8af36
feat(85-01): co-fate impersonation session writes with audit rows
szTheory Apr 25, 2026
b1c2cd8
docs(85-02): close the audit atomicity planning trail
szTheory Apr 25, 2026
b42d02a
docs(85-02): add the phase 85 verification gate
szTheory Apr 25, 2026
aa8ecb1
docs(85): finalize the phase 85 execution artifacts
szTheory Apr 25, 2026
82213bc
docs(phase-84): backfill routing honesty planning trail
szTheory Apr 26, 2026
04c2ee7
docs(milestone): record v1.19 audit (tech_debt) and flip phase 82 to …
szTheory Apr 26, 2026
6832d98
chore(release): sync CHANGELOG ### Summary into GitHub release body
szTheory Apr 26, 2026
8b593e0
docs(86): capture phase 86 context — reshape GAUAT email QA to 0-huma…
szTheory Apr 26, 2026
89ff1f8
docs(state): record phase 86 context session
szTheory Apr 26, 2026
7f9fc42
docs(86): research phase domain
szTheory Apr 26, 2026
14c9e80
docs(phase-86): commit phase 86 plans + balanced profile config baseline
szTheory Apr 26, 2026
cff1bf5
test(86-01): add failing contrast ratio tests for Sigra.A11y.Contrast
szTheory Apr 26, 2026
84f5057
feat(86-01): add Sigra.A11y.Contrast and Example.EmailAssertions
szTheory Apr 26, 2026
68cf988
test(86-01): add failing CSS lint tests for Sigra.Email.CssLint
szTheory Apr 26, 2026
d75b75a
feat(86-01): add CssLint, caniemail allowlist, and bump CTA to #1d4ed8
szTheory Apr 26, 2026
6e860ec
feat(86-01): extend Phase 04 and 08 email tests to close G1-G9
szTheory Apr 26, 2026
beafb86
docs(86-01): complete plan 01 summary — ExUnit harness and accessibil…
szTheory Apr 26, 2026
974f2b7
chore: merge executor worktree (worktree-agent-a9af4ff8bcdc9f1d1) — 8…
szTheory Apr 26, 2026
9023b75
fix(86-01): align install fixtures with CTA color bump
szTheory Apr 26, 2026
0e8e59c
docs(phase-86): update tracking after wave 1 (86-01 complete)
szTheory Apr 26, 2026
26687d8
docs(phase-86): mark 86-01 complete in roadmap checklist
szTheory Apr 26, 2026
9518c80
feat(86-02): deterministic email snapshot and UAT report mix tasks
szTheory Apr 26, 2026
b52ab55
feat(86-02): add Playwright email visual lane — 36 committed baselines
szTheory Apr 26, 2026
d26273d
docs(86-02): complete plan 86-02 — email snapshot harness and visual …
szTheory Apr 26, 2026
4255bf8
chore: merge executor worktree (worktree-agent-a2b2df7f7452242f0) — 8…
szTheory Apr 26, 2026
6ce3cd3
docs(phase-86): update tracking after wave 2 (86-02 complete)
szTheory Apr 26, 2026
dbb16eb
feat(86-04): materialize Phase 08 lifecycle email evidence bundle
szTheory Apr 26, 2026
f4ae827
docs(86-04): complete Phase 08 lifecycle email evidence plan summary
szTheory Apr 26, 2026
afaa905
feat(86-03): wire email_visual_regression CI lane, INDEX, VERIFICATIO…
szTheory Apr 26, 2026
c700a97
feat(86-03): materialize Phase 04 evidence bundle with 8 SHA-suffixed…
szTheory Apr 26, 2026
d07ca2e
docs(86-03): complete plan 86-03 — CI wiring, Phase 04 evidence bundl…
szTheory Apr 26, 2026
6425f06
chore: merge executor worktree (worktree-agent-a1007adcd5c6cc09a) — 8…
szTheory Apr 26, 2026
d956bec
fix(86-03,86-04): drop duplicate build_byte_budget_csv added by paral…
szTheory Apr 26, 2026
19dfe41
chore: merge executor worktree (worktree-agent-af7f53afdd14e7315) — 8…
szTheory Apr 26, 2026
029d8e4
docs(phase-86): update tracking after wave 3 (86-03 + 86-04 complete)
szTheory Apr 26, 2026
eaf0fd8
docs(86): add code review report (4 critical, 6 warnings, 2 info)
szTheory Apr 26, 2026
63fc683
docs(86): verifier appends status frontmatter + goal-backward analysis
szTheory Apr 26, 2026
053e39d
fix(86): make uat.report --check exit 2 on missing baselines (CR-01, …
szTheory Apr 26, 2026
170003a
fix(86): generalize email-visual release upload to any v* tag (CR-03)
szTheory Apr 26, 2026
cc80fac
fix(86): regenerate Phase 08 evidence with full D-86-06 frontmatter (…
szTheory Apr 26, 2026
2fffcb0
docs(phase-86): complete phase execution
szTheory Apr 26, 2026
e539959
docs(phase-86): mark GAUAT-02 satisfied (Phase 08 28-baseline harness…
szTheory Apr 26, 2026
6aa25cc
docs(phase-86): evolve PROJECT.md after phase 86 completion
szTheory Apr 26, 2026
5578523
docs(87): capture phase context + reshape GAUAT-03..06 to 0 human UAT
szTheory Apr 26, 2026
769dc06
docs(state): record phase 87 context session
szTheory Apr 26, 2026
a31458c
docs(phase-87): add validation strategy
szTheory Apr 26, 2026
9d66f67
docs(87): create phase plans (87-01a wave-1, 87-01b wave-2 deps 01a, …
szTheory Apr 27, 2026
6f61ed7
feat(87-01a): scaffold oauth issuer test seam
szTheory Apr 28, 2026
34d91c5
feat(87-01a): complete oauth issuer green cycle
szTheory Apr 28, 2026
fd03ffb
docs(87-01a): complete oauth issuer plan
szTheory Apr 28, 2026
481de08
feat(87-01b): add oauth smoketest task
szTheory Apr 28, 2026
1ab2692
feat(87-01b): extend oauth install smoke
szTheory Apr 28, 2026
ecc5203
feat(87-01b): scaffold example app oauth surface
szTheory Apr 28, 2026
d871735
feat(87-01b): wire example oauth login and settings
szTheory Apr 28, 2026
367a164
ci(87-01b): add oauth playwright workflow lane
szTheory Apr 28, 2026
e45eb49
docs(88): capture phase context
szTheory Apr 28, 2026
8e0ec91
docs(state): record phase 88 context session
szTheory Apr 28, 2026
0f73fe7
docs(88): research phase domain
szTheory Apr 28, 2026
57d1687
docs(88-01): scaffold GAUAT-07 evidence bundle
szTheory Apr 28, 2026
23d164d
docs(88-02): scaffold GAUAT-08 evidence bundle
szTheory Apr 28, 2026
f67b9fd
docs(88-01): scaffold GAUAT-07 evidence bundle
szTheory Apr 28, 2026
d5034b1
docs(88-02): scaffold GAUAT-08 clean-machine bundle
szTheory Apr 28, 2026
bf05676
chore(88-01): run MFA Playwright lane and emit raw GAUAT-07 artifacts
szTheory Apr 28, 2026
9fc4f43
docs(88-01): generate GAUAT-07 manifest and README from emitted artif…
szTheory Apr 28, 2026
5d09edc
docs(88-01): validate final GAUAT-07 artifact set and posture
szTheory Apr 28, 2026
adc1d39
docs(88-01): complete MFA backup-code rotation evidence plan
szTheory Apr 28, 2026
5b99077
test(88-02): run generated-host install-smoke lane for GAUAT-08 artif…
szTheory Apr 28, 2026
8dde6db
docs(88-02): generate GAUAT-08 manifest and README
szTheory Apr 28, 2026
bb41548
docs(88-02): validate GAUAT-08 artifact set and posture
szTheory Apr 28, 2026
200f728
docs(88-02): complete GAUAT-08 generated-host plan
szTheory Apr 28, 2026
9431f28
docs(phase-88): update tracking after wave 1
szTheory Apr 28, 2026
de9af25
fix(88-03): update sigra.uat.report to verify snapshots on older shas
szTheory Apr 28, 2026
ae70fd7
docs(88-03): write consolidated GAUAT results and update SEED-001 status
szTheory Apr 28, 2026
e788325
docs(88-03): record Phase 88 verification posture
szTheory Apr 28, 2026
9c4c7a4
docs(88-03): complete File Launch-Truth Surfaces and Close-Out Phase …
szTheory Apr 28, 2026
8aefe62
docs(phase-88): evolve PROJECT.md after phase completion
szTheory Apr 28, 2026
d45aea2
chore(gauat): finalize Phase 87 and Phase 88 UAT evidence and Phase 8…
szTheory Apr 28, 2026
effdf42
trigger ci
szTheory Apr 28, 2026
f26212c
fix(ci): add CLOAK_KEY to email_visual_regression job
szTheory Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
515 changes: 513 additions & 2 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion .github/workflows/hex-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on:
type: string

permissions:
contents: read
contents: write

jobs:
publish:
Expand Down Expand Up @@ -66,6 +66,16 @@ jobs:
- name: Verify release version in mix.exs
run: grep -n "@version \"${{ inputs.release_version }}\"" mix.exs

- name: Sync changelog summary into GitHub release body
env:
GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
chmod +x scripts/release/sync_release_summary.sh
scripts/release/sync_release_summary.sh \
"${{ inputs.release_version }}" \
"${{ inputs.tag }}"

- name: Fetch library deps
run: mix deps.get

Expand Down
24 changes: 23 additions & 1 deletion .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,31 @@ jobs:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json

sync-release-summary:
name: Sync GitHub release summary
needs: release-please
if: ${{ needs.release-please.outputs.release_created == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ needs.release-please.outputs.tag_name }}

- name: Sync changelog summary into GitHub release body
env:
GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
chmod +x scripts/release/sync_release_summary.sh
scripts/release/sync_release_summary.sh \
"${{ needs.release-please.outputs.version }}" \
"${{ needs.release-please.outputs.tag_name }}"

publish-hex:
name: Publish to Hex.pm
needs: release-please
needs: [release-please, sync-release-summary]
if: ${{ needs.release-please.outputs.release_created == 'true' }}
runs-on: ubuntu-latest
permissions:
Expand Down
77 changes: 77 additions & 0 deletions .planning/AUDIT-ATOMICITY-DEFAULTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Sigra — audit atomicity defaults (GSD / planning)

**Purpose:** Capture **default engineering choices** for bounded **SEED-002**–style phases and `/gsd-discuss-phase` so planners rarely re-open settled tradeoffs. **Override** in phase CONTEXT when a requirement truly demands an exception (call that out explicitly).

**Status:** Established **2026-04-24** (Phase 80 research synthesis); extended **D-AUD-05..07** **2026-04-24** (Phase 81 JWT audit-only slice + discuss shift-left); **D-AUD-12** + discuss delegation prefs **2026-04-24** (Phase **83**).

## Defaults

### D-AUD-01 — Orchestration layer

- **`Sigra.Account`** (and analogous top-level orchestrators) **own** `Repo.transaction/1`, `Ecto.Multi`, and `Sigra.Audit.log_multi_safe/3` when audit must share fate with domain writes.
- **Domain modules** (`Sigra.Account.PasswordChange`, `EmailChange`, `Deletion`, …) stay **audit-agnostic**: no `Sigra.Audit` imports; they expose changesets, `Repo` operations, or small `Multi.run`-friendly steps.
- **Rationale:** Matches Phoenix **context** orchestration, avoids ActiveRecord/Django-signal-style hidden coupling, keeps **one transaction owner**, reduces nested-transaction footguns, improves generator DX (single extension seam).

### D-AUD-02 — Deprecation of superseded audit-only helpers

- When a standalone `log_safe/3` helper is replaced by an atomic **`Multi` + `log_multi_safe`** path: **`@deprecated`** with a **compile-time** warning for **at least one minor**, then **remove** in the following minor (pre-1.0). Document the **single supported** call sequence in CHANGELOG + upgrade guide.
- **Avoid:** immediate patch removal of public APIs; long-lived “smart no-op” shims without idempotency keys; default **runtime raise** for “double audit” in production (prefer CI / docs / generator alignment).

### D-AUD-03 — Options keyword shape

- Public **`Sigra.Account.*`** arities keep **`(repo, …, opts)`** with the **same physical `opts` keyword** hosts/generators already pass for `change_password`, email flows, etc.
- Implementations **`Keyword.take`** / NimbleOptions **composed schemas** so each operation uses the **audit context slice** consistently; operation-specific keys are validated per function without inventing a second public opts bag.

### D-AUD-04 — Testing split

- **MockRepo / unit:** API contracts, branches, error tuples, composition (no second Postgres copy of every branch).
- **Postgres + fault injection (`CHECK` / similar):** **one** happy path + **one** rollback proof per atomic story in `*_audit_atomicity_test.exs` (or equivalent), mirroring existing `change_password` patterns.

### D-AUD-05 — Audit-only `Multi` (no domain step)

- Helpers that **only** persist an audit row (e.g. **`api.jwt_refresh`**, **`api.jwt_refresh_reuse`**) still use **`Repo.transaction/1` + `Ecto.Multi` + `Sigra.Audit.log_multi_safe/3`** when `:audit_schema` is set — same **durability class** as token verify failure audits — with a **single private `commit_*`** owning the transaction shell and **thin `def` wrappers** for action-specific opts.
- **Do not** imply **shared fate** with unrelated domain tables unless a future phase explicitly joins them in the same `Multi` (**AUD-08**-class work stays out of bounded SEED-002 slices unless scoped).

### D-AUD-06 — Caller contract when audit insert fails (audit-only paths)

- Public functions that today return **`:ok`** and use **`log_safe`/`log_multi_safe`** for **side-channel audit** keep **`:ok`** on audit subsystem failure **when the audit row is not co-fated with a durable partner write**. This covers three legitimate sub-classes: **detection-only** (the audit row is the forensic record), **pre-domain** (the event fires before a persistence target exists), and **audit-only helpers**. Emit **`[:sigra, :audit, :log_safe_error]`** (or the same telemetry contract as `emit_log_safe_error`) so operators can alert; **raise** only on programmer-wiring errors. **`@doc`** must state **`:ok` does not guarantee** the audit row exists.

### D-AUD-07 — ExUnit layout for audit fault injection

- **Separate named tests** per action × fault story (no parametrized loops for fault paths). Reuse **only** small private helpers for `ALTER … CHECK` + `try/after` + telemetry attach; **unique** handler IDs per test; **`async: false`**; action-scoped SQL counts.

### D-AUD-08 — Persistence + audit co-fate (JWT refresh class; **AUD-19**)

- When requirements mandate **one commit** for **domain `user_tokens` effects** and **`api.jwt_refresh*`** audit rows (**:audit_schema** set):
- **Orchestrator** (**`Sigra.JWT.refresh/3`**, optionally delegated to an internal **`@moduledoc false`** module) owns **exactly one** **`Repo.transaction/1`** (or **`Repo.transact/2`** if the project adopts it here).
- **`Sigra.APIToken`** (or equivalent) must expose audit as **`Ecto.Multi` steps** composable into that transaction — **do not** call **`Repo.transaction`** inside helpers used from that **`Multi`** (no nested txn / savepoint surprise).
- **Public contract:** **`{:ok, tokens}`** iff the **full bundle** commits; **any** step failure → rollback and **`{:error, _}`** — **explicit exception** to **D-AUD-06** for this class only. **`@doc`** must contrast with **`audit_jwt_refresh/2`** / **`audit_jwt_refresh_reuse/2`** standalone semantics (**`:ok`** + telemetry on audit-only failure).
- **Rationale:** **D-AUD-06** exists because audit-only paths cannot roll back already-committed host work; co-fate paths **can** and **must** roll back persistence when audit fails — returning **`:ok`** with tokens would violate least surprise and audit integrity.

### D-AUD-09 — Security telemetry after commit (reuse / co-fate)

- **`Telemetry.event/3`** (or similar) that implies **persisted** security outcomes (**reuse detected**, family revoked) must run **after** the transaction **commits** (success branch), not interleaved between persistence and audit where a later audit failure would roll back DB state but leave misleading signals.

### D-AUD-10 — ExUnit split: audit-only vs persistence co-fate

- **Audit-only** stories (helpers that do not join **`user_tokens`** writes in the same txn) stay in **`api_token_audit_atomic_test.exs`** (or the established audit-atomicity module for that surface).
- **Persistence + audit co-fate** proofs live in a **dedicated** file (e.g. **`jwt_refresh_audit_cofate_test.exs`**) with **`@moduledoc`** cross-linking the audit-only module — preserves CI failure labels and avoids conflating **D-AUD-06** contracts with **D-AUD-08** contracts in one module.

### D-AUD-11 — Planning matrix updates when **T1** semantics strengthen

- Prefer **surgical cell edits** + **one dated supersession footnote** (phase id + what narrowed, e.g. **AUD-08** closed) across **44** / **45** / **09-VERIFICATION** / **09-03-SUMMARY** in lockstep; **`CHANGELOG` [Unreleased]** carries the user-visible behavior story; phase **`NN-VERIFICATION.md`** is the merge gate spine. Avoid wholesale matrix rewrites unless the row taxonomy is wrong.

### D-AUD-12 — MFA invalid pre-DB enrollment attempt (**AUD-04-022**)

- When **`:audit_schema`** is set, **`Sigra.MFA.confirm_enrollment/5`** wrong-TOTP path (**before** enrollment `Multi`) persists **`mfa.enroll.failure`** via **`Repo.transaction/1` + `Ecto.Multi` + `Sigra.Audit.log_multi_safe/3`**, using the **same audit-only shell** as **`commit_ad_hoc_mfa_audit/5`** (success → **`emit_telemetry_from_changes`**; failure → **`[:sigra, :audit, :log_safe_error]`** per existing rescue/changeset paths).
- **Public return:** **`{:error, :invalid_code}`** whenever the TOTP check fails — **independent** of audit insert outcome (**not** **D-AUD-08**; not a new failure atom for audit DB issues).
- **Explicit waiver** (retain **`log_safe`**) remains valid only if a phase **CONTEXT** records an intentional **exception to D-AUD-05** with updated **EX-44-02** rationale (**AUD-20-01** second branch).

## Discuss-phase preferences (this project)

- When the user **delegates** (“all”, “synthesize”, “don’t make me think”), default orchestrator behavior: **parallel research** (subagents or equivalent) on listed gray areas → **one coherent CONTEXT** aligned with **PROJECT.md** / **REQUIREMENTS.md** / these defaults.
- **Still require explicit user choices** for topics in **`.planning/config.json` → `workflow.discuss_always_surface_for_user`** (semver/public API, security model vs published OWASP stance, generator/host output contracts).

## When to still run discuss-phase

Use `/gsd-discuss-phase` when any of: new **external** contract (HTTP, host generator output), **semver exception**, **cross-cutting** audit API change (e.g. new `log_multi_safe` step names), **persistence + audit co-fate** scope not already covered by **D-AUD-08**, or **explicit** stakeholder preference. Otherwise planners may treat **D-AUD-01..11** as locked unless phase SPEC says otherwise.
106 changes: 101 additions & 5 deletions .planning/MILESTONES.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
- `SEED-001` — 8 human-only UAT items to run before GA public announcement (email visual × 4, OAuth real-credential × 4)
- `SEED-002` — Phase 9 `log_safe/3` hybrid to atomic `Ecto.Multi` conversion (C-1 caveat followup)

**Backlog** (999.x parking lot):
- `Phase 999.1` — Retroactive Nyquist validation pass for 6 draft + 1 missing VALIDATION.md files
- `Phase 999.2` — Dependabot major-version bumps (setup-node 4→6, upload-artifact 4→7, checkout 4→6) requiring per-bump CI verification
**Backlog** (999.x parking lot; archaeology only):
- `Phase 999.1` — Retroactive Nyquist validation pass for 6 draft + 1 missing VALIDATION.md files; shipped in v1.3 and now retained as a tombstone/pointer only
- `Phase 999.2` — Dependabot major-version bumps (setup-node 4→6, upload-artifact 4→7, checkout 4→6) requiring per-bump CI verification; historical parking-lot label only until promoted into a newly numbered phase

**Archive:**
- [v1.0 Roadmap](milestones/v1.0-ROADMAP.md) — full phase details
Expand Down Expand Up @@ -81,7 +81,7 @@
### Tech Debt Carried Forward

- **`gsd-tools audit-open --json` is deprecated** for Sigra maintainers; the **supported path** is [`MAINTAINING.md`](../MAINTAINING.md) section **Planning hygiene (without gsd-tools JSON)** plus optional [`scripts/maintainers/planning-audit-hygiene.sh`](../scripts/maintainers/planning-audit-hygiene.sh).
- `Phase 999.1` Nyquist backfill remains parked.
- `Phase 999.1` Nyquist backfill remains archaeology-only; Phase 84 owns the routing-honesty cleanup so active workflows stop pointing at the tombstone.
- `Phase 999.2` Dependabot major-version cleanup remains parked.

**Archive:**
Expand Down Expand Up @@ -114,7 +114,7 @@

### Tech Debt Carried Forward

- `SEED-001` human-only GA UAT items; `SEED-002` audit atomicity hybrid; backlog **999.1** / **999.2** unchanged from prior milestones.
- `SEED-001` human-only GA UAT items; `SEED-002` audit atomicity hybrid; backlog **999.1** / **999.2** remain historical parking-lot labels only.
- Residual subjective reviewer items called out in phase VERIFICATION/HUMAN-UAT docs where automation cannot fully substitute judgment.

**Archive:**
Expand Down Expand Up @@ -489,3 +489,99 @@
- [v1.14 Requirements](milestones/v1.14-REQUIREMENTS.md)

---

## v1.17 Forced password change audit atomicity (Shipped: 2026-04-24)

**Scope:** 1 phase (**80**), **`Sigra.Account.clear_password_change_requirement/3`** + planning truth (**AUD-17-01**..**AUD-17-04**).

**What shipped:** **`clear_password_change_requirement/3`** co-fates **`must_change_password: false`** with **`account.password_change`** (`metadata: %{forced: true}`) via **`Repo.transaction/1`** + **`Ecto.Multi`** + **`Sigra.Audit.log_multi_safe/3`** when `:audit_schema` is set; **`audit_forced_password_change/2`** **`@deprecated`**; **`test/sigra/account_audit_atomicity_test.exs`** forced-clear + CHECK rollback; **44** inventory + **09-VERIFICATION** C-1 **043** **T1** + **09-03-SUMMARY** + **`CHANGELOG` [Unreleased]**; **EX-44-05** closed.

### Key accomplishments

1. **AUD-17-01** — Forced-clear path matches atomic audit pattern used elsewhere on **Account**.
2. **AUD-17-02** — Standalone post-commit **`log_safe`** for that completion path retired (**deprecation**).
3. **AUD-17-03 / AUD-17-04** — Postgres-backed atomicity tests + planning truth aligned to **AUD-04-043**.

### Stats

- **Requirements:** 4/4 **Validated** in archived [`milestones/v1.17-REQUIREMENTS.md`](milestones/v1.17-REQUIREMENTS.md).
- **Timeline:** **2026-04-24**; **`/gsd-complete-milestone`** — live **`REQUIREMENTS.md`** removed.
- **Milestone audit:** not filed (optional); pre-close **`audit-open`**: all artifact types clear (2026-04-24).
- **`gsd-sdk query milestone.complete`:** failed (`version required for phases archive`); manual **`milestones/v1.17-*`** archival (same pattern as **v1.12**–**v1.16**).
- **Git (since `v1.16` tag):** 9 commits; **24** files (**1288** insertions / **50** deletions in `git diff --shortstat v1.16..HEAD` at close).

### Tech debt carried forward

- **SEED-002** — remaining **`log_safe/3`** clusters (**048–049**, OAuth phase **45**, etc.).
- **AUD-04-022** — **`log_safe`** invalid enrollment path unchanged (**EX-44-02**).

**Archive:**

- [v1.17 Roadmap](milestones/v1.17-ROADMAP.md)
- [v1.17 Requirements](milestones/v1.17-REQUIREMENTS.md)

---

## v1.16 API verify failure audit atomicity (Shipped: 2026-04-24)

**Scope:** 1 phase (**79**), **`Sigra.APIToken.verify/2`** failure audits + planning truth (**AUD-16-01**..**AUD-16-04**).

**What shipped:** **`api.token_verify.failure`** for invalid / revoked / expired branches uses **`Repo.transaction/1`** + **`Ecto.Multi`** + **`Sigra.Audit.log_multi_safe/3`** when `:audit_schema` is set; **`log_safe_error`** telemetry on audit insert failure while callers still receive **`{:error, reason}`**; **44** + **09** + **09-03-SUMMARY** + **`CHANGELOG` [Unreleased]**; **`test/sigra/api_token_audit_atomic_test.exs`** coverage + fault injection; **EX-44-01** verify slice retired (appendix row retained).

### Key accomplishments

1. **AUD-16-01 / AUD-16-02** — **`verify/2`** failure branches match atomic audit pattern without **D-27** success-path noise.
2. **AUD-16-03** — **AUD-04-044..046** **T1** in **44** inventory + **09-VERIFICATION** C-1 matrix.
3. **AUD-16-04** — Success path remains telemetry-only.

### Stats

- **Requirements:** 4/4 **Validated** in archived [`milestones/v1.16-REQUIREMENTS.md`](milestones/v1.16-REQUIREMENTS.md).
- **Timeline:** **2026-04-24**; **`/gsd-complete-milestone`** same day — live **`REQUIREMENTS.md`** removed.
- **Milestone audit:** not filed (optional); pre-close **`audit-open`**: all artifact types clear (2026-04-24).
- **`gsd-sdk query milestone.complete`:** not relied on; manual **`milestones/v1.16-*`** archival (same pattern as **v1.12**–**v1.15**).
- **Git (since `v1.15` tag):** 1 commit; **13** files (**487** insertions / **80** deletions in `git diff --shortstat 'v1.15^{}'..HEAD` at close).

### Tech debt carried forward

- **SEED-002** — remaining **`log_safe/3`** clusters (e.g. **043**, **048–049**, OAuth phase **45**).
- **AUD-04-022** — **`log_safe`** invalid enrollment path unchanged (**EX-44-02**).

**Archive:**

- [v1.16 Roadmap](milestones/v1.16-ROADMAP.md)
- [v1.16 Requirements](milestones/v1.16-REQUIREMENTS.md)

---

## v1.15 Account + API C-1 planning truth (Shipped: 2026-04-24)

**Scope:** 1 phase (**78**), library tests + planning truth (**AUD-14**..**AUD-14-05**).

**What shipped:** **`44-AUD-04-INVENTORY.md`** rows **035–042** and **047** aligned to **`Multi` + `log_multi_safe`** in **`lib/sigra/account.ex`** and **`lib/sigra/api_token.ex`**; **`09-VERIFICATION.md`** C-1 **T1**/**T2** honesty for those rows; **`09-03-SUMMARY.md`** bounded-batch note for **phase 78** / **AUD-14**; **`CHANGELOG.md` [Unreleased]** trace bullet; **`test/sigra/account_audit_atomicity_test.exs`** **`change_password`** success + CHECK-guard rollback.

### Key accomplishments

1. **AUD-14-01 / AUD-14-02** — Inventory rows match code for **Account** paths and **`APIToken.revoke/2`**, preserving **EX-44-05** and **EX-44-01** for **044–046** at **v1.15** close (**044–046** advanced in **v1.16** / **phase 79**).
2. **AUD-14-03** — **09-VERIFICATION** Phase **44** table carries defensible **T1**/**T2** labels for **035–042**, **043**, **044–046**, **047**, **048–049**.
3. **AUD-14-04 / AUD-14-05** — Summary + changelog trace; Postgres-backed atomicity tests for **`change_password`**.

### Stats

- **Requirements:** 5/5 **Validated** in archived [`milestones/v1.15-REQUIREMENTS.md`](milestones/v1.15-REQUIREMENTS.md).
- **Timeline:** **2026-04-24**; **`/gsd-complete-milestone`** same day — live **`REQUIREMENTS.md`** removed.
- **Milestone audit:** not filed (optional); pre-close **`audit-open`**: all artifact types clear (2026-04-24).
- **`gsd-sdk query milestone.complete`:** failed (`version required for phases archive`); archival manual (same pattern as **v1.12**–**v1.14**).
- **Git (since `v1.14` tag):** ~4 commits; **13** files (**282** insertions / **72** deletions in `git diff --shortstat v1.14..HEAD` at close).

### Tech debt carried forward

- **SEED-002** — remaining **`log_safe/3`** clusters per **44** / phase **45** inventory; backlog-triggered.
- **AUD-04-022** — **`log_safe`** invalid enrollment path unchanged (**EX-44-02**).

**Archive:**

- [v1.15 Roadmap](milestones/v1.15-ROADMAP.md)
- [v1.15 Requirements](milestones/v1.15-REQUIREMENTS.md)

---
Loading