Skip to content

Commit 012e67c

Browse files
cemililikclaude
andauthored
feat(identity): establish audited identity and membership storage (#38)
* test(identity): isolate pure startup diagnostics from fixture ownership The source Docker guard correctly treats direct fixture references as provider dependencies. Put pure finite classification in its own type so offline canary controls remain Docker-free without weakening the guard. ADR: 0063, 0064 * docs(roadmap): close provider classification correction reviews Record independent final-source verification of finite failure codes and the fixture-free diagnostic boundary, without claiming a repair. ADR: 0063 * fix(ci): retain closed Docker startup failure families Distinguish PostgreSQL SDK milestones and fixed daemon failure families without exporting provider text or changing startup and cleanup policy. Keep malformed and unknown responses on the existing generic diagnostic. Validate seven offline cases, seven corpus/Docker-sweep cases, all 43 launcher controls and sixty combined shard/aggregate controls. ADR: 0063 * fix(ci): contain malformed diagnostic Unicode Map raw unpaired UTF-16 parser failures to the existing fixed fallback. Four independently reproduced red controls now pass within the seven-case offline suite with warnings as errors. Record first-round review and the successful isolated Linux startup without claiming hosted reproduction. ADR: 0063 * docs(roadmap): record daemon diagnosis correction reviews Record both fresh second-round approvals, independent offline checks and source-bound evidence limits before the next complete hosted A run. ADR: 0063 * fix(testing): align fixture publishers and browser readiness Publish application PostgreSQL on the identity fixtures' loopback address. Share publication checks and require real configured/runtime inspection; retain all database roles and ownership cleanup. Poll only valid empty browser target lists within the original shared five-second discovery budget. Preserve immediate invalid-response refusal, closed diagnostics and owner/liveness checks. Validate nine C# cases, seven corpus/Docker-sweep cases, 1756 guarded frontend cases, 43 launcher controls and sixty shard/aggregate controls. Record actual Linux before-red/after-green publication and role proofs. ADR: 0003, 0063, 0064 * docs(roadmap): record publication correction first reviews Retain both scoped approvals, independently executed controls and the fourth frozen source's verified auxiliary evidence without promoting its failed integration result or claiming an observed daemon version. ADR: 0063 * docs(roadmap): complete publication correction reviews Record both fresh second-round approvals and independent browser, PostgreSQL privilege and cleanup checks before complete final-source A/B qualification. Keep source-bound evidence limits explicit. ADR: 0063 * fix(identity): clarify private setup and realm proof failures Keep unsafe private-file refusals actionable without exposing their contents, and make realm drift controls reject malformed profiles and exercise username uniqueness independently. Extend owned fixture TLS validity without changing trust. Record the existing issuance choice in a Proposed ADR pending separate maintainer approval. ADR: 0004, 0064 * docs(testing): preserve provider-only fixture boundaries Describe the actual dependencies of provider-only and combined API tests without implying every Keycloak proof configures application modules. Record the first independent correction reviews and their verified fix. ADR: 0004, 0064 * docs(roadmap): complete setup correction reviews Record both independent correction reviews and their validation limits, while keeping the dedicated issuance ADR Proposed until explicit approval. ADR: 0004, 0064 * fix(identity): prove coupled development token expiration Clarify the proposed issuance ADR's authority and provider consequences without treating the review as acceptance. Preserve historical package statements through dated adjacent corrections and name the actual reconciliation owners. Validate signed access and ID expiration together, including session clamping, and plant an independent ID-expiration payload defect that passes each fresh-window check. Retain the existing runtime and case population. ADR: 0004, 0064 * docs(roadmap): record first issuance correction review Record independent proof/security and ADR/provenance approval while retaining the second review and explicit ADR acceptance gates. ADR: 0004, 0064 * docs(roadmap): complete issuance correction reviews Record the fresh second-round proof and ADR reviews and their limits. Keep formal ADR acceptance and current-head hosted qualification separate. ADR: 0004, 0064 * docs(identity): accept development issuance decision Record explicit maintainer acceptance of revised ADR-0067 and complete its authority references in Security 11, the catalogue and local guides. Preserve original phase approval and Proposed-state reviews with dated adjacent disclosures. Keep issuance configuration, API acceptance, session ownership and source-bound qualification unchanged. The preceding ordinary CI failure remains separately under investigation. ADR: 0004, 0064, 0067 * docs(roadmap): record first issuance acceptance review Record the independent authority and scope reviews of the approved ADR-0067 carrier changes, with hosted failure investigation retained. ADR: 0067 * docs(roadmap): complete issuance acceptance reviews Record both completed independent carrier reviews and the source-bound CI triage. Preserve the failed lifecycle case without inferring its missing assertion diagnostic or waiving aggregate refusal. ADR: 0067 * fix(ci): retain closed causal restart failure locations Add the one observed lifecycle test source to the finite diagnostic projection while keeping paths, stacks and provider messages private. Plant the missing location in the existing control, observe it fail, then pass all 43 offline launcher controls after adding the mapping. This does not identify or fix the previous runtime assertion failure. Success witnesses, aggregate refusal and execution budgets stay intact. ADR: 0063 * docs(roadmap): record closed diagnostic correction review Record independent privacy and counterexample reviews of the one-source mapping, including all 43 controls and the removed-mapping negative. ADR: 0063 * docs(roadmap): complete closed diagnostic correction reviews Record the fresh second-round privacy and proof checks, including the missing-map negative, all offline controls and byte-preserved execution. Keep the preceding failed lifecycle receipt unwaived. ADR: 0063 * fix(tooling): preserve safe development lifecycle operations Keep teardown usable before realm convergence, retain closed setup diagnostics, and confine private configuration and migration credentials to their owners. Add actual-launcher controls without changing accepted realm capabilities. ADR: 0004, 0053, 0054, 0064, 0067 * test(identity): strengthen convergence and CI gate counterexamples Exercise retained-account and transport boundaries independently, keep the realm gates mandatory, and project only recognized safe failure kinds. Record source-bound checks without treating repeat passes as a root cause. Guard the documented migration build before executing no-build EF. ADR: 0004, 0063, 0064, 0067 * docs(decisions): propose development identity visibility preparation Keep the demonstrated hidden-identity refusal while examining a bounded metadata-first exception. Record the independent historical-bootstrap scope prerequisite explicitly; approval and dependent runtime remain pending. ADR: 0004, 0064, 0067, 0068 * docs(identity): bound historical realm upgrade qualification Separate profile visibility preparation from fully planned detachment of only three qualified stock console edges. Retain compatible scopes, existing grants and explicit approval before dependent runtime. Record actual feasibility, completed correction reviews and the remaining proof boundary honestly. ADR: 0004, 0064, 0067, 0068 * test(tooling): declare isolated child test environments Supply the test mode required by Next's process environment types without inheriting application credentials into child fixtures. Full typecheck, lint and all 197 affected cases pass. Record the proposed warm-realm correction steps and reflow the first document review's long lines. ADR: 0064, 0067 * docs(roadmap): record final correction and proposal reviews Record both fresh review rounds for the isolated fixture typing fix and the final Proposed warm-realm correction. Preserve the approval hold and separate author checks, private feasibility and hosted qualification. ADR: 0064, 0067 * fix(identity): resolve assigned console scopes by bound ID Admin assignment endpoints return only ID and name. Read and bind the complete representation before checking protocol, while preserving all existing compatible allowance and mapper checks. Add independent graph, identity, readback and transport-cap counterexamples; 256 guarded Node cases and six workflow-gate controls pass. ADR: 0004, 0064 * docs(decisions): qualify preparation authority and console evidence Require all identity-independent refusals before preparation, preserve readable prior definitions, and specify preparation diagnostics, write accounting and exact assignment-only DELETE authority. Retain shipped catalogue status with pending extensions. Correct raw provider anchors and distinguish actual console token effects from unproved POST/runtime behavior. Record conditional maintainer acceptance authority and the separate source-bound CI failure without guessing its cause. ADR: 0004, 0064, 0067 * fix(ci): retain closed native settlement failure locations Add the existing settlement test file to the finite diagnostic source projection. Verify exact and near-match handling without exposing raw paths or errors. All 43 offline controls pass. This does not infer the lost CI assertion or alter runtime, deadlines or success witnesses. ADR: 0063 * docs(roadmap): record revised decision inspection and failure limits Record the first fresh review of the compatible-read correction and conditional decision revision. Reflow its one minor finding and clarify what the failed launcher envelope can and cannot establish. ADR: 0063, 0064, 0067 * docs(decisions): accept bounded warm-realm qualification Accept ADR-0068 under the maintainer's conditional authority after both fresh revision reviews. Disclose the two bounded phase replacements and historical remedy follow-up; reconcile authority headers, architecture, guidance and index. Preserve shipped catalogue status/counts while the expanded obligations remain explicitly pending. Acceptance authorizes the three-step implementation, without claiming automatic-path proof. ADR: 0004, 0064, 0067, 0068 * feat(identity): qualify stock console assignment normalization Bind complete historical scope, mapper and role representations before removing only three approved account-console assignments. Preserve the compatible path, keep DELETE authority opaque and requalify explicit partial-progress reruns without replay or a durable marker. Commit a credential-redacted historical fixture, fixed canonical baseline and independent real-provider reproduction. The ordinary production path performs sixteen writes, then zero after test-owned metadata setup. Automatic preparation and the remaining token/self-service proofs retain the next steps' gates. ADR: 0004, 0064, 0067, 0068 * test(identity): cover every interrupted console assignment Persist uncertain-response and cancellation controls at all three DELETE positions. Verify the exact durable prefix, no replay, last-edge handoff to compatible preservation and explicit zero-write convergence. Record the first independent Step 1 review and its verified proof gap. Runtime behavior and mutation authority remain unchanged. ADR: 0068 * docs(roadmap): close the first warm-realm correction step Record both fresh review rounds, the persisted interruption correction and its independently verified convergence. Keep preparation, complete automatic-path evidence and final hosted qualification explicitly pending. Clarify that the Node census guards files and counts, not test semantics. ADR: 0068 * feat(identity): prepare warm-realm identities before fresh planning Qualify independent prerequisites before the bounded metadata exception, then discard every provisional projection before admitting ordinary writes. Keep uncertain dispatched progress visible through failures and cleanup. Actual historical provider controls prove convergence and explicit recovery. ADR: 0068 * fix(identity): qualify visible facts before warm-realm preparation Keep already observable identity and profile refusals ahead of metadata preparation. Preserve mapper refusal codes through stock qualification and retain dispatched metadata notices through the seed and demo entry owners. Actual provider regressions and clean counterpart controls bind these fixes. ADR: 0068 * docs(roadmap): record verified warm-preparation corrections Bind the closed first-round findings and caller/mapper regressions to their committed fixes and independent checks without claiming final qualification. ADR: 0068 * docs(roadmap): close reviewed warm-realm preparation step Record both fresh review rounds, verified correction coverage and remaining complete-path qualification without treating partial evidence as release proof. ADR: 0068 * test(identity): prove historical realm credentials and API Qualify the approved warm upgrade with usable MFA, signed application reads and stored account changes. Retain source-bound entry evidence and measured case assignments while keeping incomplete public qualification explicit. ADR: 0004, 0064, 0067, 0068 * docs(roadmap): record warm qualification and Step 3 reviews Retain both historical demo outcomes and their distinct evidence limits, then record the two fresh independent review rounds before final hosted assignment qualification. No earlier failure is relabelled as success. ADR: 0063, 0068 * test(ci): bound ingress lookup and retain settlement facts Remove an unrelated unbounded informational lookup from the native ingress fixture while preserving real request settlement and all security checks. Exercise case-bound diagnostics through the pinned test adapter and retain failed qualification receipts without guessing their missing root cause. ADR: 0047, 0055, 0063, 0068 * docs(roadmap): record first CI correction review Retain independent source and actual adapter checks without treating historical green assignments as a waiver for the failed A3 receipt. ADR: 0063, 0068 * docs(roadmap): close independent CI correction reviews Record the fresh second review and clarify the informational fetch bound without claiming a universal response-body deadline or waiving A3. ADR: 0063, 0068 * test(jobs): attribute settlement loss to its execution Preserve the original held Outcome invariant without assigning later Finalize observations to it. Prove the distinction with a real locked Finalize commit, conservative renewal refusal and actual cleanup, and retain closed identity attribution across all failure boundaries. ADR: 0047, 0059 * test(jobs): join issued settlement flights before cleanup Await actual flights before positive ownership joins so an early assertion cannot retain unfinished work permanently. Preserve the first failure and qualify the cleanup path with a real held-COMMIT negative and bounded, case-bound cleanup observations. ADR: 0047, 0059 * docs(roadmap): close independent attribution reviews Record the verified cleanup correction, both fresh review rounds and the exact whitespace-only source binding. Keep current-head hosted qualification in the PR and preserve every earlier failed receipt. ADR: 0047, 0059, 0068 * test(jobs): preserve recurrence failure and cleanup observations Keep the first actual recurrence test fault through independent cleanup and retain only case-bound finite diagnostics. Real adapter controls preserve the original assertion even when cleanup also fails; production behavior and all existing waits remain unchanged. ADR: 0047, 0059, 0063, 0068 * docs(roadmap): record recurrence diagnostic first reviews Record independent ownership and export checks against actual adapter failure, cleanup, source and archive evidence while preserving the failed hosted run. ADR: 0047, 0059, 0063, 0068 * docs(roadmap): close recurrence diagnostic review rounds Bind both fresh review rounds to actual failure preservation, positive cleanup and complete retained evidence, with hosted qualification and merge separate. ADR: 0047, 0059, 0063, 0068 * test(jobs): isolate settlement proofs from pre-ack renewal races Schedule the real renewal pacing callbacks around Outcome settlement, retain actual timer cleanup, and prove the unrelated Prepare-lock refusal against PostgreSQL. Preserve exact cases, deadlines and production policy. Retain the failed CI and partial-rerun evidence with bounded diagnostics. ADR: 0047, 0059, 0060, 0063 * docs(roadmap): record first settlement scheduling reviews ADR: 0047, 0063 * test(jobs): arm settlement deadlines before publication holds Create the actual normal deadline timer before the fixture publication hold. Preserve real durations, callback/factory ownership and exact case identities. Retain fresh clean and exclusion-control evidence, and explicitly refuse the ordering control's unconfirmed internal cleanup witness. ADR: 0047, 0059, 0060, 0063 * docs(roadmap): record independent deadline fix verification ADR: 0047, 0063 * fix(ci): audit links against immutable event commits Compare the PR event base snapshot directly with the checked-out tree instead of fetching a later shallow base branch. Exercise the actual workflow owner against real squash graphs, missing bases and broken links. Preserve strict aggregate identity refusal and record the merged implementation accurately. ADR: 0007, 0041, 0063 * docs(roadmap): record link audit correction review Record both independent first-round reviews and the actual workflow and corpus checks. Complete hosted A/B qualification remains pending on an open follow-up PR; closed-PR identity evidence is not waived. ADR: 0007, 0041, 0063 * docs(roadmap): close link audit correction reviews Record the different second review pair and independently reproduced old-owner failures. Keep complete final-source hosted qualification pending on the open follow-up PR. ADR: 0007, 0041, 0063 * fix(ci): classify Markdown audit regression tooling Register the new Python proof script in the explicit non-runtime census. The real frontend guard caught the omission; preserve rejection of unknown sources and runtime exemptions. All 1840 frontend cases pass. ADR: 0018, 0056, 0063 * docs(roadmap): record tooling census correction review Record the first fresh review pair and retained frontend evidence. Complete hosted qualification remains pending on the corrected source. ADR: 0007, 0056, 0063 * docs(roadmap): close tooling census correction reviews Record the different second review pair and retain the failed initial attempt's evidence limits. Fresh same-source A/B qualification follows. ADR: 0007, 0056, 0063 * test(jobs): preserve native wait failure attribution Retain the first body or explicit runtime-join exception instead of masking it in finally. Export only case-bound closed boundary and owner task observations so startup and cleanup cancellations can be separated. Validate clean and three planted fault paths with actual native work, including the old test's masking counterexample. The earlier hosted cancellation remains unexplained; no timeout or runtime policy changes. ADR: 0007, 0047, 0060, 0063 * docs(roadmap): record native wait diagnostic review Preserve original proof receipts and disclose the corrected container count against retained raw cleanup evidence. Record source binding and the first independent review round without asserting a hosted cause. ADR: 0007, 0047, 0060, 0063 * docs(roadmap): close native wait diagnostic reviews Record the second fresh independent pair and exact retained evidence verification. Keep hosted cancellation and helper scheduling causes unproven until source-bound qualification supplies actual evidence. ADR: 0007, 0047, 0060, 0063 * test(jobs): wait for actual cleanup before fixture hints The native execution fixtures may consume their sole extra hint while an earlier empty recovery still owns private cleanup. Wait for actual native work and local identity release before issuing that same hint. Reproduce premature consumption with real SQL/native workers and an owned System timer cleanup barrier. Preserve all existing budgets, production policy and original case identities; add one regression fact. ADR: 0047, 0059, 0060, 0063 * test(jobs): retain cancellation before fixture hint emission Restore the original final cancellation check after readiness waits. Record the first independent review round and fresh exact-source clean and planted-failure evidence without claiming atomic cancellation or a cause for the earlier hosted failure. ADR: 0007, 0047, 0059, 0060, 0063 * docs(roadmap): close fixture handoff correction reviews Record the second fresh pair and exact proof/source verification. Preserve the unknown hosted cause and require complete final-source A/B qualification before the follow-up draft is ready for review. ADR: 0007, 0047, 0059, 0060, 0063 * fix(ci): bound browser dependency mirror waits Let the hosted browser installer leave stalled APT mirrors while retaining its complete dependency set, verification and existing time budgets. Read back effective root settings and remove only the exclusive fragment. Exercise the actual workflow shell across success and failure paths, and retain the failed prior attempts as unqualified observations. ADR: 0007, 0056, 0063 * test(ci): exercise partial browser setup writes Make the write-failure control leave a genuinely incomplete fragment before refusing, then verify that the actual workflow shell removes it. Record the first independent review pair and the failed A receipt. ADR: 0007, 0056, 0063 * docs(ci): record browser acquisition review closeout Record the second fresh independent review pair and its extracted-shell checks. Keep the prior failed attempts separate from the complete hosted A/B qualification still required on the resulting source. ADR: 0007, 0056, 0063 * fix(ci): reserve bounded public demo completion time The complete B assignment reaches the last public audit before its sixteen-minute outer allowance cancels it. Allocate seventeen minutes inside the same twenty-minute job, twelve-minute proof and thirty-second native cleanup limits. Bound the remaining cleanup/receipt steps and restore NuGet without a save post-hook to retain a three-minute tail. Exercise actual deadline and tail shells, preserving forced failures. Keep failed partial evidence distinct from complete qualification. ADR: 0007, 0056, 0063 * docs(roadmap): record first outer-budget correction reviews Record two independent approvals, their actual-shell controls and historical evidence checks without claiming new hosted qualification. ADR: 0056, 0063 * docs(roadmap): close outer-budget correction reviews Record fresh second-round approvals and independent historical evidence revalidation. Keep complete final-source hosted A/B as a separate gate. ADR: 0056, 0063 * fix(ci): join maintenance in OpenAPI control repositories The hosted snapshot control fails strict temporary cleanup while its Git object directory changes. Keep maintenance in the foreground only in the synthetic repository so the waited commit also waits its actual work. Prove nested commit-graph completion with a real Git trace under a private configuration that otherwise requests background maintenance. Retain strict cleanup and all OpenAPI comparison and admission rules. The observed mechanism is not a captured trace of the hosted failure. ADR: 0007, 0052 * test(ci): require successful owned Git maintenance proof Reject a planted graph write failure even when a prior graph exists. Correct pinned source anchors using physical raw-file lines and record both first-round reviews and their verified fixes. ADR: 0007, 0052 * docs(roadmap): close Git maintenance fixture reviews Record two fresh second-round approvals and the independently repeated clean, detached and planted-failure controls with their runtime limits. ADR: 0007, 0052 * fix(ci): retain closed producer gate refusal diagnostics Both aggregate jobs reject a gate but discard which source-owned producer and step failed validation. Emit finite state words before the unchanged refusal so later API success cannot obscure the original observation. Never export arbitrary provider values or retry inconsistent evidence. Keep the unsuccessful historical attempt separate from new qualification. ADR: 0007, 0063 * docs(roadmap): record gate diagnostic review evidence Retain independent closed-output checks and historical evidence limits. Separate complete public component observations from failed whole-run qualification and final-source A/B still required. ADR: 0007, 0056, 0063 * docs(roadmap): close producer gate diagnostic reviews Record fresh differential and mutant controls, independent component archive checks and the unchanged final-source whole-workflow gate. ADR: 0007, 0063 * fix(ci): own Outbox startup and attribute producer refusal Disable the unowned telemetry exporter in the Outbox host fixture and join actual startup before disposal even when its assertion wait expires. Retain only finite startup facts from the real test adapter output. Report closed producer states before the unchanged aggregate refusal. Keep unknown hosted causes distinct from local counterfactual evidence. ADR: 0007, 0044, 0046, 0063 * docs(roadmap): record Outbox correction first review Record independent code, protocol and retained-evidence validation while preserving unknown hosted causes and complete final-source A/B gates. ADR: 0063 * docs(roadmap): record independent Outbox correction approval Record the second fresh review pair and narrow container identity prose to the exact retained evidence. Keep full final-source A/B pending. ADR: 0063 * fix(ci): bound pending producer metadata acquisition Read fresh complete attempt snapshots under one short acquisition budget before applying the unchanged successful-producer witness. Refuse terminal, malformed and identity-invalid evidence immediately, including when an earlier owner is pending. Never combine snapshots. Keep the five-minute aggregate ceiling and upload reserve unchanged. ADR: 0063 * fix(ci): validate creation times before metadata settlement Reject malformed or reversed creation timestamps before a pending owner can cause another read. Record independent repros and corrected first-round review validation. ADR: 0063 * docs(roadmap): record independent metadata acquisition reviews Record fresh second-round deadline and malformed-evidence controls, with retained failed-attempt and pending hosted qualification limits. ADR: 0063 * docs(decisions): accept ADR-0069 phase documents and delivery logs Phase 02b's phase document reached 18,884 lines, 92% of them dated packet records, and Phase 02d followed the same shape; status was narrated in five places and no check covered link fragments. The maintainer accepts keeping the plan and the record in separate files, status in one place, and two CI guards that hold both, after one review round whose findings this text resolves. ADR: 0069 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(roadmap): split Phase 02b and 02d records into delivery logs Moves every dated packet record out of the two phase documents into sibling append-only delivery logs, grouped by packet in source order, with the superseded Status blocks kept verbatim in each log's archive. Each heading's anchor was recomputed in its new file and checked against its original one, duplicates included, and every original line survives the split; only heading levels and link targets around the text change. 606 inbound links are retargeted with their text unchanged, so the Accepted ADRs touched owe no amendment. Phase 04's one dated plan heading keeps its date in its acceptance line and its six links follow it. ADR: 0069 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: hold packet status once and record the delivery log rule Packet state was narrated in the phase Status block, the packet table, the Completion Criteria preamble, the roadmap index, CLAUDE.md and the repository README, and every step edited all of them. Each now points at the phase document, whose bounded Status block owns packet state; CLAUDE.md drops from 856 to 405 lines. The rule itself lands where readers look for it: Roadmap § Phase Structure and § Decision Timing, Documentation Standards, the glossary, CLAUDE.md and the two skills that write roadmap records. ADR-0069's dated amendment names the README as a sixth carrier and fixes how its budgets are counted. ADR: 0069 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(meta): guard link fragments and roadmap structure The link audit strips fragments and reads only changed files, so a moved heading broke links silently, and nothing stopped a phase document from growing records again. The meta job now resolves every fragment link in the tree against GitHub's heading slugs and holds phase documents, delivery logs, the roadmap index, CLAUDE.md and the README to ADR-0069; `make lint` runs both through `lint-docs`. Each guard ships planted-violation controls, the source census classifies the four new tooling files, and the link audit now skips code spans as it already skipped fenced samples. ADR: 0069 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(decisions): amend ADR-0069 with generated delivery log indexes A delivery log is too large to read whole, so an agent needing one entry has no map of the rest. The amendment opens each log with an index generated from its headings and checked in CI, listing lengths rather than line numbers and no inferred record kinds, and states that the index is navigation, not a record. ADR: 0069 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(roadmap): open each delivery log with a generated index The Phase 02b log is about 305,000 tokens, so an agent needing one entry had no map of the rest. Each log now opens with an index of its packet sections, entries and dated sub-entries with their lengths, generated by scripts/delivery-log-index.py (`make docs-index`) and refused when stale by the meta job and `make lint-docs`. The fragment audit covers every row's anchor; the logs, roadmap index, Documentation Standards, glossary, CLAUDE.md and the two record-writing skills say to read the index, not the log. ADR: 0069 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ci): install Chromium without the APT mirror The public demo's five-minute browser step failed four of today's twelve attempts while Playwright's --with-deps installer downloaded fonts from the runner's slow APT mirror; the 15-second acquire timeouts cannot end a slow transfer that is still moving. The hosted image already carries every Chromium library, and no public-demo check depends on system fonts, so the step installs only the pinned Chromium build and drops the temporary APT fragment with it. The workflow test executes the actual step against stubs and fails on any sudo or APT call; against the previous workflow it fails. The delivery log records run 39805658821, the still-unexplained native fixture hang, and the maintainer's single-assignment qualification decision for PR #35. ADR: 0056, 0063 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(decisions): propose owned tenant BFF sessions Define session custody, lifecycle, admission and evidence before the first BFF credential owner is implemented. Keep G13 open until the maintainer accepts the proposal and five-step delivery package. ADR: 0004, 0053, 0054, 0064, 0067, 0069 * docs(decisions): resolve BFF session proposal review findings Separate local logout guarantees from provider navigation, preserve logout at full sign-in capacity and require the actual warm-realm BFF chain. Record the first independent proposal review and its verified corrections. ADR: 0004, 0053, 0054, 0064, 0067, 0069 * docs(roadmap): finish the BFF decision pass and prior closeout Record the second independent proposal review, make optional BFF activation explicit and distinguish public requests from OIDC transactions. Verify PR 35's merged source and successful CI without inferring historical causes. Keep the new session ADR Proposed until maintainer approval. ADR: 0004, 0053, 0054, 0064, 0067, 0069 * docs(decisions): revise BFF ownership after maintainer review Compare maintained RP alternatives and select openid-client without a credential-bearing cookie or competing session framework. Define provider event persistence, source and subject admission, effective expiry and browser transaction fencing before requesting renewed approval. ADR: 0004, 0035, 0036, 0053, 0054, 0064, 0067, 0069 * docs(decisions): retain logout owners in subject admission Keep logout-return entries in the subject budget until return expiry or consumption and actual work settlement. Distinguish AccountSite actor and scope evidence from independently validated OIDC subject continuity. Record the first revised proposal review and its verified corrections. ADR: 0035, 0053, 0054, 0064, 0067, 0069 * docs(roadmap): complete revised BFF proposal review Record the second fresh independent review pair and final source clarifications. Preserve API-owned resolved organization scope separately from optional protected claims and retain approval-pending status. ADR: 0035, 0053, 0054, 0064, 0067, 0069 * docs(decisions): accept native tenant BFF session ownership Record maintainer approval of ADR-0070 and its five-step delivery plan before dependent implementation. Reconcile custody, CSRF, event evidence and deployment rules, append bounded prior-decision disclosures, and register the four proof obligations without claiming runtime delivery. ADR: 0035, 0053, 0054, 0064, 0067, 0069, 0070 * feat(identity): add inactive BFF RP and provider event policy Keep credentials behind a server-only pinned RP with fixed-purpose bounded transport and signature-enabled grants. Qualify development event storage before metadata preparation, preserve existing event policy and verify actual fresh/warm persistence without activating browser sign-in. Targeted checks pass; the delivery record explicitly tracks the remaining historical count reruns and added real-body cancellation proof before Step 1 closure. Production route and configuration admission stay closed. ADR: 0004, 0035, 0053, 0054, 0064, 0067, 0068, 0070 * fix(identity): qualify logout and event response boundaries Keep the supported loopback logout path inside the closed provider boundary and refuse known event-expanded realm overflows before any preparation write. ADR: 0068, 0070 * fix(identity): preserve provider defaults and closed network reasons Retain every pinned default-saved event and distinguish library-wrapped network uncertainty from malformed responses. Close both Step 1 review rounds with independent omission controls and real provider evidence. ADR: 0068, 0070 * feat(identity): own bounded native BFF session lifecycles Keep credentials and actual operation ownership in one native process across browser transactions, refresh, replacement and logout. Exercise capacity and revocation races before wiring any production route or activation. ADR: 0035, 0053, 0054, 0070 * fix(identity): preserve current callback visitor attribution Use the callback's verified visitor for AccountSite without moving the original pending-source credit or consuming state on a malformed source. ADR: 0064, 0070 * docs(roadmap): close native BFF ownership reviews Record both fresh review approvals and the tested source before starting the closed HTTP and SDK slice; retain later activation and runtime proof owners. ADR: 0069, 0070 * feat(web): implement closed BFF HTTP and request projections Keep production activation closed while adding native response-owned auth protocol, bounded input, host cookies, CSRF and safe read-only RSC sessions. Use the exact authenticated SDK for the native AccountSite witness. Qualify the inactive path through actual native HTTPS and production Next middleware/RSC bundles. Real provider/API and browser proof remains Step 5. ADR: 0053, 0054, 0070 * fix(web): retain native RSC activity through Next middleware Capture only the closed activity scalar before Next strips Flight headers. Keep response-owned refresh and idle mutation separate from RSC reads. Exercise actual production Next with expired access and passive controls; a copied dropped-handoff mutant must fail the same RSC assertions. ADR: 0053, 0054, 0070 * docs(roadmap): close P02b-7 HTTP protocol review rounds Record both fresh second-round approvals and retain the distinction between native Next proof and the remaining provider/browser gates. ADR: 0069, 0070 * feat(web): activate optional tenant BFF and localized session UI Activate native session and request owners atomically after private configuration agreement. Resolve live host/locale admission before session actions, and guard the read-only Studio/Portal shells. Add complete sign-in/recovery copy, effective-expiry warning, real extension and local-first logout UI. Keep browser transport closed to one same-origin action and veil protected history before restoration. Preserve actual public admission, browser fallback and HMR evidence without bypassing the new shell guard. Validate 2,081 guarded frontend cases, production Next builds, the PostgreSQL admission lifecycle and five corpus controls. Real provider, browser history and final-source hosted proof remain Step 5. ADR: 0053, 0054, 0069, 0070 I18n: auth * fix(web): close development auth traces and add skip links Suppress Next request URL tracing before the native process imports Next; retain an actual development canary and a guard-removal counter-control. Add localized keyboard skip links to auth documents and protected shells. Bound frontend file concurrency while retaining complete guarded discovery. ADR: 0053, 0054, 0069, 0070 * fix(web): preserve focus through session recovery transitions Announce unchanged or maximum extension and recover focus after focused controls expire, while preserving external focus and passive warnings. Record both independent Step 4 review rounds and begin lifecycle proof. ADR: 0069, 0070 * test(identity): prove native BFF lifecycle and browser isolation Exercise the reconciled warm provider through the native BFF and real application-role API, with separate actual HTTPS cookie/history proof and an enabled no-network startup control. Keep private IPC and joined fixture cleanup outside retained artifacts. Correct the sign-in document's referrer policy so browser form Origin survives exact CSRF admission. Require fresh native/SDK fixture builds and retain complete local discovery and advisory timing evidence. Hosted qualification, demo and both review rounds remain open. ADR: 0070, 0064, 0063, 0053, 0054 * fix(identity): join BFF proof owners before reporting success Close the private lifetime pipe before joining fixture processes and independently require empty owned temporary roots. Reject nonzero native shutdown and forced process-group cleanup instead of publishing success. Own the browser synchronously before CDP connection to fence late launch. Prove early parent disposal and the exact shutdown counter alongside the real warm-provider/API chain and separate HTTPS browser history control. Record stopped-provider public-demo evidence and complete local controls. ADR: 0056, 0063, 0070 * fix(identity): observe parent EOF throughout BFF acquisition Keep bounded private input flowing while native compilation and build are awaited, so an early parent close reaches the fixture owner before readiness. Prove the held-build abort joins and removes its private tree. Require zero native exit and unforced settlement in every protocol and UI proof. Add the exact shutdown counter and retain the real six-case BFF and 2090-case frontend results with both review confirmations. ADR: 0056, 0063, 0069, 0070 * test(web): expect closed shells when tenant sign-in is disabled The standalone ingress proof still expected pre-BFF placeholders after the accepted activation changed disabled protected shells to 503. Require that unavailable response without cookies, forms or protected content while preserving exact bootstrap, method and TLS controls. Record the hosted failure honestly and retain the fresh production proof, 19 cleanup controls and both focused source confirmations. ADR: 0053, 0056, 0070 * test(ci): isolate held-constructor cancellation and copied ingress Copy the new pure ingress dependency into the existing local launcher fixture. Establish real constructor entry before the held-constructor test requests stop or expires its SQL lease, while retaining real timers and shared cleanup bounds. Keep failure-only closed handoff observations for future source diagnosis. Record the complete failed first A attempt, focused independent reviews and local worker/parser/aggregate evidence without claiming its cause reproduced. Refresh overview pointers for optional native tenant sign-in. ADR: 0047, 0059, 0063, 0070 * test(jobs): preserve the handoff control before constructor entry Compose the existing real renewal pacing and held-disposal observers so safe preconstructor renewal refusal cannot replace the one-hint cleanup subject. Keep actual clocks, original assertions and the shared cleanup budget. Record both completed failed A runs and six focused real-worker passes. Regenerate the delivery index after the final receipt edit. ADR: 0047, 0059, 0063, 0069, 0070 * test(web): distinguish closed browser readiness failures Read the owned debugging-port file once and retain only branded finite readiness observations. Preserve the existing deadline and polling, and keep observed child death separate without exporting private errors. Cover actual files, incomplete publication, private exceptions, deadline boundaries and forged diagnostics. Record the failed hosted attempt and successful real-browser/frontend/parser evidence without inferring its cause. ADR: 0032, 0063, 0069, 0070 * test(jobs): retain the first source-contention failure Preserve the first body or explicit cleanup exception while attempting all owned cleanup. Retain only exact-case, closed memory observations and source locations, with malformed/private diagnostic controls. Keep every runtime policy, operation budget and successful assertion unchanged. Record the complete A and failed B separately; local passes do not establish the historical cancellation cause or complete same-source qualification. ADR: 0047, 0059, 0060, 0063, 0069, 0070 * test(jobs): accept lawful finalizer retries in causal restart Reproduce the exact-one assertion overconstraint with a genuine-handler post-write conflict and fresh actual admission. Keep one logical provider effect, immutable outcome, ledger accountability and atomic business/audit proofs while permitting the runtime's existing bounded finalizer retries and repeat recovery reads. Retain only closed failure facts and preserve the first explicit failure. Record actual counter/local receipts and update the advisory selector cost; complete source-bound hosted A/B qualification remains pending. ADR: 0047, 0061, 0063, 0069, 0070 * test(web): retain closed browser failure and cleanup evidence Preserve the first browser fixture failure across actual cleanup and retain finite case-bound journey, stage and source observations in CI. The failed hosted interleaving remains unproven; no success assertion, operation budget, retry policy or execution topology changes. Record both original hosted attempts and require original evidence retention before a complete rerun replaces Actions artifacts. ADR: 0063, 0069, 0070 * docs(roadmap): close P02b-7 implementation qualification Record two complete source-matched hosted layouts with exact case, artifact, ownership and cleanup evidence. Mark the five-step packet complete while retaining maintainer review and P02b-8 exit work. Preserve the historical browser failure's evidence limits and the separate scope of real-provider and actual-browser proofs. ADR: 0063, 0069, 0070 * fix(web): preserve anonymous reads and BFF failure ownership Keep public rendering available on malformed browser state and preserve live sessions across plain API outages without relaxing refresh fences. Confine logout hints to Location, prove cookie and first-error cleanup boundaries, and reconcile test assertions and delivery claims with the actual source and evidence. ADR: 0053, 0054, 0063, 0064, 0069, 0070 I18n: auth.session.expired * docs(roadmap): record the reviewed BFF correction handoff Keep implementation state separate from live source-bound check results so recording CI evidence in the PR does not invalidate its source again. The correction source and local review receipts remain explicit. ADR: 0063, 0069, 0070 * test(web): retain startup evidence until child absence Do not remove either counter tree when actual child absence cannot be confirmed. Keep failure evidence and the original startup error intact. The focused independent confirmation and actual child controls pass. ADR: 0063, 0069, 0070 * test(jobs): distinguish recovery renewal from initial timer setup Preserve the first failed recovery proof across actual cleanup and retain closed failure stages without exporting private diagnostic content. The hosted failure remains unexplained; keep every runtime bound and exact outcome assertion while requiring a real later timer rearm. ADR: 0047, 0063, 0069, 0070 * docs(roadmap): refresh the recovery follow-up index Regenerate the delivery index after the final focused verification receipt. ADR: 0069 * fix(ci): classify private fixture image preparation failures Retain only finite component and failure observations for repeated opaque pre-test image-pull refusals. Keep the command's default behavior and all budgets while preserving first-error ownership through private capture cleanup. No retry or registry policy changes are introduced. ADR: 0062, 0063, 0069 * docs(auth): propose uncertain AccountSite refusal policy Separate API authentication uncertainty from proven identity refusal before changing live session custody. Preserve the qualified correction source in a durable receipt and record the remaining correction and approval gates. ADR: 0064, 0069, 0070 * docs(auth): accept explicit AccountSite refusal decision Record the maintainer-authorized decision after verified review corrections. Preserve accepted history and separate local session custody from checked API authority, including callback statuses and conservative masked refusals. ADR: 0064, 0070, 0071 * fix(auth): bind closed BFF boundaries and lifecycle proofs Close independent HTTP and custody regression gaps without expanding the approved surface. Stabilize projected expiry and apply compatible security patches while preserving native ownership and actual-settlement evidence. ADR: 0053, 0054, 0070 I18n: unchanged * test(auth): close configuration and scoped dependency escapes Bind configuration references to the checked export and test quoted package keys so independently planted bypasses cannot evade the new source guards. ADR: 0070 * fix(auth): retain ordinary sessions on uncertain API refusal An API 401 cannot distinguish invalid from undecidable credentials. Preserve ordinary-read ownership without idle touch while withholding checked content; keep callback and refreshed revision publication fail closed. ADR: 0064, 0070, 0071 * test(auth): pin the checked configuration plugin binding Keep the fixed configuration export from delegating to an uninspected local wrapper while preserving the clean pinned Next integration. ADR: 0070 * fix(auth): preserve accessible recovery and proof observations Keep safe recovery available while withholding unverified content. Exercise actual child-output and cookie-header observations, and retain current localized fixture views without claiming a full provider browser journey. ADR: 0027, 0070 I18n: en/tr auth catalogues updated * test(auth): bind provider and CI proof failure boundaries Make original cookie revocation, opposite-tenant refusal and closed successful causal observations visible through their actual owners. Plant isolated CI violations while preserving existing budgets and production job semantics. ADR: 0047, 0063, 0070, 0071 * fix(auth): reconcile current session proof carriers Keep current architecture, standards and future acceptance owners aligned with the delivered native boundary. Carry the closed privacy stage through both proof readers without changing authority, cleanup or deployment support. ADR: 0069, 0070, 0071 * docs(auth): distinguish verified callback authority Preserve the native host rule while excluding unverified browser selectors, and record the first correction review and source-bound qualification gates. ADR: 0063, 0070, 0071 * test(auth): observe provider time and actual HTML refusal Use fresh fixture-owned issuance time instead of assuming an optional response header. Keep the real browser negative aligned with HTML while independently preserving publication, audit and reader-isolation checks. ADR: 0070, 0071 * test(auth): bind authenticated SDK result boundaries Replace a vacuous ownership comparison and isolate cancellation, body failure and Problem Details mapping in the authenticated wrapper without duplicating the shared public response policy or changing runtime behavior. ADR: 0064, 0070, 0071 * docs(auth): record SDK counterfactual review evidence Separate the verified wrapper coverage gap from an unreproduced signal claim, and retain the complete current frontend census without overstating scope. ADR: 0064, 0069, 0070, 0071 * docs(auth): hand off the reviewed correction source Close the completed local review gates while keeping exact-source hosted qualification, durable receipt and maintainer merge as explicit remaining work. ADR: 0063, 0069, 0070, 0071 * test(jobs): retain closed recurrence wait observations Keep the original timeout and ownership failure visible while retaining bounded pre-stop progress facts for the unexplained hosted failure. ADR: 0047, 0063, 0069 * test(ci): bind both recurrence observation cases independently Prevent the finite diagnostic control from shrinking with its production allowlist and preserve the failed qualification's exact evidence scope. ADR: 0063, 0069 * test(auth): preserve closed browser launch observations Distinguish launch phases and retain branded readiness failures without changing browser execution, deadlines or actual cleanup requirements. ADR: 0063, 0069, 0070 * test(auth): report browser liveness without inferring exit Keep the readiness diagnostic faithful for failed spawns as well as observed exits and preserve the completed first-round review evidence. ADR: 0063, 0069, 0070 * test(jobs): isolate causal stop after actual provider acceptance Use the qualified real-timer pacing owner to exclude an unrelated legal pre-ACK refusal while retaining original deadlines, runtime policy and all causal provider, cleanup and durable-state assertions. ADR: 0047, 0063, 0069 * docs(roadmap): record final BFF correction qualification Bind the completed reviews and independently verified A/B evidence to its exact implementation source while keeping the closeout documentation-only. ADR: 0063, 0069, 0070, 0071 * fix(auth): close review proof and recovery gaps Isolate security controls from unrelated refusals and keep recovery usable without granting failed checks authority. Bind native credential flows to the fixed port, bound diagnostic child output and preserve source-bound qualification and explicit maintainer acceptance evidence. ADR: 0009, 0047, 0063, 0069, 0070, 0071 I18n: auth.session.unavailable_title, auth.session.unavailable * docs(roadmap): retain first correction review receipts Bind the independent source-review conclusions and their executed checks to the committed correction without presenting local results as hosted qualification. ADR: 0069, 0070, 0071 * docs(roadmap): record independent correction recheck Preserve the second fresh review scope and independently executed checks, then freeze the corrected source for complete hosted qualification. ADR: 0063, 0069, 0070, 0071 * test(auth): delimit opaque observer child arguments A valid opaque cookie can begin with a dash. Keep it positional after the Node option terminator and force that boundary in both output observers so the controls reach the intended late-cookie assertion. ADR: 0063, 0069, 0070 * docs(roadmap): record observer argument review evidence Keep the exact narrow review and independent argv/scanner checks distinct from the failed hosted assignment and pending final qualification. ADR: 0063, 0069, 0070 * docs(roadmap): freeze reviewed observer correction Record the second independent observer review and preserve failed-source limits before beginning complete qualification of the corrected source. ADR: 0063, 0069, 0070 * docs(roadmap): record reviewed BFF correction qualification Bind complete same-source A/B and retained independent evidence to the reviewed implementation while keeping this closeout documentation-only. ADR: 0063, 0069, 0070, 0071 * docs(roadmap): close merged tenant BFF delivery Record PR #36's verified merge and identical tested source tree. Close P02b-7 while keeping P02b-8's decisions, erasure inventory and phase exit enforcement explicitly pending. ADR: 0069, 0070, 0071 * docs(roadmap): propose phase exit enforcement decisions Ground G16 and G18 in the delivered analyzer, storage and CI boundaries before implementation. Record the additive ADR-0032 proposal, complete erasure-inventory scope and four reviewed implementation steps without changing runtime or accepting either gate. ADR: 0032, 0046, 0047, 0057, 0069, 0070 * docs(roadmap): refine phase exit proposal after review Preserve Phase 03's existing erasure deliverables and make the proposed exception and constant-name boundaries unambiguous before acceptance. Record both independent first-round reviews and the baseline checks. ADR: 0032, 0046, 0047, 0069 * docs(roadmap): require canonical inventory before gate acceptance Install the G18 carrier and its existing authority handoffs before marking either gate accepted or starting analyzer work. Keep Step 2 focused on independent storage verification and drift controls. ADR: 0032, 0046, 0047, 0069 * docs(roadmap): record phase exit proposal review verification Retain both independent correction rechecks and the pending maintainer decision without implying analyzer delivery or phase-exit qualification. ADR: 0032, 0046, 0047, 0069 * docs(decisions): accept phase exit enforcement package Record the approved G16 diagnostic and G18 canonical inventory before implementation. Preserve current erasure authorities and Phase 03/11 ownership while registering the pending proof obligations. ADR: 0032, 0046, 0047, 0057, 0069, 0070 * feat(kernel): guard sensitive exception messages at compile time Check bounded sensitive-name expressions across production C# projects using the shared runtime matcher, while preserving LS0001 scope and the approved Warning posture. Exercise actual compiler imports and isolated CI builds alongside source propagation and clean-sample controls. ADR: 0032, 0069 Module: Tenancy, Identity, Customization, Audit, Education, Content, Media * fix(kernel): analyze dynamically bound exception constructors Keep known string arguments under the approved guard when another constructor argument is dynamic. Retain evaluated wiring controls and remove the superseded XML parser that tested only itself. ADR: 0032, 0069 * docs(roadmap): close first phase exit implementation step Retain both fresh independent second-round reviews and their execution limits before beginning inventory drift enforcement. ADR: 0032, 0069 * test(kernel): verify durable asynchronous inventory coverage Bind the canonical inventory to actual compiled migration operations so new storage and missing classifications cannot silently escape the erasure review. Keep structural coverage separate from deletion authority and live-schema proof. ADR: 0046, 0047, 0057, 0069 * fix(kernel): refuse unsupported inventory table creation Keep new durable copies from silently bypassing the migration census through SELECT INTO or fragmented dynamic SQL while preserving the pinned installer. ADR: 0046, 0047, 0057, 0069 * fix(kernel): close inventory schema resolution bypasses Refuse unsupported schema resolution and dynamic commands so conditional names and qualified renames cannot masquerade as inventoried public tables. ADR: 0046, 0047, 0057, 0069 * docs(roadmap): close asynchronous inventory verification Record both independent review rounds and their verified corrections before continuing phase-exit carrier reconciliation. ADR: 0069 * fix(kernel): reconcile delivered phase contract carriers Keep the plan, standards, workflow examples and source explanations aligned with delivered authentication and asynchronous ownership without granting new authority or disguising future permission and erasure prerequisites. ADR: 0032, 0033, 0044, 0046, 0047, 0064, 0065, 0069, 0070, 0071 * docs(roadmap): record carrier reconciliation review Keep independent source and corpus verification distinct from final-source runtime qualification before opening the second review round. ADR: 0069 * docs(roadmap): close phase carrier reconciliation Record both fresh approvals and keep final-source runtime qualification as an explicit remaining exit obligation. ADR: 0069 * test(kernel): bind phase exit criteria to actual proof owners Make delivery reconciliation counts explicit and map every exit obligation to its real owner before complete source-bound qualification. Preserve existing audit composition and future tenant-status decision authority. ADR: 0033, 0044, 0046, 0047, 0057, 0069 * docs(roadmap): record exit source review boundary Keep independent source approval separate from still-pending complete hosted qualification at the frozen code and test source. ADR: 0069 * docs(roadmap): record the second exit source review Keep source approval and the retained A evidence separate from the pending B and current-head qualification so no partial proof implies phase exit. ADR: 0032, 0063, 0069 * docs(roadmap): close source-bound Phase 02b exit qualification Preserve exact-source A and B evidence and the completed review trail while keeping final PR-head checks and maintainer merge as separate gates. Record the live protection and each future phase's actual owner. ADR: 0032, 0063, 0069 * fix(kernel): close exit guard and evidence review gaps Ensure the approved exit guards cannot silently miss build suppression or unclassified storage, and bind audit cleanup proof to the production capture. Reconcile the surrounding ownership and privacy claims with current authority. ADR: 0032, 0044, 0046, 0047, 0057, 0069 Module: Audit, Customization, Education, Tenancy * test(kernel): reject opaque SQL routine storage creation Refuse quoted routine bodies that can hide dynamic storage DDL from the bounded inventory reader, and prove their actual effect on owned PostgreSQL. Align the remaining realm-activation and job-qualification carrier comments. ADR: 0046, 0047, 0057, 0069 * test(kernel): validate complete SQL routine declaration boundaries Keep default dollar strings and post-body options from hiding an opaque body or unresolved search path, while preserving the pinned migration headers. ADR: 0046, 0047, 0057 * docs(roadmap): record verified exit correction review boundaries Keep source review, local execution and pending hosted qualification distinct, including the accepted scope limits and independently verified dispositions. ADR: 0032, 0046, 0047, 0057, 0069 * test(ci): include the new PostgreSQL fixture in the plan witness Reconcile the declared fixture population with the actual new test class so complete-plan validation remains strict before hosted qualification. ADR: 0063, 0069 * test(kernel): bind retry fairness and SQL literal proof to durable facts Distinguish body entry from committed job effects through a controlled rollback, and keep escaped SQL literals from hiding durable storage declarations. ADR: 0046, 0047, 0057, 0063, 0069 * docs(roadmap): record the reviewed CI correction source Bind both fresh second-round reviews and the independently rebuilt census to an exact source while leaving complete hosted qualification pending. ADR: 0047, 0063, 0069 * test(kernel): qualify completion after acknowledged skipped wakeups Separate native completion proof from accepted bridge repair timing while retaining the real ACK, due, generation and cleanup fences. Prove a locked retry generation with durable business and audit outcomes and a wrong- generation counterfactual, without changing production behavior or deadlines. ADR: 0047, 0059, 0063, 0069 * docs(roadmap): freeze the reviewed native completion correction Bind both fresh second-round reviews and post-hook execution to the exact committed test correction before complete hosted qualification. ADR: 0047, 0063, 0069 * test(frontend): own Playwright artifacts through fixture cleanup Keep CDP artifacts beneath the existing private fixture root so SDK cleanup failures cannot leave an unowned sibling behind a successful close. Preserve joined shutdown and the parent empty-root guard; validate with the real browser journey and an isolated SDK refusal counterexample. ADR: 0063, 0069, 0070 * docs(roadmap): freeze reviewed fixture ownership and carrier fixes Record both fresh source reviews and restore accurate module terminology and ADR navigation before qualifying the final correction source. ADR: 0032, 0047, 0063, 0069, 0070 * docs(roadmap): close qualified PR corrections and exit evidence Bind the complete corrected-source A/B proof and independent audits to exact source, cases, artifacts and cleanup. Keep current documentation-head checks, maintainer review and merge as separate gates. ADR: 0032, 0063, 0069 * docs(roadmap): close merged phase 02b and point to phase 03 Record the actual PR merge and its equality to the qualified source so phase completion follows verified delivery. Preserve dated evidence and point the entry documents to the next phase without starting its work. ADR: 0063, 0069 * docs: prepare phase 03 identity implementation plan Make identity delivery start from explicit first-writer gates and complete proof ownership, preserving the accepted auth, isolation and audit boundaries. Reconcile scope and dependency examples so preparation cannot be mistaken for runtime authorization. ADR: 0017, 0036, 0044, 0064, 0069, 0070 Module: Identity, Tenancy, Customization, Audit * docs(decisions): propose identity and membership foundation Break the first-login actor cycle through an explicit application identity contract, and settle shared membership and privacy invariants before their first writers. Keep both decisions Proposed and all runtime gates closed pending maintainer approval; separate later packet responsibilities. ADR: 0017, 0036, 0044, 0064, 0069, 0070 Module: Identity, Tenancy, Audit * docs(decisions): close first identity proposal review findings Make tenantless pre-session bootstrap and organization learner grants explicit before approval. Separate insertion-time audit proof from retained references and choose a closure guard compatible with the read policy. Record the independent review scope and pending implementation boundary. ADR: 0064, 0069, 0070 Module: Identity, Audit * docs(decisions): define global audit outcomes and fresh lock reads Preserve MUST reconciliation for failed or uncertain identity creation and make its subject attribution and cleanup explicit. Require a fresh read committed snapshot after admission locks so the promised database guards cannot accept stale closure or administrator state. ADR: 0033, 0040, 0044, 0069 Module: Identity, Audit * docs(decisions): preserve canonical audit timestamp reconciliation Keep the existing fresh-timestamp indeterminate evidence for the new global class rather than introducing a separate key policy. Distinguish durable failure evidence from proof of a committed identity creation. ADR: 0033, 0044, 0069 Module: Identity, Audit * docs(roadmap): record reviewed identity proposal readiness Keep approval and runtime boundaries visible after both independent review roun…
1 parent 7cad840 commit 012e67c

369 files changed

Lines changed: 34228 additions & 5222 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/skills/local-dev-setup/SKILL.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ session, supply `ConnectionStrings:Default` (`learnstack_app`) and
126126
`ConnectionStrings:OutboxDispatcher` (`learnstack_outbox_admin`) through environment
127127
or the project's `learnstack-api-dev` user-secrets store. The mandatory API worker
128128
resolves its guarded source and verifies dispatcher connectivity at startup.
129+
Also supply `Identity:AuthorityId` (`Identity__AuthorityId`) and
130+
`Authentication:Tenant:Issuer` (`Authentication__Tenant__Issuer`) matching the
131+
installed deployment authority, following
132+
[Identity deployment](../../../docs/modules/identity/README.md#global-implementation-and-deployment).
133+
Authority qualification is mandatory before the API accepts requests.
129134
The dispatcher credential belongs only to the API; every Seeder invocation uses
130135
an explicit application-only environment, and the web launcher receives neither
131136
database credential. Both empty hop lists remain

‎.claude/skills/run-tests-locally/SKILL.md‎

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,16 @@ frontend/apps/web/scripts/
7979

8080
### Step 3: Run unit tests
8181

82+
Use `--configuration Release` for repository qualification, matching CI. The
83+
architecture suite includes exact compiled ownership/opcode controls; a Debug
84+
build is not interchangeable with that qualified population. Run heavy .NET and
85+
native frontend qualification sequentially on a workstation so cold development
86+
compilation does not compete with the architecture mutation census.
87+
8288
Fastest; no Docker required.
8389

8490
```bash
85-
dotnet test backend/tests/LearnStack.Tests.Unit \
91+
dotnet test --configuration Release backend/tests/LearnStack.Tests.Unit \
8692
--no-restore \
8793
--logger "console;verbosity=normal"
8894
```
@@ -91,11 +97,12 @@ Typical runtime: < 30 s. Failures here are almost always domain-logic bugs.
9197

9298
### Step 4: Run architecture tests
9399

94-
Also fast; no Docker. Failures here mean **structural drift** — the code violates
95-
a documented rule.
100+
No Docker. The full IL mutation census can take tens of minutes on a workstation;
101+
CI runs it in bounded shards. Failures here mean **structural drift** — the code
102+
violates a documented rule.
96103

97104
```bash
98-
dotnet test backend/tests/LearnStack.Tests.Architecture \
105+
dotnet test --configuration Release backend/tests/LearnStack.Tests.Architecture \
99106
--no-restore
100107
```
101108

@@ -134,7 +141,7 @@ into native/ordinary execution jobs behind the required integration aggregate. L
134141
`--filter "Requires!=Docker"` gives you the Docker-free half.
135142

136143
```bash
137-
dotnet test backend/tests/LearnStack.Tests.Integration \
144+
dotnet test --configuration Release backend/tests/LearnStack.Tests.Integration \
138145
--no-restore \
139146
--logger "console;verbosity=normal" \
140147
--filter "FullyQualifiedName~Enrollment" # subset
@@ -273,17 +280,17 @@ processes on Ctrl+C; it does not run the CI browser/audit proof.
273280

274281
### Step 7: Single-test focus
275282

276-
`dotnet test --filter`:
283+
`dotnet test --configuration Release --filter`:
277284

278285
```bash
279286
# Class
280-
dotnet test --filter "FullyQualifiedName~EnrollmentCreateTests"
287+
dotnet test --configuration Release --filter "FullyQualifiedName~EnrollmentCreateTests"
281288

282289
# Method
283-
dotnet test --filter "FullyQualifiedName~EnrollmentCreateTests.Create_succeeds"
290+
dotnet test --configuration Release --filter "FullyQualifiedName~EnrollmentCreateTests.Create_succeeds"
284291

285292
# Docker trait — native CI additionally uses NativeCrashProof=true and its complement
286-
dotnet test --filter "Requires=Docker"
293+
dotnet test --configuration Release --filter "Requires=Docker"
287294
```
288295

289296
`vitest`:
@@ -298,11 +305,11 @@ pnpm --filter @learnstack/web test -t "shows danger tone" # name filter
298305

299306
```bash
300307
# From the repository root; collect behavioral suites separately.
301-
dotnet test backend/tests/LearnStack.Tests.Unit \
308+
dotnet test --configuration Release backend/tests/LearnStack.Tests.Unit \
302309
--collect:"XPlat Code Coverage" --results-directory coverage/unit
303-
dotnet test backend/tests/LearnStack.Tests.Integration \
310+
dotnet test --configuration Release backend/tests/LearnStack.Tests.Integration \
304311
--collect:"XPlat Code Coverage" --results-directory coverage/integration
305-
dotnet test backend/tests/LearnStack.Tests.Architecture
312+
dotnet test --configuration Release backend/tests/LearnStack.Tests.Architecture
306313
reportgenerator -reports:"coverage/**/coverage.cobertura.xml" \
307314
-targetdir:"coverage/html" \
308315
-reporttypes:Html
@@ -337,12 +344,12 @@ make install
337344

338345
# The `backend` job — build with warnings as errors, then the Docker-free half
339346
(cd backend && CI=true dotnet build LearnStack.slnx --no-restore --configuration Release)
340-
(cd backend && dotnet test LearnStack.slnx \
347+
(cd backend && dotnet test --configuration Release LearnStack.slnx \
341348
--no-restore --no-build --configuration Release \
342349
--filter "Requires!=Docker" --logger trx)
343350

344351
# The complete Docker complement; CI requires both native/ordinary partitions
345-
(cd backend && dotnet test LearnStack.slnx \
352+
(cd backend && dotnet test --configuration Release LearnStack.slnx \
346353
--no-restore --no-build --configuration Release \
347354
--filter "Requires=Docker" --logger trx)
348355
```

‎.env.example‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,12 @@ ConnectionStrings__OutboxDispatcher='Host=localhost;Port=5432;Database=learnstac
6565
# ─── Keycloak (two realms per ADR-0004 Amendment 1) ──────────────────────
6666
# The Development API defaults to the loopback tenant issuer declared in
6767
# backend/src/LearnStack.Api/appsettings.Development.json. Other deployment modes
68-
# require an explicit canonical HTTPS issuer; this override goes only to the API.
69-
# Authentication__Tenant__Issuer=https://identity.example/realms/learnstack
68+
# require an explicit canonical HTTPS issuer; the API and authority installer use it.
69+
Authentication__Tenant__Issuer=http://localhost:8080/realms/learnstack
70+
# Global identity uses an explicit stable deployment ID, not a hash of the issuer.
71+
# `make migrate` installs/verifies BOTH explicit keys as one immutable registration.
72+
# This fixed ID is local development data; deployment owners choose their stable ID.
73+
Identity__AuthorityId=019a1929-5450-7bbb-8df1-516e8e002501
7074
KEYCLOAK_ADMIN=admin
7175
KEYCLOAK_ADMIN_PASSWORD=admin-dev-secret
7276
# Server-only BFF client source. Old local .env files must add it explicitly;

‎.github/workflows/ci.yml‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ jobs:
242242
backend-integration-tests:
243243
name: backend ordinary-${{ matrix.index }}
244244
runs-on: ubuntu-24.04
245-
timeout-minutes: 20
245+
timeout-minutes: 25
246246
strategy:
247247
fail-fast: false
248248
matrix:
@@ -295,7 +295,23 @@ jobs:
295295

296296
- name: Prepare pinned provider fixture images within the whole-job budget
297297
timeout-minutes: 2
298-
run: python3 scripts/ci-test-shards.py prepare-fixtures
298+
env:
299+
LEARNSTACK_NATIVE_RUNNER_CONTEXT: ${{ runner.environment }}
300+
LEARNSTACK_NATIVE_RUNNER_OS: ${{ runner.os }}
301+
LEARNSTACK_NATIVE_RUNNER_ARCH: ${{ runner.arch }}
302+
LEARNSTACK_NATIVE_RUNNER_LABEL: ubuntu-24.04
303+
LEARNSTACK_NATIVE_JOB_CONTAINER: ${{ toJSON(job.container) }}
304+
LEARNSTACK_NATIVE_JOB_SERVICES: ${{ toJSON(job.services) }}
305+
LEARNSTACK_CI_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
306+
LEARNSTACK_NATIVE_RUN_ID: ${{ github.run_id }}
307+
LEARNSTACK_NATIVE_ATTEMPT: ${{ github.run_attempt }}
308+
LEARNSTACK_NATIVE_JOB: ${{ github.job }}
309+
LEARNSTACK_NATIVE_SHA: ${{ github.sha }}
310+
LEARNSTACK_NATIVE_REPOSITORY: ${{ github.repository }}
311+
LEARNSTACK_NATIVE_WORKFLOW_REF: ${{ github.workflow_ref }}
312+
LEARNSTACK_NATIVE_WORKFLOW_SHA: ${{ github.workflow_sha }}
313+
LEARNSTACK_NATIVE_WORKSPACE: ${{ github.workspace }}
314+
run: python3 scripts/ci-test-shards.py prepare-fixtures ordinary-${{ matrix.index }}
299315

300316
- name: Verify stock browser for admission navigation proof
301317
run: |

‎CLAUDE.md‎

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ repository holds only LearnStack's side of the boundary, in
3939

4040
## What state this is in
4141

42-
**Phase 01, Phase 02a and Phase 02d are complete; Phase 02b is the live phase.**
42+
**Phase 01, Phase 02a, Phase 02d and Phase 02b are complete; Phase 03 is in progress.**
4343
[Phase 02d](docs/roadmap/phase-02d-walking-skeleton.md) owns the two-tenant walking
44-
skeleton. [Phase 02b](docs/roadmap/phase-02b-events-auth.md) owns current packet
45-
and decision state for events, background jobs, identity and sessions.
44+
skeleton. [Phase 02b](docs/roadmap/phase-02b-events-auth.md) owns the delivered
45+
events, background jobs, API authentication and session baseline.
46+
[Phase 03](docs/roadmap/phase-03-identity-admin.md) owns identity, membership and authorization work; its Status block records
47+
current packet state. Acceptance of a contract does not complete its implementation.
4648
[Phase 06](docs/roadmap/phase-06-renderer-admin-studio.md) owns the full
4749
renderer/Studio expansion.
4850

@@ -61,8 +63,8 @@ the foundation ports — is recorded packet by packet in
6163
frozen history, together with the 2026-08-08 restructure that moved correctness
6264
earlier, additive infrastructure later and proof earlier.
6365

64-
**Four modules hold domain code:** Tenancy, Customization, Audit and Education.
65-
Content, Identity and Media remain scaffolded. Module-level references in the docs
66+
**Five modules hold domain code:** Tenancy, Customization, Audit, Education and
67+
Identity. Content and Media remain scaffolded. Module-level references in the docs
6668
to types such as `ILiveClassProvider` or `ITenantSearch` describe intended shape
6769
owned by their named phases.
6870

@@ -77,10 +79,13 @@ For any task, read in this order:
7779
5. [docs/standards/00-principles.md](docs/standards/00-principles.md) — the beliefs every other standard descends from.
7880
6. [docs/glossary.md](docs/glossary.md) — terminology; the single source of truth for project-specific terms.
7981

80-
Then read the phase that is live and the one it stands on:
82+
Then read the current phase and the completed baselines it stands on:
8183

84+
- [docs/roadmap/phase-03-identity-admin.md](docs/roadmap/phase-03-identity-admin.md) —
85+
**the current phase**. Read its identity,
86+
membership, authorization and first-writer decisions before planning code.
8287
- [docs/roadmap/phase-02b-events-auth.md](docs/roadmap/phase-02b-events-auth.md) —
83-
**the live phase**. Its Status block owns packet state; its decision register owns
88+
complete. Its Status block owns packet state; its decision register owns
8489
gate state and links each Accepted decision package in the delivery log, which is
8590
normative — read it before writing the code its gate governs. Navigate a delivery
8691
log by the generated index at its top; never read the whole file.
@@ -177,6 +182,8 @@ rules:
177182
- OpenTelemetry + correlation id end to end ([10](docs/standards/10-observability.md)).
178183
- WCAG 2.2 AA across all surfaces ([16](docs/standards/16-accessibility.md)).
179184
- Audit-coverage matrix required per module ([18](docs/standards/18-audit-coverage.md)).
185+
- Global User identity consumes the existing typed `UserId`; global and tenant
186+
transaction owners never join or retarget each other ([ADR-0072](docs/decisions/0072-application-owned-identity-bootstrap.md)).
180187
- Permission keys `{module}.{resource}.{action}` with closed action set + scope
181188
(Platform / Tenant / Organization) ([19](docs/standards/19-permissions.md)).
182189
- Infrastructure-stack rules (foundation ports and their default
@@ -294,9 +301,12 @@ rules:
294301
and every module's `IAuditCatalogSource` names the first two. Declaring them
295302
in the module is a project cycle. `AuditEntry` consumes them; it does not
296303
declare them.
297-
- **Announce `TenantId.PlatformSentinel` as a request's tenant.** Exactly one
298-
class of row carries it — a platform-scope operation with no resolvable
299-
tenant, written standalone — and Packet 9 puts the guard where the value
304+
- **Announce `TenantId.PlatformSentinel` as a request's tenant.** Exactly two named
305+
classes of audit row may carry it: platform-scope standalone operations and
306+
ADR-0072 global `identity.user.create` attempts under its confined common
307+
owner. Neither class grants tenant authority or permits a tenant setter to
308+
announce the sentinel.
309+
Packet 9 puts the guard where the value
300310
enters: `SetProvisioningTenantContextAsync` refuses the sentinel exactly as it
301311
already refuses `Guid.Empty`, and `Tenant.Create` refuses it in the factory
302312
([ADR-0044 Amendment 3](docs/decisions/0044-audit-write-path.md)). The

‎Makefile‎

Lines changed: 9 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -120,106 +120,15 @@ build-frontend: ## `pnpm -r build` the frontend monorepo.
120120

121121
.PHONY: migrate
122122
migrate: ## Apply every EF migration chain (platform + each module) as `learnstack_migration` (the ONLY sanctioned carrier of that credential).
123-
@# Every dotnet command in this recipe runs from `backend/`, because that is where
124-
@# the SDK pin lives (`backend/global.json`). Run from the repository root there is
125-
@# no global.json above them, so whichever SDK is newest on the machine answers —
126-
@# and the pin exists precisely so this target and CI apply the same EF version.
127-
@#
128-
@# Standards 05 § Database roles: ConnectionStrings:Migration must never appear
129-
@# in API or worker runtime configuration. The role OWNS every table it creates,
130-
@# and a runtime that is the owner is precisely the arrangement FORCE ROW LEVEL
131-
@# SECURITY exists to defeat — every isolation test would then pass against
132-
@# policies that constrain nothing. This target is where the credential lives.
133-
@#
134-
@# Every design-time factory reads only ConnectionStrings__Migration, never
135-
@# the startup application's Default connection. Export to that confined
136-
@# factory; do not duplicate the credential on the process command line.
137-
@# Four things this recipe does that a naive version does not, each because the
138-
@# naive version was measured doing the wrong thing:
139-
@#
140-
@# 1. `.env` is read one key at a time, NOT shell-sourced. A connection string
141-
@# contains semicolons, and `. ./.env` on an unquoted row parses them as
142-
@# statement separators: `ConnectionStrings__Migration` arrived as
143-
@# `Host=localhost`, and `Port`, `Database`, `Username`, `Password` leaked
144-
@# into the environment as bare variables. `tr -d '\r'` as well, because a
145-
@# CRLF row otherwise leaves the closing quote and the carriage return
146-
@# inside the credential.
147-
@# 2. The role is compared EXACTLY. An unanchored `*Username=learnstack_migration*`
148-
@# accepted `learnstack_migration_readonly` and would have run migrations as
149-
@# it. Splitting on `;` and comparing the whole token has no neighbourhood.
150-
@# 3. The error path prints a REDACTED string. An earlier version echoed the
151-
@# whole value, password included — in the one target whose entire purpose
152-
@# is keeping that credential in one place.
153-
@# 4. The loop carries its own status. `-e` does not abort on a failure inside
154-
@# a for-loop body that is part of a compound list: both iterations ran
155-
@# after `false` and the recipe still exited 0, so a migration target
156-
@# reported success after every migration failed.
157-
@# 5. The loop covers `LearnStack.Infrastructure` as well as the modules. The
158-
@# platform chain (outbox_messages, idempotency_keys) lives outside
159-
@# `src/Modules`, and a glob that only walked the modules left the two
160-
@# tables no module owns unmigrated on every documented path.
161-
@# 6. Tenancy is named BEFORE the glob. From Phase 02a Packet 9 the chains are
162-
@# no longer independent: `audit_config` carries the schema's only
163-
@# cross-chain foreign key, to `tenants`, which the Tenancy chain creates.
164-
@# The glob expands alphabetically and `Modules/Audit` sorts first, so the
165-
@# naive order fails on a fresh database. `applied` is what keeps the named
166-
@# project from being visited twice when the glob reaches it — a second
167-
@# `database update` is a no-op, but a recipe that prints the same chain
168-
@# twice reads like a bug in the recipe.
169-
@# 7. Build the startup graph once in Release, with restore for standalone use.
170-
@# Every EF invocation uses that fresh output; the demo launches the same API.
171-
@# Explicit failures also stop old Make versions without shell errexit.
172-
@# 8. Save and unexport the migration credential before restore/build; only
173-
@# the no-build EF child receives it, through its process environment.
174-
@migration_cs="$${ConnectionStrings__Migration:-}"; \
175-
unset ConnectionStrings__Migration; \
176-
migration_env="$${LEARNSTACK_COMPOSE_ENV_FILE:-.env}"; \
177-
if [ -z "$$migration_cs" ] && [ -f "$$migration_env" ]; then \
178-
migration_cs=$$(sed -n "s/^ConnectionStrings__Migration=//p" "$$migration_env" \
179-
| tail -1 | tr -d "\r" | sed "s/^['\"]//; s/['\"]$$//"); \
180-
fi; \
181-
role=$$(printf '%s' "$$migration_cs" | awk -f scripts/connection-string.awk -v field=user); \
182-
redacted=$$(printf '%s' "$$migration_cs" | awk -f scripts/connection-string.awk -v field=redacted); \
183-
if [ -z "$$migration_cs" ]; then \
184-
echo "ConnectionStrings__Migration is not set."; \
185-
echo "It arrives with the four-role model in Phase 02a Packet 6: copy the"; \
186-
echo "'four database roles' and 'four connection strings' blocks out of"; \
187-
echo ".env.example into your .env and re-run. A .env written before that"; \
188-
echo "packet has neither."; \
189-
exit 1; \
190-
fi; \
191-
if [ "$$role" != "learnstack_migration" ]; then \
192-
echo "ConnectionStrings__Migration names Username='$$role', not learnstack_migration:"; \
193-
echo " $$redacted"; \
194-
echo "Migrations must run as the role that OWNS every table. Running them as"; \
195-
echo "the runtime role is the arrangement FORCE ROW LEVEL SECURITY defeats."; \
196-
echo "If the value looks truncated at the first ';', quote it in .env. A"; \
197-
echo "URI-style DSN (postgres://...) is not a form Npgsql parses at all; the"; \
198-
echo "expected shape is the key/value list in .env.example."; \
199-
exit 1; \
200-
fi; \
201-
(cd backend && dotnet tool restore >/dev/null) || exit $$?; \
202-
(cd backend && dotnet build src/LearnStack.Api --configuration Release --nologo) || exit $$?; \
203-
found=0; \
204-
failed=0; \
205-
applied=" "; \
206-
for proj in backend/src/Modules/Tenancy/LearnStack.Modules.Tenancy.Infrastructure \
207-
backend/src/LearnStack.Infrastructure \
208-
backend/src/Modules/*/LearnStack.Modules.*.Infrastructure; do \
209-
test -d "$$proj/Persistence/Migrations" || continue; \
210-
case "$$applied" in *" $$proj "*) continue;; esac; \
211-
applied="$$applied$$proj "; \
212-
found=1; \
213-
echo "==> $$(basename $$proj)"; \
214-
(cd backend && ConnectionStrings__Migration="$$migration_cs" dotnet ef database update \
215-
--project "../$$proj" \
216-
--startup-project src/LearnStack.Api \
217-
--configuration Release --no-build) || failed=1; \
218-
done; \
219-
if [ "$$found" = "0" ]; then \
220-
echo "No project carries Persistence/Migrations yet — the first lands with the Tenancy schema in Phase 02a Packet 6."; \
221-
fi; \
222-
exit "$$failed"
123+
@# The Node owner selects one deployment source, validates the migration role,
124+
@# and confines credentials to EF/authority children after fresh Release builds.
125+
@# Keep dependency order explicit and cover future module chains with the glob.
126+
@node scripts/migrate.mjs \
127+
backend/src/Modules/Tenancy/LearnStack.Modules.Tenancy.Infrastructure \
128+
backend/src/LearnStack.Infrastructure \
129+
backend/src/Modules/Audit/LearnStack.Modules.Audit.Infrastructure \
130+
backend/src/Modules/Identity/LearnStack.Modules.Identity.Infrastructure \
131+
backend/src/Modules/*/LearnStack.Modules.*.Infrastructure
223132

224133
.PHONY: sdk
225134
sdk: ## Regenerate @learnstack/sdk types from the committed v1 snapshot.

0 commit comments

Comments
 (0)