TenantAtlas/specs/285-workspace-rbac-environment-access/plan.md
ahmido c7b38606a9 feat: implement spec 285 workspace-first environment access (#344)
Implements platform feature branch `285-workspace-rbac-environment-access`.

Summary:
- switch managed environment authorization to workspace-first role resolution with explicit environment-scope narrowing
- rewire Filament pages, resources, policies, and user tenant access helpers to the shared access-scope resolver
- add Spec 285 coverage across unit, feature, and browser tests plus full spec artifacts

Validation:
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Auth/WorkspaceFirstCapabilityResolverTest.php tests/Unit/Auth/ManagedEnvironmentAccessScopeResolverTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Auth/WorkspaceFirstManagedEnvironmentAccessTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Filament/WorkspaceMembershipRoleManagementTest.php tests/Feature/Rbac/GovernanceArtifactsWorkspaceFirstAuthorizationTest.php tests/Feature/Rbac/OperationRunWorkspaceFirstAuthorizationTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Verification/ProviderExecutionReauthorizationTest.php tests/Feature/ProviderConnections/ProviderConnectionHealthCheckStartSurfaceTest.php tests/Feature/Tenants/TenantProviderBackedActionStartTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Audit/TenantMembershipAuditLogTest.php tests/Feature/Filament/TenantMembersTest.php tests/Feature/TenantRBAC/TenantMembershipCrudTest.php tests/Feature/TenantRBAC/TenantSwitcherScopeTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

Target branch: `platform-dev`.

Follow-up integration path after merge:
- `platform-dev` -> `dev`.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #344
2026-05-09 12:40:50 +00:00

26 KiB

Implementation Plan: Workspace-first RBAC & Environment Access Scoping

Branch: 285-workspace-rbac-environment-access | Date: 2026-05-09 | Spec: spec.md Input: Feature specification from specs/285-workspace-rbac-environment-access/spec.md

Summary

Prepare the reserved workspace-first RBAC slice by collapsing the current dual authorization model into one workspace-first access contract. The implementation path keeps workspace_memberships as the sole role-bearing truth, replaces role-bearing ManagedEnvironmentMembership semantics with a narrow managed-environment access-scope overlay, retargets CapabilityResolver, WorkspaceContext, User::canAccessTenant(), and the key environment-owned policies to that contract, and migrates the current tenant-membership management surface so it no longer edits a second role system.

This plan is intentionally narrow. Filament remains v5 on Livewire v4, provider registration remains in apps/platform/bootstrap/providers.php, ProviderConnectionResource remains non-globally-searchable, destructive membership actions stay server-authorized and confirmation-protected, and provider capability or source-taxonomy work from Specs 283 and 284 stays separate. Implementation should start only when Specs 280, 281, and 283 are present on the runtime branch.

Inherited Baseline / Explicit Delta

Inherited baseline

  • apps/platform/app/Models/WorkspaceMembership.php, WorkspaceMembershipManager, WorkspaceMembershipPolicy, WorkspaceRole, and WorkspaceCapabilityResolver already provide workspace-scoped role truth, audit logging, and last-owner protection.
  • apps/platform/app/Models/ManagedEnvironmentMembership.php, TenantMembershipManager, TenantRole, RoleCapabilityMap, and CapabilityResolver still carry a second environment-scoped role truth.
  • apps/platform/app/Models/User.php still treats managed-environment memberships as the source for Filament tenant access, default tenant selection, and canAccessTenant().
  • apps/platform/app/Support/Workspaces/WorkspaceContext.php already treats workspace membership as the first shell boundary but still delegates managed-environment access to User::canAccessTenant().
  • apps/platform/app/Policies/ProviderConnectionPolicy.php, OperationRunPolicy.php, FindingPolicy.php, EvidenceSnapshotPolicy.php, ReviewPackPolicy.php, and TenantReviewPolicy.php all enforce workspace and managed-environment access differently.
  • apps/platform/app/Filament/Resources/TenantResource/Pages/ManageTenantMemberships.php and TenantMembershipsRelationManager.php currently expose managed-environment membership CRUD with role selectors.
  • apps/platform/app/Support/Operations/OperationRunCapabilityResolver.php already distinguishes workspace-owned and environment-owned capabilities, and ProviderOperationStartGate from Spec 283 is expected to remain the downstream provider-capability gate after local RBAC passes.

Explicit delta in this plan

  • Make workspace membership the only role-bearing access authority for workspace-owned and managed-environment-owned surfaces.
  • Replace the current role-bearing meaning of ManagedEnvironmentMembership with a narrow access-scope overlay contract. Whether the implementation keeps the current table name or renames it in place is a bounded implementation choice; dual-write or fallback semantics are forbidden.
  • Rework CapabilityResolver so it resolves the current role from workspace membership and uses managed-environment scope only for visibility narrowing.
  • Rework User::canAccessTenant(), User::getTenants(), and WorkspaceContext so environment accessibility follows the same workspace-first contract.
  • Retarget key policies and Filament access gates to use that contract consistently.
  • Migrate the current tenant-membership UI into workspace role management plus managed-environment scope management so operators can no longer assign roles in two places.
  • Keep provider capability, route-shell, and taxonomy prerequisites explicit instead of silently absorbing them.

Technical Context

Language/Version: PHP 8.4.15, Laravel 12.52
Primary Dependencies: Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, existing auth resolvers, policies, and Filament relation-manager surfaces
Storage: PostgreSQL, reusing existing membership persistence rather than adding a new table
Testing: Pest unit tests, Pest feature tests, and one Pest browser smoke
Validation Lanes: fast-feedback, confidence, browser
Target Platform: Laravel monolith in apps/platform
Project Type: web application
Performance Goals: preserve request-local auth caching and avoid N+1 membership or scope queries on representative environment-owned lists, run lists, and bulk-authorization preflight
Constraints: no /system RBAC redesign, no new role family, no mandatory environment-level ACL product, no provider-boundary work from Specs 281 to 284, no copy/localization work from Spec 286, no no-legacy guardrail pack from Spec 287, no compatibility shim or dual-write path
Scale/Scope: one workspace-first authorization cutover over the existing admin panel, managed-environment selection, membership management, and environment-owned policies

Likely Affected Repo Surfaces

  • apps/platform/app/Models/User.php
  • apps/platform/app/Models/WorkspaceMembership.php
  • apps/platform/app/Models/ManagedEnvironmentMembership.php or its in-slice successor
  • apps/platform/app/Filament/Resources/TenantResource.php
  • apps/platform/app/Filament/Resources/Workspaces/WorkspaceResource.php
  • apps/platform/app/Filament/Resources/ProviderConnectionResource.php
  • apps/platform/app/Services/Auth/WorkspaceCapabilityResolver.php
  • apps/platform/app/Services/Auth/CapabilityResolver.php
  • apps/platform/app/Services/Auth/WorkspaceMembershipManager.php
  • apps/platform/app/Services/Auth/TenantMembershipManager.php or its in-slice successor
  • apps/platform/app/Support/Workspaces/WorkspaceContext.php
  • apps/platform/app/Policies/ProviderConnectionPolicy.php
  • apps/platform/app/Policies/OperationRunPolicy.php
  • apps/platform/app/Policies/FindingPolicy.php
  • apps/platform/app/Policies/EvidenceSnapshotPolicy.php
  • apps/platform/app/Policies/ReviewPackPolicy.php
  • apps/platform/app/Policies/TenantReviewPolicy.php
  • apps/platform/app/Policies/TenantOnboardingSessionPolicy.php
  • apps/platform/app/Filament/Resources/TenantResource/Pages/ManageTenantMemberships.php
  • apps/platform/app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php
  • apps/platform/app/Filament/Resources/Workspaces/RelationManagers/WorkspaceMembershipsRelationManager.php
  • apps/platform/app/Support/Operations/OperationRunCapabilityResolver.php
  • apps/platform/app/Support/Tenants/TenantInteractionLane.php and TenantOperabilityService only if environment scope needs one shared access question instead of duplicated page-local checks
  • representative proof files under apps/platform/tests/Unit/Auth/, apps/platform/tests/Feature/Auth/, apps/platform/tests/Feature/Rbac/, apps/platform/tests/Feature/Filament/, and apps/platform/tests/Browser/

Filament v5 / Capability Surface Notes

  • Livewire v4.0+ compliance: all touched Filament work remains on Filament v5 with Livewire v4.
  • Provider registration location: provider registration stays in apps/platform/bootstrap/providers.php; nothing moves to bootstrap/app.php.
  • Global search rule: ProviderConnectionResource remains non-globally-searchable; touched searchable resources such as TenantResource and WorkspaceResource keep existing valid View destinations and must not gain broken search links.
  • Destructive actions: workspace membership and managed-environment scope removals remain ->action(...) plus ->requiresConfirmation() and server-side authorization. No URL-only destructive affordance is introduced.
  • Asset strategy: no new asset registration or filament:assets behavior is introduced.

Workspace-first Access Contract Fit

  • Keep one canonical access decision shape for environment-owned surfaces:
    • workspace_role
    • workspace_member
    • managed_environment_allowed
    • failed_boundary when access is denied
    • required_capability
    • capability_allowed
    • provider_capability_context only as an optional downstream note after local RBAC passes
    • downstream provider-capability or operability outcome where applicable
  • Keep the default environment-access rule explicit: no scope rows means inheritance across the currently selectable managed environments in the workspace; explicit scope rows mean allowlist narrowing only.
  • Keep managed-environment scope subordinate to workspace membership. No scope row may grant access to a user who lacks workspace membership.
  • Keep role-to-capability mappings derived from one workspace role value. Reusing the current capability constants is in scope; inventing a new role family is not.
  • Keep current provider capability and operability checks downstream. This slice determines whether local RBAC allows the request to proceed to those deeper checks.
  • Keep denied-access diagnostics derived from the shared access decision only. Boundary-safe logs may capture workspace, managed environment, failed boundary, and required capability, but they must not expose raw provider payloads or secrets.

UI / Surface Guardrail Plan

  • Guardrail scope: changed surfaces
  • Native vs custom classification summary: native Filament relation managers plus shared shell/context logic
  • Shared-family relevance: membership management, managed-environment selection, related drilldowns, and page access guards
  • State layers in scope: shell, page, relation manager, modal, remembered context, URL-query
  • Audience modes in scope: operator-MSP, support-platform
  • Decision/diagnostic/raw hierarchy plan: workspace role decision first, managed-environment scope second, deeper diagnostics only when access is denied or narrowed
  • Raw/support gating plan: audit history and raw identifiers stay secondary; debug semantics do not become primary page copy
  • One-primary-action / duplicate-truth control: workspace membership surfaces manage roles; managed-environment scope surfaces manage visibility only; the shell uses one shared access outcome instead of repeating different denial stories on each page
  • Handling modes by drift class or surface: review-mandatory
  • Repository-signal treatment: review-mandatory until all in-scope policies and selection APIs converge on the same access contract
  • Special surface test profiles: standard-native-filament, global-context-shell, shared-detail-family
  • Required tests or manual smoke: functional-core, state-contract, browser-smoke
  • Exception path and spread control: none; any temporary alias or duplicate role editor becomes a blocker or explicit split
  • Active feature PR close-out entry: Guardrail

Shared Pattern & System Fit

  • Cross-cutting feature marker: yes
  • Systems touched: workspace membership management, managed-environment scope management, environment selection, environment-owned page policies, and run drilldowns
  • Shared abstractions reused: WorkspaceCapabilityResolver, CapabilityResolver, WorkspaceContext, OperationRunCapabilityResolver, WorkspaceMembershipManager, and the existing Filament relation-manager patterns
  • New abstraction introduced? why?: one unified workspace-first access-decision path is expected because the repo currently has two partially overlapping resolver stacks
  • Why the existing abstraction was sufficient or insufficient: the current abstractions already own caching, capability checks, and membership queries, but they are split by workspace versus environment truth and therefore cannot answer one canonical access question today
  • Bounded deviation / spread control: no bounded exception is planned; implementation should replace, not wrap, the duplicated role-bearing environment path

OperationRun UX Impact

  • Touches OperationRun start/completion/link UX?: yes
  • Central contract reused: OperationRunCapabilityResolver, OperationRunPolicy, and the current provider-operation start path for downstream provider gating
  • Delegated UX behaviors: workspace-bound versus environment-bound run access, required capability lookup, and downstream provider gating remain delegated to the shared run auth seams
  • Surface-owned behavior kept local: existing run links and monitoring surfaces stay local; only the access decision changes
  • Queued DB-notification policy: N/A
  • Terminal notification path: existing central lifecycle mechanism
  • Exception path: none

Provider Boundary & Portability Fit

  • Shared provider/platform boundary touched?: no
  • Provider-owned seams: N/A
  • Platform-core seams: N/A
  • Neutral platform terms / contracts preserved: downstream provider capability inputs from Spec 283 remain provider-neutral and unchanged
  • Retained provider-specific semantics and why: N/A
  • Bounded extraction or follow-up path: N/A

Constitution Check

GATE: Must pass before implementation begins and again after design artifacts are complete.

  • Inventory-first / snapshot truth: PASS. The slice changes local authorization only.
  • Read/write separation: PASS. Membership and scope mutations are DB-only and audit-backed; no new remote write flow is introduced.
  • Graph contract path: PASS. No new Graph calls are introduced.
  • Deterministic capabilities: PASS with implementation condition. Capability results for environment-owned pages must be derivable from workspace role plus explicit scope plus existing capability constants.
  • RBAC-UX plane separation: PASS. /admin versus /system remains unchanged.
  • Workspace isolation: PASS. Workspace membership becomes the canonical first boundary.
  • Managed-environment isolation: PASS. Managed-environment access remains explicit, but only as a narrowing overlay.
  • Destructive action discipline: PASS by preservation. Membership and scope removals remain confirmation-protected.
  • Global search safety: PASS with implementation condition. Searchable resources touched by the cutover must still honor deny-as-not-found for inaccessible environments.
  • OperationRun / Ops-UX: PASS. The feature reuses existing run access seams.
  • Data minimization: PASS. No new persistence is added.
  • Test governance: PASS. Proof stays bounded to unit, feature, and one browser smoke.
  • Proportionality / no premature abstraction: PASS with implementation condition. The access-decision path must replace the split model rather than sit beside it.
  • Persisted truth / behavioral state: PASS. No new persisted truth or state family is required.
  • UI semantics / shared pattern first / Filament-native UI: PASS. Existing native relation managers and shared shell contracts remain the primary surfaces.
  • Provider boundary: PASS. The slice consumes provider capability context but does not redefine provider/platform boundaries.

Gate evaluation: PASS for artifact quality, with explicit external prerequisites from Specs 280, 281, and 283.

Post-design re-check: PASS when research.md, data-model.md, quickstart.md, contracts/workspace-rbac-environment-access.logical.openapi.yaml, tasks.md, and checklists/requirements.md keep the same workspace-first role truth, optional scope-overlay rule, and proof commands.

Test Governance Check

  • Test purpose / classification by changed surface: Unit, Feature, Browser
  • Affected validation lanes: fast-feedback, confidence, browser
  • Why this lane mix is the narrowest sufficient proof: resolver and scope inheritance belong in unit tests; policy and Filament access behavior belong in feature tests; one browser smoke proves real shell and membership-surface continuity
  • Narrowest proving command(s):
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Unit/Auth/WorkspaceFirstCapabilityResolverTest.php tests/Unit/Auth/ManagedEnvironmentAccessScopeResolverTest.php)
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Feature/Auth/WorkspaceFirstManagedEnvironmentAccessTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Rbac/OperationRunWorkspaceFirstAuthorizationTest.php tests/Feature/Rbac/GovernanceArtifactsWorkspaceFirstAuthorizationTest.php tests/Feature/Filament/WorkspaceMembershipRoleManagementTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php)
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php)
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail bin pint --dirty --format agent)
  • Fixture / helper / factory / seed / context cost risks: moderate because proof needs workspace memberships, explicit environment-scope rows, managed environments, and representative environment-owned records without widening global test defaults
  • Expensive defaults or shared helper growth introduced?: no; any new helper should stay feature-local and opt-in
  • Heavy-family additions, promotions, or visibility changes: none beyond one bounded browser smoke
  • Surface-class relief / special coverage rule: standard-native-filament relief for relation-manager CRUD, plus one global-context-shell smoke for access continuity
  • Closing validation and reviewer handoff: rerun the commands above, verify no policy still uses a role-bearing environment membership path, verify managed-environment scope rows cannot outlive or bypass workspace membership, verify the current tenant-membership surface no longer edits roles, verify representative environment-owned lists, run lists, and bulk-authorization preflight stay query-bounded under the shared contract, verify touched searchable resources do not leak inaccessible environments through search results, verify denied-access logging remains diagnosable without raw provider detail, and verify run access still distinguishes workspace-bound versus environment-bound runs correctly
  • Budget / baseline / trend follow-up: contained feature-local increase only
  • Review-stop questions: did the implementation keep dual role authority, did it introduce a new role family, did environment scope become a second ACL product, did it widen into route or provider taxonomy work, did any shell access path skip the shared contract
  • Escalation path: document-in-feature for bounded migration notes only; reject-or-split if dual truth remains
  • Active feature PR close-out entry: Guardrail
  • Why no dedicated follow-up spec is needed: the remaining adjacent concerns are already tracked as Specs 284, 286, and 287

