soul.demarkus.io:6309/index/decisions.md/v15 draft reader meta

Decisions

Part of the demarkus-soul hub. Architecture decision records for the core project, canonical here since 2026-09-28; docs/adr/ in git is a frozen archive of 0001 to 0027 (see where decisions live). Sub-project decisions live in their own series, for example /demarkus-library/adr/. Status and dates live in each ADR.

  • ADR 0001: broker confidential web-client registry

  • ADR 0002: align store frontmatter with the Open Knowledge Format

  • ADR 0003: default OKF type on publish

  • ADR 0004: edge semantics, provenance on every edge, typed relations via rel- metadata

  • ADR 0005: node identity omits the default port

  • ADR 0006: the Postgres backend is an optional build, not a dependency; superseded by ADR 0010

  • ADR 0007: SNI selects and pins one virtual Mark server per QUIC connection

  • ADR 0008: GCS world state commits through one root CAS

  • ADR 0009: AGPL for the core, MIT for plugins and satellites

  • ADR 0010: remove the Postgres backend; the knowledge server owns shared multi-writer state

  • ADR 0011: allowlisted private-use scheme redirects for MCP hosts, unblocking Cursor's MCP OAuth against the broker

  • ADR 0012: body match is an optional mode of LOOKUP; recall specified, ranking left to the implementation

  • ADR 0013: source revisions, extraction views, graph freshness and generated-format compatibility

  • ADR 0014: the protocol module is wire and stored format only

  • ADR 0015: the backend contract takes a context per call and reads through views

  • ADR 0016: the publish policy is enforced above the store, inside its commit

  • ADR 0017: archive preconditions, closed views, and seeding above the store

  • ADR 0018: one mark URL parser, and host case is not identity

  • ADR 0019: tool bodies and the write contract live in shared packages

  • ADR 0020: one reconcile owner in docwrite, and write tools check arguments before authorization

  • ADR 0021: a world registry that announces drops, DNS label world names, one tenant door for tools and resources

  • ADR 0022: the MCP gateway takes its dependencies from Run, not the Server; NewServer takes a deps struct

  • ADR 0023: the broker is core, oauthsrv, gateway and storage behind one Run, with brokertest for shared fixtures

  • ADR 0024: the plugin binary is provision and registry package families by concern, and a harness is a host.Host value

  • ADR 0025: WATCH is the eighth verb, the store emits hints only, and protocol 1.0 freezes after WATCH and ALPN mark/1

  • ADR 0026: a client SDK under MIT with its own semver, CC0 wire fixtures, the server never imports it, exact relicensed file list

  • ADR 0027: world token files are optional at open and split into a broker-owned runtime file and an operator-owned static file; the chart's bootstrap Job becomes optional for GitOps

  • ADR 0028: every store owns a durable change epoch and sequence behind backend.ChangeSource, proven by one conformance suite; the file store keeps a journal, the bucket store its receipts (proposed)

soul.demarkus.io:6309/adr/0027-world-token-files-optional-and-split.md draft reader meta

ADR 0027: World token files are optional at open and split into runtime and static

Status: accepted (2026-09-28). Canonical copy in git at docs/adr/0027-world-token-files-optional-and-split.md. Resolves demarkus #517, merged in PR #518; related debt in Broker runtime Secrets under GitOps.

Context

A knowledge world refused to open without its tokens file, and the file was one Secret the broker appends to at runtime. No reconciler can own that Secret (a sync would reset the broker's entries), so the Helm chart created it with a pre-install Job: an extra image on the cluster's allowlist, RBAC over Secrets, a kubectl pinned to the API server's minor, and hook ordering under Argo CD. The Job also minted the agent's admin token, so removing it needed another home for that token.

Decision

  • A world's token files are optional at open when the server says so (worldruntime.Config.OptionalTokensFiles, always set by the knowledge server). A missing file contributes no tokens; the store is the union of the files present on disk, on the first open and on every reload. The directory watcher loads a file that appears later. A file that vanishes revokes its entries on the next reload. The single-host demarkus-server stays strict: its worlds may hold read tokens, and a mistyped path must not make a private world public.
  • Each world has two files: auth.tokensFile, the runtime file a broker appends to, and auth.staticTokensFile, operator-owned entries such as an agent's publish token. auth.Source merges them; a hash in both is a load error, and the config refuses a path used twice across worlds or files.
  • The chart projects both Secrets, optional, into one directory per world: <name>-tokens (broker-created) and <name>-static-tokens (operator supplied, hashes only, safe in git). The bootstrap Job stays on by default for existing installs; a GitOps install turns it off and supplies the static Secret plus the raw <hub>-token-values the agent reads.

Consequences

  • An Argo CD install renders no Job, no extra image and no Secret RBAC, and two syncs in a row leave the broker's entries untouched.
  • The agent's token is static: rotation is a new hash in the static Secret and a new raw value in its Secret, hot-reloaded on the server side.
  • A world without any token Secret is silently read-only until one lands; the open logs one Info line per missing file.
  • configwatch.Watcher takes a target set in one directory, so both files share one watcher and one debounce in every server.
  • The issue asked for a vanished runtime file to keep the last good store. Rejected: the kubelet swaps symlinks and never leaves a file transiently absent, the broker writes files atomically, and a store that depends on history rather than disk state changes behaviour on restart. Mirroring the disk is the simpler guarantee and makes deletion an honest revocation.
trail
  1. soul.demarkus.io:6309 v15
  2. 0027-world-token-files-optional-and-split