runtime

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 31, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package runtime is the persistence layer for tiny operator-toggleable settings that need to survive process restart and be writable at runtime from an API endpoint (e.g. PUT /api/config/media).

The file lives at <DataDir>/runtime_overrides.json and is the highest- precedence config layer per phase-k-media-contract.md § 6:

default < yaml < env < runtime_overrides.json

Why a separate package (not config.go):

  • config.Load() reads a static YAML at startup; this layer is writable at runtime by the API server. Keeping it separate makes the "static vs mutable" boundary explicit.
  • Pointer-valued fields (*bool) distinguish "no override set" from "override set to false" so absence falls through to env/yaml/default.

Atomicity: SaveOverride writes a sibling .tmp file and renames; readers never observe a partial JSON document.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SaveOverride

func SaveOverride(dataDir string, mutate func(*Overrides)) error

SaveOverride atomically updates one or more fields in runtime_overrides.json by:

  1. Loading the current file (or empty Overrides if missing).
  2. Applying mutate(&ov) so the caller can set just the field it owns without clobbering siblings.
  3. Marshalling, writing to a .tmp sibling, then os.Rename — readers see either the old file or the new one, never a torn write.

The directory is created with 0o755 if it does not exist; this matches the writer's behavior for the data dir tree.

Types

type MediaOverrides

type MediaOverrides struct {
	SaveAttachments *bool `json:"save_attachments,omitempty"`
}

MediaOverrides toggles the media extraction subsystem at runtime.

SaveAttachments is *bool so we can distinguish:

  • nil: no override; use yaml or hardcoded default
  • &true: force extraction on
  • &false: force extraction off

type Overrides

type Overrides struct {
	Media   MediaOverrides   `json:"media"`
	Plugins *PluginsOverride `json:"plugins,omitempty"`
}

Overrides is the on-disk shape of runtime_overrides.json.

Every nested struct uses pointer fields so absent == nil (== "fall through to the layer below"); a present false value is meaningful and MUST not collapse into "unset".

func LoadOverrides

func LoadOverrides(dataDir string) (Overrides, error)

LoadOverrides reads <dataDir>/runtime_overrides.json.

A missing file is NOT an error: it returns the zero Overrides{} so callers can treat "no override" as the common case without special- casing os.IsNotExist at every callsite.

A malformed file IS an error — silently swallowing a parse failure would hide configuration drift from the operator.

type PluginInstanceOverride

type PluginInstanceOverride struct {
	Type    string         `json:"type"`
	ID      string         `json:"id"`
	Enabled *bool          `json:"enabled,omitempty"`
	Config  map[string]any `json:"config,omitempty"`
}

PluginInstanceOverride is one configured plugin instance as stored on disk. Field semantics:

  • Type, ID: identifying tuple. Operator chooses ID (unique across all instances). Both are required when an instance is persisted.
  • Enabled: *bool because a single-instance PATCH may carry "config only" or "enabled only"; nil means "do not change this field" when applied by PUT /api/config/plugins/{id}. For full-list PUTs (the common path) clients SHOULD send a concrete bool.
  • Config: per-type config blob. nil pointer (map==nil) means "do not change this field" on PATCH; an empty map means "clear overrides for this instance."

The pointer-on-Enabled choice mirrors MediaOverrides.SaveAttachments — absent in the wire format MUST be distinguishable from `false`.

type PluginsOverride

type PluginsOverride struct {
	Instances []PluginInstanceOverride `json:"instances"`
}

PluginsOverride is the runtime-override block for the plugin instance list, mirroring plugin-b-c-spec §3.3.2 / §3.3.3.

The bug-prone distinction is between a nil pointer and a non-nil pointer with an empty Instances slice:

  • Overrides.Plugins == nil → no override; YAML wins.
  • Overrides.Plugins != nil with Instances == nil OR len() == 0 → "operator turned all plugins off"; override wins, no plugins run.
  • Overrides.Plugins != nil with a non-empty Instances → full replace of the YAML list.

Because of that, Instances has NO omitempty: an explicit empty array must round-trip through json.Marshal → json.Unmarshal as the same non-nil empty slice we just wrote.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL