Skip to content

Commit 0dfade0

Browse files
cemililikcoderabbitai[bot]claude
authored
feat(web): own tenant BFF sessions and close browser admission (#36)
* docs(roadmap): close quota correction reviews for qualification Record both fresh quota reviews, current Release and PostgreSQL proofs, and the complete frontend source inventory correction. Freeze the source for renewed exact-head CI; historical results remain source-specific. * docs(roadmap): close merged P02b-4 and name the next packet Record the identical squash-merge tree and complete final-source A/B qualification. Reconcile mutable status carriers while preserving dated delivery receipts and keeping P02b-5 authentication gates open. ADR: 0047, 0063 * docs(decisions): propose the P02b-5 authentication boundary Verify the authentication entry contract before exposing validated claims while authorization remains staged. Record the bounded audit and read-mode instruments, shared ingress costs and five reviewable development steps for maintainer approval before runtime changes. ADR: 0064, 0036, 0040 * docs(roadmap): record P02b-5 decision reviews Keep the reviewed proposal and current entry evidence separate from runtime delivery. Close both independent decision review rounds, reconcile mutable phase pointers and retain the explicit maintainer acceptance boundary. ADR: 0064, 0036, 0040 * docs(decisions): resolve tenant authentication review gaps Make absent-credential masking, host-backed read admission and rejection attribution explicit before activation. Close JOSE and vendor diagnostic boundaries, disclose the full read-mode scope extension and preserve prior review receipts with dated finding dispositions rather than rewriting them. ADR: 0064, 0036, 0040, 0052 * docs(roadmap): record first authentication revision reviews Retain independent review evidence without treating it as acceptance. Make real-identifier checks explicit at the host-backed read boundary so an initialized wrapper cannot be mistaken for a valid tenant identity. ADR: 0064, 0036, 0040, 0052 * docs(roadmap): close authentication proposal revision reviews Record the second independent revision round and final document checks without treating reviewer approval as maintainer acceptance. Keep the original receipts and runtime boundary explicit before renewed approval. ADR: 0064, 0036, 0040, 0052 * docs(decisions): accept the tenant authentication boundary Record explicit maintainer acceptance before dependent runtime work. Disclose the bounded audit and exact read-mode changes in each affected ADR, correct row-10 staging through adjacent errata, and register the five proof obligations without claiming implementation evidence. ADR: 0064, 0036, 0040, 0052 * feat(kernel): add the isolated tenant token foundation Validate signed tenant credentials against the accepted closed profile and bound metadata retrieval before activating the HTTP authentication surface. Keep raw vendor failures out of enabled sinks while preserving closed application outcomes and unrelated diagnostics. ADR: 0064, 0036, 0032 * fix(kernel): keep metadata hosts out of native HTTP metrics Constrain native HTTP and DNS metric dimensions because request-local trace suppression does not prevent destination names reaching OTLP. Preserve duration and status signals, and prove the boundary with real retrieval, an unprojected control and a distinct hostname canary. ADR: 0064, 0032 * docs(roadmap): close both token foundation review rounds Record independent validation of the native metric privacy correction and keep the primary status carriers aligned before starting the real read-only application subject. ADR: 0064 * feat(tenancy): add the host-bounded read-only account query Expose only the caller's validated scope and the existing public site projection through an independently guarded application request. Select its physical read-only mode by one immutable exact-type declaration and share the existing transaction owner across API and Seeder composition. Prove actual app-role isolation, lifecycle visibility, audit Off behavior and SQL/EF write refusal before routing the request over HTTP. ADR: 0064, 0040, 0052, 0036 * docs(tenancy): record account query review and implementation Record both independent Step 2 first-round checks and reconcile the read-only standard with the implemented query before HTTP activation. ADR: 0064, 0040, 0052 * docs(roadmap): close both account query review rounds Record independent transaction, isolation and composition verification before starting attributed reconciliation and subject admission. ADR: 0064 * feat(kernel): attribute tenant refusals and add subject admission Carry validated identity through reconciliation without inventing audit tenants, and bound authenticated rejection work before recording. Preserve anonymous admission and keep production HTTP activation in the next step. ADR: 0064, 0036, 0033, 0044 * docs(roadmap): record the first admission review round Record independent checks of quota lifetime, attributed refusal and actual app-role audit behavior before the second review round. ADR: 0064 * fix(kernel): export actor UUIDs at rejection log boundaries Apply the identifier emission rule to both rejection log paths and pin the actual subject quota window independently. Close both Step 3 reviews with verified corrections and a planted default-window control. ADR: 0064, 0023 * docs(roadmap): wrap the admission closeout pointer Keep the current packet summary within the documentation prose convention. ADR: 0064 * feat(api): activate the closed tenant authentication boundary Bind strict bearer validation, host reconciliation and subject admission to one independently guarded read. Keep anonymous transport credential-free and qualify production routing, durable rejection attribution and generated public/authenticated contracts before widening the HTTP surface. ADR: 0064, 0036, 0040, 0052 Module: Tenancy * fix(api): document the early request body refusal The actual HTTP boundary rejects oversized GET bodies before authentication, but generated clients could not see that response. Require 413 in the served contract and negative controls while preserving the existing runtime outcome. ADR: 0064 * docs(roadmap): close both HTTP activation review rounds Record independent rechecks of the complete active boundary and its corrected contract before progressing to final production enforcement and qualification. ADR: 0064 * test(kernel): enforce closed tenant authentication authority Keep the activated authentication boundary dependent on its typed, validated identity and explicit production consumers. Prove missing, forged and mutable subjects fail the same complete census. Reconcile carrier contracts and catalogue owners without claiming pending CI. Make terminal-plan seed maintenance explicit so bitmap EXPLAIN counts measure live backlog rather than obsolete MVCC index entries. ADR: 0064 * fix(kernel): close alternate authentication authority paths Reject role metadata through its interface and positional identity extraction through generated deconstruction. Compiled negative controls reproduce each review gap before the detector correction. Reconcile the older job manifest's exact controller inventory with the approved AccountSite read and exercise its extra-action refusal. Align catalogue derivations and startup guidance with the active boundary. ADR: 0064 * fix(kernel): close identity exports and inherited role metadata Keep record formatting and alternate token APIs from bypassing the typed identity census. Bound acquisition and forwarding to the actual owners, and resolve authorization metadata through inheritance and interfaces. Compiled negative controls reproduce all three review gaps before the corrections; independent original probes confirm closure. Reconcile the remaining scalar-scope and membership reachability documentation. ADR: 0064 * docs(roadmap): close tenant API implementation and reviews Record all five completed steps, both independent review rounds and verified corrections while separating failed/as-of receipts from final PR-head qualification. Keep realm issuance, browser sessions and phase exit with their first consumers; start no next packet. ADR: 0064 * docs(roadmap): link tenant authentication review handoff Keep the live PR-head CI receipt discoverable from the local delivery record without treating an unmerged implementation as a merged packet. ADR: 0064 * docs(decisions): fix punctuation in ADR index summaries * docs(decisions): accept bounded tenant assertion diagnostics Accept the reviewed target-tenant audit allowance before dependent code. Disclose the loss of durable actor coverage and outbound destination metrics, preserve older decisions, and reconcile the proof owners. ADR: 0036, 0064, 0065 * fix(kernel): close tenant authentication review gaps Bind authentication and host authority to validated inputs, enforce the reviewed audit allowance, and strengthen the production censuses with load-bearing controls. Keep public transport and API configuration confined and reconcile the served OpenAPI and generated SDK contracts. ADR: 0036, 0040, 0052, 0064, 0065 Module: Tenancy, Kernel * docs(roadmap): record authentication review corrections Record verified dispositions, completed local populations and fresh independent reviews. Reconcile the shipped allowance and signal owners without borrowing historical CI receipts for the correction head. ADR: 0064, 0065 * fix(ci): retain closed public demo failure phases Preserve the first browser or worker phase across owned cleanup without exporting provider text. Exercise real worker connection refusal and primary/cleanup failures without changing proof budgets or retries. ADR: 0056, 0064 * fix(ci): recognize signalled browser startup exits Read Node's signal status alongside numeric exit status so a terminated browser is diagnosed without waiting for the startup deadline. Cover live, normal and signal status using actual child processes. ADR: 0056, 0064 * fix(ci): accept native child status in diagnostic types Describe only the process fields read by closed diagnostics. Compile-check real ChildProcess values and the operation callback in existing native child controls, while retaining unknown-field sanitization coverage. ADR: 0056, 0064 * docs(roadmap): record hosted authentication qualification Record complete source-bound backend receipts and the isolated demo refusal, with closed-diagnostic corrections and both fresh review rounds. Keep final-source hosted qualification explicit and mandatory. ADR: 0064, 0065 * docs(standards): Mark ADR-0065 diagnostic controls as implemented * fix(auth): close review privacy and proof gaps Enforce exemplar privacy, exact issuer/JWKS paths and worker process attribution. Strengthen production censuses, real persistence and HTTP controls, and SDK ownership proofs. Reconcile historical evidence and production activation ownership. ADR-0066 remains Proposed; subject-cap policy refinements await explicit approval. ADR: 0064, 0065 * fix(tests): close cross-assembly and middleware proof gaps Scan counter and header literals across all production assemblies. Inspect source-owned middleware and OpenAPI helper leaves before treating framework calls as terminals; plant real-wrapper and alias mutations. Record first-round findings, completed controls and exemplar correlation cost without claiming current-head hosted qualification. ADR: 0064, 0065 * fix(tests): reject hidden fluent middleware registrations Trace builder-valued receivers conservatively before skipping ordinary calls. Actual Program and resolver return mutations must expose chained extra authentication with a specific diagnostic; endpoint naming remains clean. Record round-two findings and the separate schema-proof limit. ADR: 0064 * docs(roadmap): record verified second review corrections Record both independent rounds, verified proof fixes and targeted recheck. Keep hosted qualification source-bound and ADR-0066 approval outstanding. ADR: 0064, 0065 * docs(decisions): clarify subject admission fault ownership Separate sticky cleanup failure from ordinary quota and capacity pressure. Specify one-disposal acquisition ordering, shared retirement ownership and unbounded disposal latency without claiming dependent runtime delivery. Mark mutable cap carriers as current code under a Proposed decision and name exact HTTP, metric, cleanup and concurrency proof obligations. ADR: 0066 * docs(decisions): complete admission retry contract inventory Record the first independent review round and explicitly include capacity retry-hint semantics in the future served and snapshot OpenAPI changes. Keep ADR-0066 Proposed and implementation proofs pending approval. ADR: 0066 * docs(roadmap): record subject admission revision reviews Record both fresh independent review rounds, the verified retry-contract inventory fix and current documentation/corpus validation. ADR-0066 stays Proposed and dependent runtime work still requires maintainer approval. ADR: 0066 * docs(decisions): accept bounded subject admission contract Record maintainer approval before dependent runtime changes. Preserve the Accepted ADR-0064/0065 bodies with adjacent attribution errata and their own dated disclosures, and align operational authorities with ADR-0066. Runtime, resource-bound and exported-signal proofs remain pending delivery. ADR: 0064, 0065, 0066 * feat(auth): own bounded subject admission cleanup Keep reclamation and failed resources under one singleton owner before allocation or debit, preserving existing quotas while exposing distinct capacity and cleanup-fault outcomes. Exercise the approved races, DI shutdown and exported signals with matching served and generated contracts. ADR: 0064, 0065, 0066 * fix(auth): preserve no-store on every subject refusal Apply the shared response policy even when a classified API path has no endpoint. Make missing-header assertions fail and bind the retirement timer to its accepted cadence so regression controls cannot pass silently. ADR: 0064, 0065, 0066 * docs(roadmap): close subject admission implementation reviews Record both fresh implementation review rounds and the verified header-proof corrections while keeping complete local and final-source hosted evidence under their own source identities. ADR: 0064, 0065, 0066 * fix(auth): close HTTP boundary proofs and receipt chronology Close composition and cross-root capability gaps in the existing authentication census. Preserve owned cleanup despite diagnostic faults, pin real reader and contract guards, and distinguish delivered status from historical acceptance receipts. ADR: 0036, 0040, 0041, 0052, 0064, 0065, 0066 * test(auth): close provider and anonymous metadata escape paths Extend the bounded filter census to effective provider composition and implemented anonymous contracts. Real DI and compiled metadata controls prevent unchanged filter options from hiding executable policy changes. ADR: 0064 * test(auth): pin effective action filters and authorization metadata Close supported MVC composition channels that can change effective filters or authorization without changing the global inventory or ordinary attributes. Pair exact runtime inventories with compiled dirty and restored controls. ADR: 0064 * docs(roadmap): close backend correction review rounds Record both independent rounds and targeted confirmation of the committed composition-proof fixes before starting the demo and SDK correction step. ADR: 0064, 0065, 0066 * fix(web): bind demo receipts and preserve failure ownership Keep local request refusal distinct from network failure and make demo receipts describe the actual process outcome and observed source. Bind both report files without relaxing browser budgets or cleanup ownership. ADR: 0053, 0054, 0056, 0064 * fix(web): retain the first owned demo failure Publish output refusal before physical shutdown and keep the same first daemon error for every observer. Classify native coordinator cancellation from its owned signal without replacing known faults or cleanup failures. ADR: 0056 * fix(web): observe failing native exits before output closure Keep the first native failure authoritative when paused or inherited output delays close, while successful capture and physical cleanup still retain their existing completion bounds. Real-child controls prove the failure ordering and preserve complete successful output. ADR: 0056, 0064 * fix(web): publish every unexpected daemon exit A daemon's zero exit is still an unexpected failure. Observe it apart from ordinary command success so delayed streams cannot replace the first daemon outcome, while complete command output remains required. ADR: 0056, 0064 * docs(roadmap): close systematic correction review rounds Record verified fixes and independent follow-up closure while keeping current-source hosted qualification separate from historical receipts, local checks, production activation and maintainer merge approval. ADR: 0056, 0064, 0065, 0066 * fix(ci): refresh architecture weights from complete hosted receipts A censored assignment colocated expensive serial controls and exhausted its existing deadline. Refresh only completed hosted selector costs, retain unknown estimates honestly, and require both final-source layouts without changing membership, topology, algorithm or time budgets. ADR: 0063, 0064 * docs(roadmap): close measured timing correction reviews Record both independent provenance and contract review rounds while requiring fresh complete A/B evidence for the revised timing plan. Clarify the existing distinction from ordinary future pushes without changing any execution or qualification policy. ADR: 0063, 0064 * fix(ci): require identified hosted timing sources Require non-null source and run identities for hosted TRX timing records. Keep historical local and console source shapes intact. Plant all three missing-identity combinations against the actual plan validator. ADR: 0063 * docs(roadmap): close provenance guard reviews Record both independent review rounds and keep historical plan qualification separate from the final-source full assignment required after the guard fix. ADR: 0063 * docs(roadmap): propose P02b-6 realm and seed decision package Define bounded development reconciliation and real identity proofs before closing the remaining realm and issuance-lifetime gates. Preserve account and secret ownership, separate provider timestamp semantics from configured lifespan, and retain explicit approval before implementation. ADR: 0004, 0036, 0064 * docs(roadmap): accept P02b-6 realm and seed decisions Record the maintainer's approval before changing identity issuance or existing development accounts. Register real-provider proof obligations and retain the independent session, authorization and production gates. ADR: 0004, 0036, 0064 * feat(identity): declare executable development realm identities Make development issuance satisfy the strict tenant API profile while keeping authentication personas in the typed seed declaration. Qualify the committed import through real confidential code/S256 flow, owned HTTPS and independent scope, lifetime and credential-refusal controls. ADR: 0004, 0036, 0064 * fix(identity): close realm and vocabulary review gaps Keep the existing G20 completeness fence aligned with every declared identity, and reject optional mapper paths that can replace protected claims. Preserve escaped literal keys and qualify implicit writers so export drift cannot hide behind default-only issuance evidence. ADR: 0004, 0036, 0064 * fix(identity): qualify client-role claim interpolation Close the remaining export drift blind spot while retaining the provider's safe built-in role path. Reconcile current guidance and record both completed Step 1 reviews before starting warm-realm implementation. ADR: 0004, 0036, 0064 * docs(roadmap): propose bounded server information read Record the measured stock response that exceeds the accepted universal body budget and propose one authenticated read exception. Keep implementation and complete-core qualification pending maintainer acceptance. ADR: 0004, 0064 * feat(identity): bound development realm transport and ownership Keep setup credentials on the selected local service and retain each request and lock through actual cleanup. These independent primitives retain the accepted 256 KiB bound; planner activation and its version-read proposal remain pending with the rest of Step 2. ADR: 0004, 0064 * docs(roadmap): compare authenticated version probe alternatives Record pinned-source analysis and isolated provider measurements for server information and read-only partial export. Keep the accepted 256 KiB transport cap and the proposed exception pending approval. ADR: 0004, 0064 * docs(roadmap): accept fixed server information response allowance Record maintainer approval after the measured alternative comparison. Keep ordinary responses, outbound bodies and all other ownership bounds unchanged. Dependent implementation and provider qualification follow. ADR: 0004, 0064 * fix(identity): confine server information response allowance Permit 512 KiB only on the fixed authenticated successful bodyless server-information GET. Keep every other response and outbound body at 256 KiB. Exercise exact bounds, closed resources and negative purposes. ADR: 0004, 0064 * feat(identity): reconcile owned development realm state safely Plan all bounded Admin REST changes before writes and independently verify preservation and convergence. Keep existing accounts, secrets, roles and unrelated configuration through warm and partial upgrades. Qualify the actual shared core on PostgreSQL-backed HTTPS Keycloak, including zero-write repeats and conflict refusals. Seed and demo activation remains the next step after both independent review rounds. ADR: 0004, 0036, 0064 * fix(identity): qualify stored identity visibility before reconciliation Admin user projections cannot establish that hidden identity values are absent. Refuse unqualified profiles and projected plan limits before any write, retaining account state and enforcing the same bounded readers on subsequent passes. ADR: 0004, 0036, 0064 * fix(identity): qualify inherited claims and preserve projected users Reject protected group aggregation and inherited identity sources before writes, retain safe group membership, and compare derived profile metadata separately from stored accounts. Real provider controls cover uninterrupted warm upgrades, nested groups, signed claim counterexamples and zero-write reruns. ADR: 0004, 0036, 0064 * docs(roadmap): close realm review and qualify account self-service Record the completed Step 2 correction reviews and the measured account-console capability gap. Keep the bounded role and fixed-account mapper proposal pending maintainer decision while the approved seed/demo lifecycle proceeds. ADR: 0004, 0036, 0064 * feat(identity): share realm convergence across seed and demo Validate private realm configuration before infrastructure work, build and run the argument-free Release Seeder with its own credential, and await one shared reconciler before public demo startup. Keep selected-stack identity and owned cancellation through setup, with credential-free build and renderer processes. ADR: 0004, 0036, 0064 * docs(roadmap): record first seed lifecycle review Keep the Step 3 receipt separate from actual Compose qualification and wrap the verified prose findings without changing its runtime contract. ADR: 0004, 0036, 0064 * fix(identity): confine seed preparation credentials Run selected stack and migration preparation under the seed owner so matching inherited Keycloak credentials never reach EF children. Retain Docker target controls with a fixed prerequisite allowlist and prove the old Makefile dependency path fails the same confinement control. ADR: 0004, 0036, 0064 * fix(identity): keep readiness under one seed owner Own PostgreSQL readiness directly rather than through a nested CLI whose detached Docker cleanup can outlive the preparation group. Prove cancellation and deadlines stop owned work, and that restoring the nested owner fails the same survival predicate. ADR: 0004, 0036, 0064 * test(identity): retain process absence witnesses in seed proofs Keep native process-group retirement evidence through both observation samples so reused IDs cannot be attributed to owned work. Close Step 3 with independent correction reviews and final runtime seed receipts. ADR: 0004, 0036, 0064 * feat(identity): qualify realm self-service and real token admission Keep development account access limited to the approved builtin role and mapper while proving protected identity fields against real Keycloak. Exercise issued credentials through the production API and retain owned provider teardown, physical read-only and complete CI discovery proofs. ADR: 0004, 0036, 0064 * fix(ci): require executed realm cases alongside JUnit reports An empty named Node suite can look like a passing JUnit case. Require actual counters from the same invocation and exercise the real workflow gate against empty-suite counterexamples. Retain measured provider case weights so complete CI assignments use observed advisory costs. ADR: 0004, 0063, 0064 * fix(tests): classify the offline realm gate control source Keep the repository source census closed while declaring the new Python counterexample helper as an exact offline test owner. Require the Node reporter to remain visible to the live runtime census and retain the completed Step 4 independent reviews and actual demo evidence. ADR: 0056, 0064 * docs(roadmap): close P02b-6 implementation and review steps Record actual provider and complete hosted backend evidence alongside the known frontend correction, promote the two delivered behavioural rules, and reconcile current carriers with all four reviewed implementation steps. Keep final PR-head qualification and merge explicitly separate. ADR: 0004, 0036, 0064 * docs(roadmap): identify the live PR qualification owner Keep the completed implementation status distinct from dynamic PR checks so the source-bound record does not imply a merge or stale test result. ADR: 0063, 0064 * fix(identity): preserve setup prerequisites and failure cleanup Retain tooling prerequisites without propagating application secrets, classify aborted transport failures and remove failed lock markers. Align finite seed preparation budgets and identity documentation with current development behavior. ADR: 0004, 0036, 0064 * docs(roadmap): record verified PR identity corrections Record the two independent correction reviews and distinguish current local evidence from the new-head hosted qualification. ADR: 0004, 0036, 0064 * fix(identity): reject false convergence and close proof gaps Refuse ambiguous account creation and incompatible login state before claiming convergence. Preserve credentials without replaying mutations, protect local setup sources, and independently verify provider identity, profile preservation and owned cleanup. Keep CI evidence bound to its actual attempt, distinguish missing receipts, and require the complete reviewed test and fixture populations. Retain failed qualification history instead of promoting partial reruns. ADR: 0003, 0004, 0018, 0063, 0064 * style: align correction whitespace Keep the fixture and dated verification prose within repository formatting conventions without changing executable behavior. ADR: 0004, 0064 * fix(identity): validate first reads and complete fixture census Reject unsafe selected sources before Compose can perform a blocking read. Bind fixture eligibility to actual declarations so qualified collections and other explicit fixtures cannot silently miss the independent-layout witness. Retain exact source-bound review receipts. ADR: 0063, 0064 * fix(identity): bind Docker preflight to the selected environment Inspect the same Docker inputs used by stack commands, including keys removed from inherited configuration. Reject collection-attribute aliases before fixture census filtering so they cannot silently narrow its proof. Retain counterfactual controls and source-bound independent reviews. ADR: 0063, 0064 * docs(roadmap): close independent correction reviews Record both completed review rounds and independent verification of the final alias and Docker-environment corrections. Keep hosted qualification with the frozen source and live PR checks rather than old passing runs. ADR: 0063, 0064 * fix(identity): keep seed authority generic and retain startup faults Bind legacy identities to their complete typed declarations instead of branching on demo usernames. Preserve existing finite provider startup faults in failed measurements without exporting raw error messages or changing execution and cleanup evidence requirements. Record the failed frozen-source run and its diagnostic limits. Keep all fixture, HTTP and whole-job deadlines unchanged. ADR: 0018, 0063, 0064 * docs(roadmap): record startup diagnosis correction reviews Record both independent rounds and exact local checks without promoting them to hosted qualification or inventing a provider startup cause. ADR: 0063 * test(identity): distinguish bounded provider startup failure families The actual hosted fixture reaches the database stage and reports the generic provider fault. Retain finite Docker status, reaper, socket and filesystem classifications without exposing provider messages or bodies. Do not infer a cause from the broader family or change startup budgets. ADR: 0063, 0064 * 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…
1 parent 935d8da commit 0dfade0

197 files changed

Lines changed: 22022 additions & 854 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/add-feature-gated-ui/SKILL.md‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ to a `mailto:` on Self-Hosted). All of this lives in
3030