Review Checklist Status

  • Review checklist artifact: checklists/requirements.md
  • Review outcome class: blocked-by-prerequisites
  • Workflow outcome: keep
  • Test-governance outcome: keep
  • Readiness note: runtime work remains externally gated on Specs 280, 281, and 283 being present on the implementation branch

Rollout Considerations

  • Land the workspace-first access resolver and the policy retargeting atomically so pages do not alternate between old and new access semantics.
  • Move the membership-management surface split in the same slice as the resolver change so operators cannot keep editing a second role authority after the backend cutover.
  • Keep environment scope opt-in and narrow from the start; otherwise the feature could accidentally hard-require scope rows for all members.
  • Preserve downstream provider capability and operability gates as-is; this slice should stop once local RBAC says the request may proceed.

Risk Controls

  • Reject any implementation that leaves role-bearing capability checks on ManagedEnvironmentMembership.
  • Reject any implementation that introduces dual-write or fallback reads between workspace and environment role truth.
  • Reject any implementation that adds a second role selector to the environment-scope surface.
  • Reject any implementation that makes environment scope mandatory for all workspace members.
  • Reject any implementation that widens into provider-capability, route-shell, source-taxonomy, copy/localization, or guardrail-pack work reserved for adjacent specs.

Research & Design Outputs

  • research.md records the repo-truth decisions, the scope-overlay rule, and the rejected alternatives.
  • data-model.md captures the canonical workspace role truth, the logical environment-scope overlay, and the shared access-decision payloads.
  • quickstart.md gives reviewers the preconditions, bounded validation flow, and exact commands.
  • contracts/workspace-rbac-environment-access.logical.openapi.yaml models the logical workspace membership summary, managed-environment access decision, and run-access decision payloads.
  • checklists/requirements.md records package readiness, boundedness, and the prerequisite note.

