Implementation language guidance DATAVERKET 004

Proposed Architecture Development Language Tooling Configuration

Defines Dataverket's default language choices and the boundary between Git-managed configuration and mutable runtime state.

Author
Lars Solem
Updated

Status

Proposed on 2026-03-14 by Lars Solem.

Context

Dataverket spans several kinds of software:

  • long-lived control-plane services
  • CLIs and operator tooling
  • infrastructure workers and agents
  • discovery and migration utilities
  • performance-sensitive or security-sensitive components

Using one language everywhere is not mandatory, but using many languages without a rationale would increase operational and cognitive cost.

The same practical concern applies to configuration management. A platform that automates infrastructure needs an explicit posture for how its own configuration, policy, and runtime state are managed.

Decision

Dataverket adopts a pragmatic multi-language posture:

  • Go is the default choice for core control-plane services, CLIs, and controllers
  • Rust is used selectively where stronger correctness or performance properties are worth the additional complexity
  • Python is used intentionally for tooling, discovery, validation, and rapid operational automation, not as the default language for every long-lived service

This is guidance, not an absolute ban on other choices, but deviations should be justified.

Dataverket also adopts a hybrid configuration-management posture:

  • Git-managed declarative configuration for platform-owned definitions, policy, and reviewed change sets
  • API and database-managed desired state for tenant-facing resources and runtime control-plane data
  • reconciliation to converge the running platform toward those declared sources of truth

This avoids treating Git as the database for all mutable runtime state while still keeping important platform configuration under reviewable change control.

Go guidance

Go is the default because it offers:

  • simple deployment and operations
  • strong fit for service daemons and CLIs
  • mature ecosystem around Kubernetes and infrastructure software
  • practical concurrency model for controllers and background workers

Typical uses:

  • Sentral APIs and bounded contexts
  • Nett and Maskin service processes
  • operator-facing APIs
  • CLI tools

Rust guidance

Rust should be used when its strengths matter materially.

Advantages:

  • memory safety and strong correctness properties
  • good fit for protocol-heavy or high-throughput components
  • attractive for security-sensitive code

Tradeoffs:

  • steeper learning curve
  • slower onboarding and iteration in some teams

Typical uses:

  • selected high-performance components
  • security-sensitive agents
  • correctness-critical low-level infrastructure code

Python guidance

Python remains useful when fast iteration and ecosystem leverage matter more than static rigor.

Advantages:

  • fast development for scripts and utilities
  • strong ecosystem for automation and integration work
  • practical for validation and migration tooling

Tradeoffs:

  • easier to accumulate inconsistent runtime and packaging patterns
  • easier to overuse for long-lived services that later need stronger operational discipline

Typical uses:

  • discovery scripts
  • migration tools
  • validation jobs
  • operational and support tooling
  • early prototypes

Repository and service posture

Configuration management posture

Dataverket should distinguish clearly between:

  1. Platform configuration Configuration that defines how Dataverket itself is operated.

  2. Tenant and operator resource intent Desired state submitted through the public API or operator workflows.

  3. Runtime and operational state Task state, observed state, leases, approvals, health, and other mutable control-plane records.

These do not need the same storage or change workflow.

Git-managed platform configuration

The preferred posture for platform-owned configuration is GitOps-style declarative management.

This should cover at least:

  • Kubernetes manifests or Helm values for Dataverket services
  • environment- or site-specific service configuration
  • policy defaults and reviewed platform feature flags
  • inventory seed data and bootstrap definitions where appropriate
  • network intent templates or other reviewed infrastructure baselines

The goal is that important platform configuration changes are:

  • reviewable
  • auditable
  • reproducible
  • promotable across environments

API and database-managed resource intent

Git should not be the only path for tenant-facing resource creation.

Tenant and operator workflows such as:

  • creating projects and environments
  • requesting VMs, clusters, networks, or buckets
  • triggering failover or approval workflows
  • updating mutable service resources through supported APIs

should be submitted through the public API and stored in service databases as authoritative desired state.

This keeps the self-service and operator model coherent and avoids forcing all platform usage through repository commits.

Runtime state is not GitOps

Dataverket should not attempt to manage these primarily through Git:

  • task and workflow state
  • observed inventory facts
  • ephemeral leases or locks
  • health and degradation signals
  • retry counters and dead-letter records
  • approvals already in progress

Those belong in the control plane’s runtime systems, primarily PostgreSQL and supporting infrastructure such as NATS JetStream.

Hybrid model

The intended model is therefore:

  • Git is the reviewable source for platform-owned configuration and bootstrap definitions
  • the public API is the supported source for tenant and operator resource intent
  • databases hold authoritative mutable state
  • controllers and reconciliation loops make running systems converge toward those declared inputs

This is compatible with GitOps principles without pretending that every piece of platform state should be represented as files in a repository.

This ADR does not yet lock:

  • monorepo versus multi-repo
  • shared library structure
  • build system standard

But the language posture implies:

  • keep the number of production languages intentionally small
  • prefer common operational patterns across services
  • avoid introducing a language only for one marginal convenience

The same discipline should apply to configuration tooling:

  • prefer a small number of standard config formats and deployment patterns
  • avoid each service inventing its own config distribution model
  • keep the boundary between reviewed platform config and mutable runtime state explicit

Consequences

  • the platform gets a default language direction without pretending one language fits every job
  • Go becomes the expected baseline for most long-lived services
  • Rust remains available where it is actually justified
  • Python is legitimized for tooling without becoming the unexamined default for the whole platform
  • platform-owned configuration gets a reviewable GitOps-friendly path without forcing tenant self-service through Git commits
  • runtime control-plane state remains in systems designed for mutable operational data

Decision Outcome

Proposed. This ADR records the current preferred direction and still needs acceptance before it becomes binding.

More Information

  • repository and build layout
  • shared library policy
  • service template and bootstrap standards
  • platform configuration repository and promotion model

Audit

  • 2026-03-14: ADR proposed.