3131
## When not to use
3232

33-
- Authorisation (permission checks). Those use `auth().permissions.includes(...)`,
34-
not feature flags.
33+
- Authentication or authorization. The current app-local
34+
`@/server/auth/auth` helper returns only a safe session projection, with no
35+
permissions/roles. Phase 03 owns permission-aware UI, backed by API enforcement;
36+
a feature flag never grants a permission.
3537
- Greying-out a feature instead of hiding. Three UI patterns the project picked:
3638
**hide** for missing features, **visualise** for limits, **block-then-link** for
3739
exceeded hard limits.
@@ -48,6 +50,13 @@ to a `mailto:` on Self-Hosted). All of this lives in
4850

4951
## Workflow
5052

53+
The hook/package examples below describe the Phase 06 entitlement-aware UI
54+
target, not exports in the current SDK. P02b-7 supplies session UI only; do not
55+
invent entitlement hooks, a permissions array or SSE transport while adding a
56+
session-protected page. Follow
57+
[add-frontend-route](../add-frontend-route/SKILL.md#step-5-authentication--permission-gating)
58+
for the implemented authentication boundary.
59+
5160
### Step 1: Feature gating with `useFeatureFlag`
5261

5362
```tsx

‎.claude/skills/add-frontend-route/SKILL.md‎

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ name: add-frontend-route
33
description: >
44
Add a Next.js App Router route under `frontend/apps/web/src/app/(public)/` /
55
`(studio)/` / `(portal)/` with the right route group, tenant + organization +
6-
locale resolution, Server Component default, permission guards (for studio /
7-
portal), and SDK-based data fetching. USE FOR: a new public page, Studio screen,
8-
or learner / instructor portal screen. DO NOT USE FOR: thin BFF proxy endpoints
9-
(those live in `app/api/`), routes for the operator portal (that's the separate
10-
`operator-portal` app), or hand-rolled `fetch` to the backend (use the typed
11-
SDK).
6+
locale resolution, Server Component default, the owning phase's permission
7+
guards, and admitted SDK-based data fetching. USE FOR: a new public page,
8+
Studio screen, or learner / instructor portal screen. DO NOT USE FOR: native
9+
BFF protocol changes or generic proxy endpoints, routes for the operator
10+
portal (that's the separate `operator-portal` app), or hand-rolled `fetch` to
11+
the backend (use the typed SDK).
1212
---
1313

1414
# Adding a frontend route
@@ -26,7 +26,6 @@ SDK contract per
2626
- A new public page (marketing / CMS-rendered).
2727
- A new Studio screen for tenant admin / org admin.
2828
- A new portal screen for learner / instructor.
29-
- A new BFF route handler under `api/` (rare; mostly auth callbacks).
3029

3130
## When not to use
3231

@@ -36,6 +35,8 @@ SDK contract per
3635
`frontend/packages/config/eslint/index.cjs`).
3736
- Routes that bypass tenant resolution — every authenticated route requires a
3837
resolved tenant.
38+
- Generic BFF proxies or a new authentication action. ADR-0070's auth protocol
39+
belongs to its native response owner; `app/api` currently contains only healthz.
3940

4041
## Inputs
4142

@@ -54,8 +55,8 @@ SDK contract per
5455
| Group | Purpose | Auth | Default render |
5556
|-------|---------|------|----------------|
5657
| `(public)` | Tenant public site (marketing, catalog, blog). | Anonymous by default; auth optional. | Dynamic SSR, no-store per ADR-0053; see Step 8. |
57-
| `(studio)` | Tenant admin Studio. | Tenant-admin or org-admin. Required at the edge. | SSR, no cache (always fresh). |
58-
| `(portal)` | Learner / instructor portal. | Membership in the resolved tenant. | SSR shell + Client Component for interactivity. |
58+
| `(studio)` | Current `/studio` account scaffold; future admin screens. | Native BFF session admission; permission-sensitive screens require Phase 03's real authorization. | SSR, no cache (always fresh). |
59+
| `(portal)` | Current `/portal` account scaffold; future learner/instructor screens. | Native BFF session admission; the current projection proves no membership or permission. | SSR shell + Client Component for interactivity. |
5960

6061
### Step 2: Create the route folder
6162

@@ -70,13 +71,15 @@ localized section names.
7071
```
7172
frontend/apps/web/src/app/
7273
(studio)/
73-
dashboard/
74-
users/
75-
page.tsx
76-
loading.tsx
77-
error.tsx
74+
studio/page.tsx
75+
(portal)/
76+
portal/page.tsx
7877
```
7978

79+
These exact paths are the current authenticated scaffold census. New screens
80+
need their owning phase's admission/authorization decision and matching route
81+
census controls; a route-group folder alone grants no access.
82+
8083
Use the `layout.tsx` already present in the route group; do not add a new layout
8184
unless the screen genuinely needs one.
8285

@@ -117,8 +120,10 @@ Rules:
117120

118121
- Default to Server Component. `"use client"` only when the screen needs hooks,
119122
browser APIs, or third-party client-only libs.
120-
- The SDK (`@learnstack/sdk/server`) is the **only** sanctioned way to call the
121-
API. Hand-rolled `fetch('/v1/...')` is blocked by lint.
123+
- Public pages use admitted resource loaders backed by `@learnstack/sdk/server`.
124+
The exact authenticated AccountSite caller stays in the native BFF owner;
125+
neither a page nor the SDK selects credentials, host or tenancy headers.
126+
Hand-rolled `fetch('/v1/...')` is blocked by lint.
122127
- Pass typed primitives across the RSC → Client boundary — no class instances, no
123128
closures.
124129

@@ -146,9 +151,11 @@ through bootstrap and the configured caller; Phase 11 owns participation/samplin
146151
**ADR-0054 native/URL controls delivered — 2026-10-09.**
147152
[The replacement contract](../../../docs/decisions/0054-bounded-public-renderer-admission.md)
148153
requires native GET/HEAD admission on every HTTP callback path, including
149-
middleware-exempt health/assets/scaffolds, with masked no-store refusal of other
150-
methods and bodyless HEAD. Production upgrades close; development retains only
151-
validated GET HMR. The [remediation record](../../../docs/roadmap/phase-02d-delivery-log.md#remediation-step-2--native-ingress-and-url-boundary)
154+
middleware-exempt health/assets/scaffolds. ADR-0070 adds POST only on exact
155+
`/api/auth/signin/keycloak`, `/api/auth/signout` and `/api/auth/extend`,
156+
with their closed Origin/CSRF/body controls. Other methods retain masked
157+
no-store refusal; HEAD remains bodyless. Production upgrades close; development
158+
retains only validated GET HMR. The [remediation record](../../../docs/roadmap/phase-02d-delivery-log.md#remediation-step-2--native-ingress-and-url-boundary)
152159
owns validation and both independent review rounds. Do not add
153160
Server Actions/write routes or WebSocket consumers without an explicit owning
154161
Phase 02b/Phase 06
@@ -159,33 +166,25 @@ accepted HTTPS port and local path select the destination.
159166

160167
### Step 5: Authentication + permission gating
161168

162-
Authentication below is the Phase 02b target, not current scaffold behavior.
163-
Today's exact `/studio` and `/portal` roots pass only after public host bootstrap;
164-
no sign-in/session helper is implemented. Phase 02b must explicitly admit its
165-
login/callback namespace before adding authenticated routes.
166-
167-
For those future `(studio)` and `(portal)` routes:
168-
169-
- Unauthenticated requests redirect through the accepted BFF/Keycloak sign-in flow.
170-
- A page-level permission check uses the future `auth()` helper:
171-
172-
```tsx
173-
import { auth } from "@learnstack/auth/server"; // illustrative: no such package exists yet; Phase 02b's session work owns the real helper
174-
import { redirect } from "next/navigation";
175-
176-
export default async function UsersPage() {
177-
const session = await auth();
178-
if (!session) redirect("/login");
179-
if (!session.permissions.includes("identity.user.read")) {
180-
redirect("/dashboard"); // or render a 403 UI
181-
}
182-
// ...
183-
}
184-
```
185-
186-
`auth()` reads from the HttpOnly cookie session set by the BFF; never touch tokens
187-
in a Client Component. The frontend permission check is **mirror-only** — the API
188-
is authoritative.
169+
P02b-7 implements the optional native BFF under
170+
[ADR-0070](../../../docs/decisions/0070-owned-tenant-bff-sessions.md).
171+
Host bootstrap precedes cookie/provider work. Disabled mode refuses auth paths
172+
with 404 and the exact `/studio` and `/portal` shells with 503. Enabled mode
173+
redirects anonymous shell requests to `/api/auth/signin` with a closed local
174+
return destination. Add no generic proxy or new auth action.
175+
176+
The app-local `auth()` is a passive safe projection lookup in the admitted native
177+
request; it does not parse cookies, refresh or mutate idle state. Layout and page
178+
consumers still check their own admission after awaits. Follow the actual
179+
[`components/auth/shell.tsx`](../../../frontend/apps/web/src/components/auth/shell.tsx)
180+
owner for those checks and the exact `/studio` or `/portal` return destination,
181+
rather than constructing a second authentication path in a page.
182+
183+
Never touch tokens in a Client Component. The projection has no permissions or
184+
roles. Phase 03 owns permission-based screens and their mirror-only UI checks;
185+
the API remains authoritative. Current shells grant no authoring capability.
186+
Use full document anchors, no-store responses and the protected history guard;
187+
do not introduce prefetch/Router Cache reuse for protected navigation.
189188

190189
### Step 6: Feature gating (entitlement-aware UI)
191190

@@ -222,7 +221,8 @@ export default async function CoursesPage() {
222221
```
223222

224223
Messages live in `frontend/apps/web/src/i18n/messages/<locale>/<namespace>.json`;
225-
P02d-6 supplies complete `en/public.json` and `tr/public.json`. General UI keys
224+
P02d-6 supplies complete `en/public.json` and `tr/public.json`; P02b-7 supplies
225+
`en/auth.json` and `tr/auth.json` through the same catalogue guard. General UI keys
226226
are dotted feature identifiers, distinct from backend `lockey_*` wire keys. The
227227
web app owns closed page-outcome mappings; the SDK supplies no translations.
228228
See [add-i18n-key](../add-i18n-key/SKILL.md).
@@ -236,8 +236,8 @@ authority. Only whole-catalogue fallback is allowed for unauthored UI languages;
236236
missing used keys in supported catalogues fail validation. Preserve exact content
237237
locale, document language and actual resolved-label language.
238238

239-
The guarded frontend suite supplies ICU, argument and callsite checks. No
240-
`lint:i18n` command or screenshot/axe tooling exists. The
239+
The guarded frontend suite supplies ICU, argument and callsite checks; there is
240+
no separate `lint:i18n` command. The full Playwright/axe suite belongs to Phase 06.
241241
[Step 1 delivery record](../../../docs/roadmap/phase-02d-delivery-log.md#p02d-6-step-1-localization-and-document-foundation)
242242
owns foundation validation; the
243243
[packet closeout](../../../docs/roadmap/phase-02d-delivery-log.md#p02d-6-packet-closeout-2026-10-10)
@@ -330,8 +330,10 @@ records passing production replacement proofs, completed reviews and verified fi
330330
which bans a direct `fetch` call outside the SDK.
331331
- The route renders under the resolved tenant/org/locale and rejects mismatched
332332
authn.
333-
- A `(studio)` route returns 403 when the actor lacks the required permission;
334-
the API was already authoritative — confirm.
333+
- Current `/studio` and `/portal` follow the native enabled/disabled session
334+
outcomes, with no authoring permission implied. Before adding a screen that
335+
requires permission, Phase 03's API authorization must refuse unauthorized work;
336+
a hidden button or successful session projection is insufficient.
335337
- The public-route budgets in
336338
[Performance Standards](../../../docs/standards/15-performance.md) hold on
337339
representative routes — judged by reading until CI's `lighthouse budget` job is
@@ -340,7 +342,8 @@ records passing production replacement proofs, completed reviews and verified fi
340342
## Common pitfalls
341343

342344
- **Mounting under the wrong route group.** Public institution routes are dynamic
343-
and no-store under ADR-0053; Studio/Portal authentication remains Phase 02b.
345+
and no-store under ADR-0053; exact Studio/Portal scaffolds use ADR-0070's native
346+
BFF session admission. Future screens do not inherit permission from that shell.
344347
- **Hand-rolled `fetch`.** Only the configured server adapter has an API transport
345348
exemption. Page consumers call its SDK; no second header setter is permitted.
346349
- **Reading `host` inside a page.** The API resolves authority. The native ingress

‎.claude/skills/add-i18n-key/SKILL.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,13 @@ frontend/apps/web/src/i18n/
7070
messages/
7171
en/public.json
7272
tr/public.json
73+
en/auth.json
74+
tr/auth.json
7375
```
7476

75-
P02d-6 supplies only `public`; later features add a namespace beneath each locale.
76-
`catalogues.ts` statically imports the two public files, and `request.ts` explicitly
77-
mounts them as `messages.public`. There is no automatic file discovery. JSON nesting
77+
P02d-6 supplies `public`; P02b-7 adds `auth`. `catalogues.ts` and
78+
`auth-catalogues.ts` statically import their complete en/tr files; `request.ts`
79+
explicitly mounts both namespaces. There is no automatic file discovery. JSON nesting
7880
supplies dotted identifiers: `public.catalog.course_count` is
7981
`catalog.course_count` within the `public` translator.
8082

@@ -141,7 +143,7 @@ same layout; they do not introduce an enrollment catalogue in P02d-6.
141143

142144
For a new namespace, adding JSON files is insufficient. Wire their static imports
143145
and locale map into `catalogues.ts`, mount the namespace in `request.ts`, and add
144-
its typed translator and callsite-census coverage. Do not pass a catalogue to a
146+
its typed translator and callsite-census coverage (`auth` uses typed `copy`). Do not pass a catalogue to a
145147
Client Component. For public keys with new ICU arguments, update
146148
`PublicMessageArguments` alongside the messages and their callsites.
147149

‎.claude/skills/code-review/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Walk every change against the project's
8484
| **Tenant id from the resolved context only** | Resolved per [ADR-0036](../../../docs/decisions/0036-tenant-resolution-trusted-inputs.md): from the host lookup of the effective host, or on a platform host from validated claims confirmed by live membership; off HTTP, from the validated authoritative job row or the integration-event envelope. Never from a request body, query string, cookie or tenant header — `X-Tenant-Id` and `X-Organization-Id` are assertions that can only reject, on every hop. Check command and DTO surfaces. |
8585
| **SQL injection** | EF Core LINQ or `FromSqlInterpolated`; never raw string concatenation. Raw SQL has parameters. |
8686
| **XSS** | No `dangerouslySetInnerHTML` outside a sanitisation wrapper; CSP nonces in place; markdown via allowlist. Nothing sets a CSP today: the [standards index](../../../docs/standards/README.md#honest-status-today) row for Security Standards carves § HTTP Headers out to [Phase 11](../../../docs/roadmap/phase-11-production-hardening.md#security), so a missing nonce is not a Blocker until that phase sets one. Accepted P02d-6 G42 requires atomic four-color validation and a fixed style element, with whole-palette fallback; output must be safe without CSP. [The accepted package](../../../docs/roadmap/phase-02d-delivery-log.md#p02d-6-accepted-answers) owns its proof obligations; acceptance alone is not delivery. |
87-
| **CSRF** | Server Actions / Auth.js session check; non-Action mutating fetches carry CSRF tokens. |
87+
| **CSRF** | ADR-0070's closed BFF POSTs require the exact verified Origin and explicit CSRF proof; OIDC callbacks require their bound state/nonce/PKCE transaction. Server Actions remain unadmitted until their owning phase authorizes them. |
8888
| **Secrets** | No secret in source / appsettings / env-file-committed; reads through `ISecretProvider`. No log of token / password / national id. |
8989
| **PII redaction** | `[PiiSensitive]` fields carry `SensitiveTokenCatalog.RedactedValue` in audit snapshots — the property stays, so the diff still records *that* it changed; logs don't carry raw PII. |
9090
| **File upload** | MIME sniff + extension allowlist + size limit + EXIF strip + tenant-scoped key. |

‎.env.example‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ KEYCLOAK_ADMIN_PASSWORD=admin-dev-secret
7373
# reconciliation verifies an existing confidential secret and never rotates it.
7474
# Never pass this value to the API, public renderer or .NET Seeder.
7575
KEYCLOAK_WEB_CLIENT_SECRET=learnstack-web-dev-secret
76+
# Optional native tenant BFF (ADR-0070). Explicit false keeps the anonymous demo
77+
# independent of Keycloak. For local watch mode, opt in with true and the issuer
78+
# below; production launch requires an HTTPS issuer and a trusting private CA.
79+
# All present root/web/process values must agree. Private source files are 0600.
80+
LEARNSTACK_BFF_ENABLED=false
81+
# LEARNSTACK_BFF_ISSUER=http://localhost:8080/realms/learnstack
7682

7783
# ─── Vault (-dev mode; token shared with Dapr secret-store component) ────
7884
# Boots the `vault` compose service via `-dev-root-token-id` AND is passed

‎.github/workflows/ci.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ jobs:
289289
working-directory: frontend
290290
run: pnpm install --frozen-lockfile
291291

292+
- name: Compile native web and authenticated SDK fixture entries
293+
working-directory: frontend
294+
run: pnpm --filter @learnstack/web build:ingress
295+
292296
- name: Prepare pinned provider fixture images within the whole-job budget
293297
timeout-minutes: 2
294298
run: python3 scripts/ci-test-shards.py prepare-fixtures

‎CLAUDE.md‎

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,10 @@ repository holds only LearnStack's side of the boundary, in
4040
## What state this is in
4141

4242
**Phase 01, Phase 02a and Phase 02d are complete; Phase 02b is the live phase.**
43-
[Phase 02d](docs/roadmap/phase-02d-walking-skeleton.md), the two-tenant walking
44-
skeleton and the first user-visible milestone, merged through PR #28 on
45-
2026-10-11: two hosts, two tenants, two education sites, one binary and one
46-
database. In [Phase 02b](docs/roadmap/phase-02b-events-auth.md), P02b-0 through
47-
P02b-5 are complete and P02b-1–5 merged through PRs #29–#33 — transactional event
48-
production, durable dispatch, subscriber delivery, background jobs and tenant API
49-
authentication — and P02b-6's realm and identity implementation is merged through
50-
PR #34, with post-merge CI corrections continuing on `development`. P02b-7 (BFF
51-
session) and P02b-8 (exit enforcement) are pending, and G13's session part stays
52-
Open, so browser sign-in is not implemented. Phase 06 retains the full
43+
[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.
46+
[Phase 06](docs/roadmap/phase-06-renderer-admin-studio.md) owns the full
5347
renderer/Studio expansion.
5448

5549
**Status lives in one place.** Each phase document's Status block owns packet

0 commit comments

Comments
 (0)