Skip to content

ADR 0031: Git-Native Process CodeRepositoryBranch Context

Date: 2026-08-22

Status: Accepted and implemented; aligned with platform ADR-046 for the immediate CodeRepository cutover

Partially superseded by ADR 0035: Independent Git source and platform execution context, accepted and implemented on metatables_removal. Network-free source discovery removes mandatory platform enrichment for local Git facts. Missing Environment errors are deferred to operations that require one; Environment scope remains derived from the registered current branch. Canonical Git facts, source drift checks, runtime target verification, and real branch-owned operation guards remain in force. ADR 0034 separately removes the historical MetaTables/DataSource implementation described in this record.

Current contract: CodeRepository, CodeRepositoryBranch, and GitHubRepositoryBinding are the canonical public names. The Project-era SDK ontology is retired and must not be reintroduced.

Context

Application code runs in local checkouts and platform-built runtime images. The SDK previously used two identity mechanisms: local .env plus Git for developer work, and authenticated CodeRepositoryBranch values projected into process environment for deployed work. That split allowed source identity to depend on mutable configuration even though both locations execute a Git checkout.

Platform ADR-0037 makes the checked-out Git repository the single source of truth for repository, branch, and commit identity. Runtime authorization remains backend-owned and target-derived; Git identity never grants permission.

Ontology

Concept Responsibility
Git worktree Identifies the repository, attached branch/ref, and exact commit executed by this process
GitHubRepositoryBinding Maps canonical Git repository identity to the logical platform CodeRepository
CodeRepository Repository-level platform aggregate; it does not authorize a branch or Environment
CodeRepositoryBranch Persisted platform identity for the exact CodeRepository and Git branch
OrganizationEnvironment Environment derived from the resolved CodeRepositoryBranch
CodeRepositoryBranch.metatables_data_source Optional physical MetaTables DataSource for that exact branch
Runtime credential or human token Authenticates and authorizes the caller; it does not select source identity

Decision

Superseded in part by ADR 0035: source-only callers use get_git_source_context() without platform enrichment. The original composition entry point below remains available.

The original decision defined one CodeRepository-context entry point:

from mainsequence.code_repository_context import get_code_repository_context

get_code_repository_context()

It uses the same algorithm in a local shell, CLI process, Job, supported ResourceRelease, runtime-agent release, or CodeRepository Executor:

containing Git worktree
  -> canonical non-secret repository identity
  -> attached refs/heads/<branch>
  -> exact full HEAD commit
  -> backend resolve-git-context contract
  -> GitHubRepositoryBinding
  -> CodeRepository
  -> exact CodeRepositoryBranch
  -> OrganizationEnvironment
  -> optional CodeRepositoryBranch MetaTables DataSource

Authentication mode affects credentials only. The resolver does not choose a local or deployed identity path.

Frozen source snapshot

The first call resolves and freezes:

repository_root
canonical_repository_identity
repository_branch
repository_ref
commit_sha
code_repository_uid | None
code_repository_branch_uid | None
organization_environment_uid | None
metatables_data_source | None
status
process_id

Initialization is protected by a process-local lock. Concurrent callers receive the identical immutable object. Resolution errors are cached. A forked child discards inherited state and resolves once for its own process.

A deliberate git switch takes effect in the next process. Later validation in the same process rejects a changed repository, branch, or HEAD as source-context drift; it does not silently retarget platform work.

Valid unresolved states

ADR 0035 removes the branch prerequisite for Environment-owned resources. The historical paragraph below remains applicable only to branch-owned targets.

Resolution itself does not fail merely because no visible CodeRepositoryBranch maps to the repository and branch:

code_repository_branch_not_registered

The canonical backend action deliberately exposes one not-found result rather than leaking whether the repository or only its branch is registered. This permits ordinary work on local repositories and new feature branches. Only an operation that requires branch-linked platform context calls require_code_repository_branch_context() and fails before its backend request. This includes both CodeRepositoryBranch-owned objects and CodeRepository-facing operations on Environment-owned resources whose Environment is resolved from the current CodeRepositoryBranch.

No unresolved state may fall back to main, a sibling CodeRepositoryBranch, a repository-level DataSource, an Environment inferred from a DataSource, collection order, or a caller-supplied CodeRepositoryBranch UID. The removed repository-level default MetaTables DataSource contract is not restored.