Project Structure

Documentation (this feature)

specs/285-workspace-rbac-environment-access/
├── checklists/
│   └── requirements.md
├── contracts/
│   └── workspace-rbac-environment-access.logical.openapi.yaml
├── data-model.md
├── plan.md
├── quickstart.md
├── research.md
├── spec.md
└── tasks.md

Source Code (expected implementation surfaces)

apps/platform/
├── app/
│   ├── Filament/
│   │   └── Resources/
│   │       ├── TenantResource/
│   │       │   ├── Pages/
│   │       │   │   └── ManageTenantMemberships.php
│   │       │   └── RelationManagers/
│   │       │       └── TenantMembershipsRelationManager.php
│   │       └── Workspaces/
│   │           └── RelationManagers/
│   │               └── WorkspaceMembershipsRelationManager.php
│   ├── Models/
│   │   ├── User.php
│   │   ├── WorkspaceMembership.php
│   │   └── ManagedEnvironmentMembership.php
│   ├── Policies/
│   │   ├── ProviderConnectionPolicy.php
│   │   ├── OperationRunPolicy.php
│   │   ├── FindingPolicy.php
│   │   ├── EvidenceSnapshotPolicy.php
│   │   ├── ReviewPackPolicy.php
│   │   ├── TenantReviewPolicy.php
│   │   └── TenantOnboardingSessionPolicy.php
│   ├── Services/
│   │   └── Auth/
│   │       ├── WorkspaceCapabilityResolver.php
│   │       ├── CapabilityResolver.php
│   │       ├── WorkspaceMembershipManager.php
│   │       └── TenantMembershipManager.php
│   └── Support/
│       ├── Operations/
│       │   └── OperationRunCapabilityResolver.php
│       └── Workspaces/
│           └── WorkspaceContext.php
└── tests/
    ├── Browser/
    ├── Feature/
    │   ├── Auth/
    │   ├── Filament/
    │   └── Rbac/
    └── Unit/
        └── Auth/

