Expand description
@yah:ticket(R040-F16, “pg-on-mesh service recipe: bind tailscale0 + pg_hba.conf snippet + ufw rules”)
@yah:at(2026-05-05T00:32:34Z)
@yah:assignee(agent:claude)
@yah:status(review)
@yah:parent(R040)
@yah:handoff(“Companion to R040-F15. Inter-node TCP (Postgres primary↔replica, NATS clusters, anything raw-protocol) lives on the Headscale mesh, not on Hetzner public IPs. Each node has a stable 100.64.x.x mesh IP that survives replacement of the underlying box, so DNS / config / pg_hba never churn when a CPX-11 is rebuilt. WireGuard already encrypts the wire — TLS becomes defense-in-depth, not load-bearing. This ticket carries the concrete pg-shaped recipe so the first stateful service deploy doesn’t have to re-derive the pattern; subsequent services (redis, NATS, etc.) cargo-cult from it.”)
@yah:next(“ServiceConfig gains a bind_interface: Option<String> field (e.g. Some(\"tailscale0\") for mesh-only services). The cloud-init/podman compose renderer translates this into either --network host + pg listen_addresses = '<mesh-ip>' OR a podman macvlan/host-binding pattern that achieves the same.”)
@yah:next(“Generated pg_hba.conf snippet: allow the mesh subnet (100.64.0.0/10) for replication + app users. Postgres binds to the node’s tailscale0 mesh IP only — listen_addresses is templated from the node’s tailscale ip --4 at first boot.”)
@yah:next(“Generated ufw rules: ufw allow in on tailscale0 to any port 5432; ufw deny 5432 — mirrors the existing yah-yubaba 7443 pattern in mirror.yml. Same shape works for any mesh-only port.”)
@yah:next(“Replica connection string uses primary’s mesh IP, NOT its public IP. Stable across box replacement.”)
@yah:next(“Out of scope: pg_basebackup orchestration, failover, WAL archiving — those belong in noisetable’s domain; this ticket only standardizes the binding/firewall/auth shape so noisetable’s pg deployment doesn’t reinvent it.”)
@yah:ticket(R323-F9, “Add sync-wave ordering to ServiceComponent (deploy-panel wave order)”) @yah:assignee(agent:claude) @yah:at(2026-05-26T15:20:25Z) @yah:status(review) @yah:phase(P2) @yah:parent(R323) @yah:next(“ServiceComponent gains a wave/order field (or depends_on between components) so the deploy panel (R323-F4) can group workload rollout rows into sync waves (wave 0 parallel, wait healthy, wave 1, …). Today all components are implicitly wave 0.”) @yah:next(“compute_service/compute_cell in reconciler/sync_status.rs surface the wave per workload so F4 doesn’t re-derive it.”) @yah:gotcha(“Until this lands, F4 should render every workload as wave 0 (no ordering).”) @yah:handoff(“Added wave: u32 (serde default=0, skip_serializing_if zero) to ServiceComponent in config.rs. Added is_zero_u32 helper. Fixed the three struct literal call-sites that now need wave: 0 (config.rs test, local_sim.rs x2, mesofact_static.rs). Added wave?: number to the TS ServiceComponent interface with a doc comment. Deploy panel now reads c.wave ?? 0 for each WorkloadRow instead of hardcoded 0. SyncFooter computes maxWave from the components array and renders ‘wave 0’ (all-zero case) or ‘waves 0–N’ (multi-wave). All 218 cloud lib tests pass; bun run typecheck clean.”) @yah:verify(“cargo test -p cloud –lib # 218 passed”) @yah:verify(“cd packages/yah/ui && bun run typecheck # no new errors”) @yah:verify(“In service.toml: add wave = 1 to a component, rebuild, open the deploy panel — that workload row shows ‘w1’ badge; SyncFooter shows ‘waves 0–1’”) @yah:verify(“Component with no wave field in TOML deserializes as wave=0 (default). Saving a wave=0 component omits the field from the output TOML (skip_serializing_if).”)
@arch:see(.yah/docs/working/W142-pond.md)
@yah:relay(R615, “Linked infra sources: sources.toml overlay so a camp can borrow another camp’s substrate”) @yah:at(2026-07-20T18:18:05Z) @yah:status(open) @arch:see(.yah/docs/working/W274-linked-infra-sources.md)
@yah:ticket(R615-F1, “InfraSource types + SourcesConfig::load(infra_dir) parsing .yah/infra/sources.toml”)
@yah:status(review)
@yah:assignee(agent:bundle-anthropic-miravel)
@yah:at(2026-08-08T19:55:57Z)
@yah:phase(P1)
@yah:parent(R615)
@yah:next(“Add InfraSourceKind { Path { path }, Git(GitSource) } + InfraSource { owner, kind, mode, select } to cloud/src/config.rs. Reuse the existing GitSource (config.rs:1205, { repo, ref, subdir }) verbatim — do not invent a second git-source shape.”)
@yah:next(“SourcesConfig::load(infra_dir) reads .yah/infra/sources.toml (schema_version = 1, ordered [[source]] array). Absent file = empty list, never an error — every existing camp has no sources.toml.”)
@yah:next(“mode is the write-gate: read-only (borrower cannot mutate) vs owner-manages. Model it as an enum, not a bool, so a future read-write-with-approval tier is additive.”)
@yah:verify(“cargo check -p cloud && cargo test -p cloud”)
@arch:see(.yah/docs/working/W274-linked-infra-sources.md)
@yah:tier(Cleric)
@yah:handoff(“InfraSourceKind{Path{path},Git(GitSource)} + SourceMode{ReadOnly,Manage} + InfraSource{owner,kind,mode,select} + SourcesConfig{schema_version,source} all landed in oss/yubaba/crates/cloud/src/config.rs (after default_git_ref, ~line 1550). GitSource reused verbatim – Git(GitSource) wraps the existing R561 type unchanged, no second git-source shape. InfraSourceKind is internally tagged (#[serde(tag="kind", rename_all="kebab-case")]) and flattened into InfraSource so a [[source]] table reads exactly like W274’s example: owner/kind/path-or-repo+ref+subdir/mode/select all at one table level. mode: SourceMode defaults ReadOnly via #[serde(default)] on the field (enum, not bool, per the ticket’s own instruction – Manage is the explicit escape hatch). SourcesConfig::load(infra_dir) returns Ok(default()) – schema_version=1, empty source list – when sources.toml is absent; only parses+errors when the file exists and is malformed.”)
@yah:handoff(“Tree anchor 85801e7f. Pathspec: oss/yubaba/crates/cloud/src/config.rs (only file touched). Tests: cargo test -p yah-cloud –lib (from oss/yubaba) 710 passed / 0 failed / 4 ignored, +6 new over the 704 baseline your R707-T6 verification recorded (sources_load_is_empty_when_the_file_is_absent, sources_parses_a_path_kind_exactly_like_w274s_example, sources_parses_a_git_kind_reusing_gitsource_verbatim, sources_mode_defaults_to_read_only_and_manage_is_explicit, sources_preserves_declaration_order, sources_round_trips_through_serialize). cargo check -p cloud also green (implied by the test build).”)
@yah:handoff(“Tree anchor at handoff: 85801e7f6b76b369c0c8ecd2e5c7874990cd9286 — the shared tree as I left it. Diff against it (git diff 85801e7f6b76b369c0c8ecd2e5c7874990cd9286..HEAD) to see what landed under you, and quote this SHA rather than ‘HEAD’ in any revert/restore instruction.”)
@yah:next(“R615-F2 picks this straight up: overlay these sources into CloudConfig::load, tagging origin{owner,source} and merging camp-local-wins-on-collision.”)
@yah:handoff(“Verified pre-existing work: InfraSourceKind{Path,Git(GitSource)} + SourceMode + InfraSource + SourcesConfig all present in oss/yubaba/crates/cloud/src/config.rs at tree anchor 871fde1c, matching the inline @yah:handoff notes already on this ticket. GitSource reused verbatim, no second git-source shape. This session added no new code – only ran verification and closed the board state, which a prior session left stuck in open despite the work being done (code + handoff notes landed, but board.review/handoff was never called).”)
@yah:verify(“cargo check -p yah-cloud – clean (2 pre-existing unrelated warnings)”)
@yah:verify(“cargo test -p yah-cloud –lib – 723 passed; 0 failed; 4 ignored (from oss/yubaba)”)
@yah:ticket(R615-F2, “Overlay loader: resolve sources in CloudConfig::load, tag origin, camp-local wins on collision”)
@yah:status(review)
@yah:assignee(agent:bundle-anthropic-miravel)
@yah:at(2026-08-08T19:56:05Z)
@yah:phase(P1)
@yah:parent(R615)
@yah:next(“In CloudConfig::load, after loading camp-local machines/providers/rules, resolve each source to an infra root (git sources read from the .yah/cache/infra/ sync cache — load stays offline), load that root’s machines/providers/rules, tag each entry with origin { owner, source }, and overlay UNDER camp-local. Camp-local wins on name collision.”)
@yah:next(“The machine load site is config.rs:533 (load_dir::yah infra sync target directory must be so the two line up. An unsynced git source (cache dir absent) overlays nothing and is explicitly NOT an error (test: an_unsynced_git_source_overlays_nothing_and_is_not_an_error) – load() stays fully offline as W274 §3 requires.”)
@yah:handoff(“select filtering implemented for machines only (name exact-match or literal mesh_tags membership – not a glob engine, matches W274’s own example verbatim) via machine_matches_select(); does NOT apply to providers – documented as a deliberate choice, nothing in W274 or the ticket describes a provider-scoped filter.”)
@yah:handoff(“EXPLICIT DECISION on the config.rs:575-equivalent gotcha (now load_from_config_dir): sources overlay does NOT apply there. Multi-root sibling config dirs (W206 layout (b)) are a second config root INSIDE the same camp, not a second camp – .yah/infra/sources.toml is tied to paths::infra_dir(workspace_root) specifically, which has no well-defined meaning for an arbitrary config_dir. Documented in the function’s doc comment and proven by load_from_config_dir_never_applies_sources_overlay (a sources.toml at the real workspace root does NOT leak into a load_from_config_dir call against a sibling .noisetable/ dir under that same root).”)
@yah:handoff(“Tree anchor 85801e7f. Pathspec: oss/yubaba/crates/cloud/src/config.rs, oss/yubaba/crates/cloud/src/paths.rs (added infra_source_cache_dir + 1 test), oss/yubaba/crates/cloud/src/reconciler/mesofact_bundle.rs (CloudConfig test-literal fixed for the 2 new fields), app/yah/cli/src/cloud.rs (3 CloudConfig test-literal sites fixed, same reason). Tests: cargo test -p yah-cloud –lib (from oss/yubaba) 720 passed / 0 failed / 4 ignored, +10 over R615-F1’s 710 baseline (9 overlay tests in config.rs + 1 in paths.rs). cargo build -p yah –lib (repo root) green – confirms nothing downstream (agent-tools, cloud.rs, hub) broke from CloudConfig’s two new fields.”)
@yah:handoff(“Tree anchor at handoff: 85801e7f6b76b369c0c8ecd2e5c7874990cd9286 — the shared tree as I left it. Diff against it (git diff 85801e7f6b76b369c0c8ecd2e5c7874990cd9286..HEAD) to see what landed under you, and quote this SHA rather than ‘HEAD’ in any revert/restore instruction.”)
@yah:next(“R615-T3 (yah infra sync) is unblocked and has everything it needs: paths::infra_source_cache_dir(workspace_root, owner) is the exact target directory to clone/pull git sources into, already matching what F2’s overlay reads from.”)
@yah:next(“R615-F4 (Infra tab origin badge, not in my assigned lane) can read CloudConfig.machine_origins/provider_origins directly – no further backend plumbing needed for the badge itself.”)
@yah:handoff(“Verified pre-existing work: overlay landed in CloudConfig::load (oss/yubaba/crates/cloud/src/config.rs) at tree anchor 871fde1c – SourcesConfig::load resolves sources, overlay_infra_sources() merges under camp-local with camp-local-wins and earlier-source-wins collision rules, machine_origins/provider_origins BTreeMaps added to CloudConfig, load_dir_tolerant() added for per-file-tolerant foreign schema skew, InfraSource::infra_root() resolves path/git kinds, load_from_config_dir explicitly does NOT get the overlay (documented). Matches this ticket’s own inline @yah:handoff notes. This session added no new code – only ran verification and closed board state that a prior session left stuck in open despite the work being done.”)
@yah:verify(“cargo check -p yah-cloud – clean (2 pre-existing unrelated warnings)”)
@yah:verify(“cargo test -p yah-cloud –lib – 723 passed; 0 failed; 4 ignored (from oss/yubaba), includes overlay tests + load_dir_tolerant test + infra_source_cache_dir test in paths.rs”)
Structs§
- Bucket
LogEntry - A bucket declaration logged in
topology.tomlbyyah cloud bucket create. - Bucket
Spec - Camp
Cloud Dbs - A camp-shared cloud database catalog, parsed from
.yah/db/cloud.toml. These are cloud DBs not owned by any single service — declared once at camp scope and addressed ascloud:<name>(two-segment id), distinct from a service-localcloud:<service>:<name>. - Cloud
Config - All cloud config loaded from a workspace root (the parent of
.yah/). - CloudDb
- A remote cloud database (
[[db.cloud]]). The connectionurlis stored in TOML but the credential never is —auth_token_envnames an environment variable the daemon reads at connect time, so the same declaration works whether the token is provisioned service-locally or camp-shared (W241; operator confirmed both scopes are needed). A camp-wide cloud DB not owned by any single service is declared identically in.yah/db/cloud.toml. - Connect
Spec - Declared reach for a BYO
staticnode (no provider API). Lives under[connect]in the machine TOML. - DbCatalog
- A service’s declared databases, grouped by environment (W241 §Sections).
Parsed from the
[db]table ofservice.toml; each[[db.<env>]]array entry names one database. The environment tag drives backend selection at query time (see the data-workbench’sdb.query/ thesql_*MCP tools):dev= local file,pond= a DB inside the running pond container stack (reached on a declared localhost port),cloud= a remote libSQL/Turso or Postgres endpoint whose auth comes from an env var (never stored in TOML). - DevDb
- A dev-mode local SQLite database (
[[db.dev]]).pathis resolved relative to the workspace root and opened as a local file — read/write, no network, no auth. - Domain
Config - A routing manifest for one domain, from
.yah/domains/<name>.toml. - Domain
Route - One entry in a
DomainConfig’s route table. - GitSource
- A git source for a component (R561-F1, “BYO git”).
- Infra
Origin - Provenance for a
MachineConfigorProviderConfigpulled in from a linked.yah/infra/sources.tomlentry, rather than declared in this camp’s own.yah/infra/(R615-F2 / W274). - Infra
Source - One
[[source]]entry in.yah/infra/sources.toml(R615-F1 / W274) — an external infra root this camp borrows machines/providers from. - Legacy
Mirror Config - Per-camp mirror declaration from
.yah/cloud/mirrors/<id>/mirror.toml(folder form) or the legacy.yah/cloud/mirrors/<id>.toml(flat form). - Legacy
Service Config - Per-service config from
.yah/cloud/services/<name>.toml. - Machine
Config - Per-machine TOML from
.yah/infra/machines/<name>.toml. - Machine
Registration [registration]— facts observed about a running box, written by the fleet rather than declared by an operator (R707-T1).- Mirror
Assignment - One mirror→machine placement entry in
topology.toml. - Mirror
Config - A service mirror — the projection of a
ServiceConfigonto concrete infra. Lives at.yah/services/<svc>/mirrors/<env>.toml. - Node
Allocatable - Static node capacity declaration on
machine.toml(R572-F3). - PondDb
- A database running inside the pond container stack (
[[db.pond]]). The pond publishes the DB on a localhost TCP port; the hub connects to127.0.0.1:<port>when the pond is up and returns a clear error when it is not. Eitherport(defaulting to a libSQL/sqldHTTP endpoint) or a fullurlmust be given. - Port
Mapping - Provider
Config - A provider account/runtime binding from
.yah/infra/providers/<id>.toml. - Required
Spec - F16 placement constraints declared on a
MirrorProviderSlot, lives under[providers.<role>] required = { regions = [...], mesh_tags = [...] }inmirrors/<env>.toml. - Secret
Config - A camp’s declaration of one cluster secret, from
.yah/infra/secrets/<slug>.toml. - Service
Component - One component of a
ServiceConfig. Thekind(e.g."mesofact-static","almanac","container") selects which reconciler runs against the pointed-at workload manifest. - Service
Config - An operator-facing service declaration from
.yah/services/<svc>/service.toml. - Service
With Mirrors - A loaded service plus its per-environment mirrors.
- Sources
Config .yah/infra/sources.toml— the ordered list of external infra roots this camp borrows from (R615-F1 / W274).- Topology
Config - Mirror-to-machine assignment table from
.yah/cloud/topology.toml. - Workload
Config - A workload declaration loaded from
.yah/cloud/workloads/<name>.toml.
Enums§
- Cloud
Config Error - Error surfaced by
CloudConfig::loadwhen a workload TOML fails validation. - Front
Door - Which front door actually serves a domain’s requests (R594-F12).
- Infra
Source Kind - How to reach an external infra root (R615-F1 / W274, “linked infra sources”): a filesystem link to a sibling camp’s live tree, or a git checkout of an extracted infra repo.
- Ingress
Provider - Which public-ingress provider fronts this mirror’s compute (W267, R594-F11).
- Mirror
Provider Slot - A provider slot inside a
MirrorConfig. Two shapes: - Mirror
Shape - Topological shape of a mirror — how its providers sit relative to each other.
- Pond
DbKind - Wire protocol of a
PondDb. - Provider
- Tag for the infrastructure provider kind. Drives which fields are valid in
a
ProviderConfigbody or aMirrorProviderSlot::Inlineblock. - Route
Mode - Body of a
DomainRoute. Three modes: - Secret
Encoding - How a
SecretConfig’s vault text becomes the bytes delivered to the container (R706 / W294). - Secret
Target Decl - Advisory mount shape on a
SecretConfig. Mirrorsworkload_spec::SecretTargetin a TOML-friendly, externally-tagged-free shape (akinddiscriminator reads better in a hand-written manifest than serde’s default enum encoding). - Source
Mode - Write-gate for a linked
InfraSource(R615-F1 / W274). - Workload
Config Error - Error from loading or validating a single workload TOML file.
Constants§
- DEFAULT_
YUBABA_ PORT - Default yubaba listen port, used when
[connect].yubaba_portis omitted.
Functions§
- canonical_
tier - Map legacy mirror file stems to their canonical tier names.
- node_
selector_ mesh_ tags - Parse the R594 mesh-tag node-selector off a workload’s annotations into the
requested tag set. Absent annotation or empty value ⇒ empty vec (“no
constraint”). Whitespace around each comma-separated tag is trimmed and
empty segments are dropped, so
"tag:build-worker, tier:x86"and"tag:build-worker,tier:x86"parse identically. - provider_
has_ machine_ driver - True iff
providerhas an auto-provision driver (create/destroy via API). Driver-backed providers requirelocation+server_type; BYOstaticnodes (brought up over SSH) do not. The cloud-vs-vps distinction the fleet cares about lives here — at the provider-capability layer — not as a separate machine type (W242 BYO Phase-0 decision).