Retired environment contract

ADR 0035 adds typed Python configuration for development Environment scope. It does not restore these retired environment variables or make them source identity.

The SDK does not read, write, or inject these values as source identity:

Caller-supplied repository, branch, and Environment identity variables

Local .env stores only unrelated user configuration plus supported endpoint and authentication transport. Setup and refresh remove stale occurrences of all four variables. Existing process values are ignored, not treated as fallbacks.

The SDK still supports authentication variables such as MAINSEQUENCE_ENDPOINT, MAINSEQUENCE_AUTH_MODE, access/refresh tokens, and runtime credentials. They answer where and as whom to call, not which repository source is running.

Branch-owned consumers

Current-branch Job, CodeRepositoryImage, ResourceRelease, CodeRepositoryResource, CodeRepositoryExecutor, migration, platform-managed MetaTable, and TimeIndexTableUpdater workflows consume the frozen context. Ordinary branch-owned collections are scoped to the resolved CodeRepositoryBranch. Explicit administrative enumeration uses separately named admin APIs.

An instance method does not make an arbitrary CodeRepositoryBranch instance runtime routing authority. Current-branch methods validate the instance UID against the UID returned by get_code_repository_context() and build their request from the resolved UID.

An explicitly targeted operation is different. GitHub issue listing and creation use the receiving CodeRepositoryBranch as the target resource, which may differ from the process-frozen branch. The SDK sends that target UID through the nested route without accepting a separate Environment, repository, or provider-binding selector. The backend derives ownership from the target and remains the authorization boundary. For runtime credentials, it constrains the target to the authenticated runtime's Organization Environment and intersects that boundary with the responsible user's branch permissions. Targeting a resource does not replace or mutate the process-frozen runtime context.

Parent-derived operations retain the persisted parent's ownership instead of inventing another branch selector. Backend authorization remains the final enforcement boundary. Current-branch operations require the Git-resolved branch to equal the authenticated runtime target; explicitly targeted operations must enforce their documented target and Environment boundary instead.

Environment-owned resources resolved from the current CodeRepositoryBranch

ADR 0035 preserves this branch-derived Environment contract. A missing Environment is valid during general source/context discovery and raises only when an Environment-owned operation requires it. Runtime target authority and SDK-owned wire fields are preserved.

Object ownership and operation context are separate concerns. Secret, Constant, logical Bucket, Artifact, and MetaTable belong to one OrganizationEnvironment; they are not owned by one CodeRepositoryBranch. CodeRepositories and branches participating in the same Environment may use the same resources.

CodeRepository-scoped SDK operations nevertheless resolve that Environment only through the frozen current CodeRepositoryBranch:

actual Git worktree and attached branch
  -> get_code_repository_context()
  -> exact persisted CodeRepositoryBranch
  -> OrganizationEnvironment
  -> Environment-owned resource operation

This rule covers CodeRepository-facing create, lookup, list, search, update, and delete operations for Secrets, Constants, Buckets, and Artifacts. It also covers MetaTable registration and import, including external_registered MetaTables. An external MetaTable may select its physical DataSource, but that DataSource is not Environment identity and cannot override the Environment derived from the CodeRepositoryBranch.

The public CodeRepository-facing SDK API accepts neither organization_environment_uid nor a caller-supplied CodeRepositoryBranch UID. The SDK resolves the current CodeRepositoryBranch once and transports its derived Environment UID as an SDK-owned wire field:

{
  "organization_environment_uid": "<branch-derived Environment UID>"
}

This is a transport detail, not user-selected authority. The SDK owns the field and rejects attempts to supply or override it. For local human credentials, the value comes from the authenticated resolve-git-context response. For a deployed JobRun or Knative runtime, the same Git-native resolution is verified against the authenticated runtime target. Resource endpoints must reject a transported Environment that disagrees with that runtime target.

Create requests carry the SDK-owned field in their body. List, detail, patch, delete, and detail-action requests carry it as a query parameter. Both forms have the same semantics: the Environment came from the frozen current CodeRepositoryBranch and is not a public selector. Backend endpoints must normalize these inputs through one Environment resolver before filtering or resolving a known resource UID.

An unregistered local branch remains valid for unrelated development. A CodeRepository-facing operation on one of these Environment-owned resources calls require_code_repository_branch_context() and fails before its request because no Environment can be derived. It must not fall back to main, another branch, an Environment UID, a DataSource, or Organization-wide enumeration.