Structure Decision: keep the documentation package self-contained under specs/285-workspace-rbac-environment-access/; later runtime work should modify the existing auth, policy, model, and Filament seams directly in apps/platform/ instead of adding a parallel RBAC subsystem.

Complexity Tracking

Violation Why Needed Simpler Alternative Rejected Because
Canonical replacement of existing role-bearing environment membership semantics The current codebase already has duplicate role truth and cannot satisfy workspace-first tenancy without replacing one side Synchronizing two role-bearing stores would add more compatibility logic and preserve the drift
One unified workspace-first access-decision path Multiple policies and selection APIs need one shared answer for workspace membership plus environment scope Page-local helpers would keep drift and inconsistent 404/403 semantics

Proportionality Review

  • Current operator problem: the current product answers one authorization question from two role-bearing truth sources, which causes inconsistent page access, duplicated operator administration, and workspace-first cutover drift.
  • Existing structure is insufficient because: the repo already contains both WorkspaceCapabilityResolver and environment-scoped CapabilityResolver, but they currently resolve different role sources and cannot guarantee one shared answer for user access, context selection, policy checks, search visibility, and run drilldowns.
  • Narrowest correct implementation: retarget the existing shared auth seams so workspace membership is the only role-bearing truth and managed-environment scope becomes narrowing-only, instead of adding a third resolver family, a new role catalog, or a new persistence layer.
  • Ownership cost created: auth services, user helpers, context helpers, policies, relation managers, audits, and the bounded proof suite all need coordinated changes, but the cost is bounded because the slice removes duplicate semantics instead of adding another permanent subsystem.
  • Alternative intentionally rejected: keeping role-bearing managed-environment memberships and synchronizing them with workspace memberships. That would preserve the current ambiguity and add more compatibility logic to a pre-production codebase.
  • Release truth: current-release truth