Explicit Organization-administration APIs may allow an administrator to select an Environment without a Git worktree. Such APIs are separate from the CodeRepository-facing SDK contract and must be named and authorized as administrative surfaces; they are not a fallback for CodeRepository code.

Backend responses expose the derived organization_environment_uid and organization_environment_name as required read-only projections. The SDK models parse those fields but never use them as write authority.

Coordinated Implementation Plan

  • [ ] Add one backend CodeRepositoryBranch-context resolver for Environment-owned resource operations. It must accept SDK-resolved local context, derive context from authenticated deployed runtimes, verify equality when both exist, and return the canonical Environment.
  • [ ] Apply that resolver to Secret, Constant, Bucket, and Artifact list, detail, create, update, and delete paths. Known public UIDs must not bypass the same Environment boundary.
  • [ ] Change CodeRepository-facing external MetaTable registration and import to derive Environment from CodeRepositoryBranch context. Preserve the explicitly selected physical DataSource without treating it as Environment identity.
  • [x] Add one SDK helper that attaches the branch-derived Environment to request bodies or query parameters. The helper calls require_code_repository_branch_context() and rejects caller overrides.
  • [x] Route Secret, Constant, Bucket, and Artifact SDK methods and their CLI commands through that helper. Remove direct Environment selection from CodeRepository-facing command and method signatures.
  • [x] Route external MetaTable.register() through the same helper instead of skipping Environment injection. Keep managed MetaTable, migration, and TimeIndexTableUpdater paths on the existing shared resolver.
  • [x] Add read-only Environment UID and name projections to all affected SDK response models while preserving strict rejection of unknown fields.
  • [x] Test SDK request injection, caller override rejection, canonical response parsing, missing Environment context, and existing process context locking.
  • [ ] Add coordinated backend integration coverage for local human credentials, deployed JobRun credentials, deployed Knative credentials, mismatched runtime context, cross-Environment known-UID access, and same-Environment sharing.
  • [x] Update CLI documentation and agent skills to describe branch-derived Environment resolution and remove instructions that ask CodeRepository users to choose an Environment UID.

Consequences

  • Local and deployed CodeRepository code use one resolution algorithm.
  • Source identity cannot be changed by environment injection.
  • Every CodeRepository-sensitive consumer sees one repository, branch, and commit for the complete process run.
  • Unregistered branches remain usable for local development but cannot create, mutate, or enumerate branch-owned platform resources or CodeRepository-facing Environment-owned resources that require branch-derived context.
  • Supported runtime images must preserve a sanitized attached Git checkout. Images without that contract must be rebuilt; the SDK has no permanent environment fallback.
  • Repository mapping uses the canonical POST /api/v1/code-repository-branches/resolve-git-context/ action. That action also verifies exact equality with an authenticated JobRun or Knative runtime target.

Rejected Alternatives

Keep a deployed environment projection

Rejected because it recreates a second mutable source of repository and branch identity and conflicts with platform ADR-0037.

Resolve on every operation

Rejected because it repeats Git/backend work and lets one process change ownership after a branch switch.

Fail every operation on an unregistered branch

Rejected because local Git development does not require a persisted CodeRepositoryBranch. Enforcement belongs at branch-owned platform operations.

Accept explicit CodeRepositoryBranch UIDs for current-repository work

Rejected because callers could select a branch that differs from the source actually executing. Explicit CodeRepository UIDs retained by some CLI commands are assertions against Git resolution, never selectors.

Required Invariants

  • Git is the only SDK source of repository, branch/ref, and commit identity.
  • Exactly one SDK entry performs current-run platform mapping.
  • Resolution runs once per process and once again after a fork.
  • Detached HEAD, missing Git metadata, missing/ambiguous remote identity, and source drift fail explicitly.
  • Unregistered repository or branch state does not abort unrelated local work.
  • Branch-owned operations and CodeRepository-facing Environment-resource operations reject unresolved context before backend calls.
  • CodeRepository-scoped resource APIs never accept caller-selected CodeRepositoryBranch or Environment identity.
  • The four retired identity variables never influence source resolution.
  • No CodeRepositoryBranch, Environment, sibling-branch, or DataSource fallback exists.
  • Backend authorization remains authoritative and must verify deployed target equality.