Config: deployment-managed env values (opt-in via DAPPS_ENV_MANAGED); derive the DAPPS callsign from the host node, probing for a free SSID - #149
Merged
Conversation
…ost node
Two startup-config behaviours for the pdn supervised-app deployment, both inert for standalone installs:
1. Set DAPPS_* env vars are now re-applied at every start, not just first start. A stored row that differs from its set env var is updated and logged as deployment-managed. Unset env vars never touch stored config, so the standalone /Setup // /Config flow is unchanged, and seeding once via env then unsetting keeps dashboard control as before. /Settings and /Setup badge env-managed fields ("managed by environment") and render them read-only.
2. When the stored callsign is absent or the N0CALL placeholder and the pdn host injects PDN_NODE_CALLSIGN, the callsign is derived as <node-base-call>-<Ssid>, where Ssid is a new seeded option (DAPPS_SSID) defaulting to "7" - proposing the convention that DAPPS resides at SSID -7 of the node callsign. Any SSID on PDN_NODE_CALLSIGN is stripped first. An explicit DAPPS_CALLSIGN or a real stored callsign always wins. /Setup prefills the derived value when applicable.
Also: the release job now stamps pdn-app.yaml's version to the release tag and attaches it as a release asset so pdn's build can fetch manifest + binary from one release; pdn-app.yaml's seeding notes updated to match (no DAPPS_CALLSIGN pre-set needed under pdn any more); the seed call in Program.cs now gets a bootstrap console logger so these decisions are visible in the journal.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…for a free SSID Amendment 1 (review fix - the re-apply semantics were a breaking change for standalone installs): scripts/dapps.service keeps EnvironmentFile=/etc/dapps.env applied forever, so re-applying set DAPPS_* values at every start would silently revert dashboard edits for every documented standalone install. The deployment-managed behaviour is now gated behind DAPPS_ENV_MANAGED=true, a mode switch read each start and never stored. Unset/false keeps today's byte-for-byte semantics: env vars seed missing rows on first start only, no UI badges. True gives the deployment-managed semantics exactly as built: re-apply at every start + journal line + read-only "managed by environment" badges. pdn-app.yaml opts supervised deployments in and documents both modes; docs/configure.md gets the same note. The original ExistingRow_NotOverwrittenByEnv test is restored verbatim and both contracts are pinned under their respective modes. The callsign derivation stays ungated - it only fires when the callsign is placeholder/absent AND PDN_NODE_CALLSIGN is present, which standalone installs never have. Amendment 2: instead of blindly trusting <nodecall>-<DAPPS_SSID>, a derived callsign now checks for free/taken SSIDs over RHPv2 itself. pdn refuses a listen on an already-claimed callsign (including the node's own) with errCode 9 "Duplicate socket", deterministically (packet.net docs/rhp2-server.md deviation D5). DbStartup records each derivation in a DerivedCallsignPending row; while that marker still matches the callsign in use (and no explicit DAPPS_CALLSIGN is set), Rhpv2InboundService treats a 9 as "taken" and walks the candidate SSIDs - start+1..15, then 1..start-1, skipping 0 and the SSID the node itself uses (parsed off PDN_NODE_CALLSIGN). The first successful listen wins and is persisted as the stored callsign (one log line: derived callsign M9YYY-8 - -7 was taken on the node), so the identity is stable on every later start; a persisted, confirmed callsign never walks again. An explicitly configured callsign NEVER walks - a 9 logs the refusal and keeps the existing retry/reconnect behaviour. Non-9 errors never walk. All candidates taken logs loudly and reverts to setup-required mode instead of spinning; the next restart re-derives and probes again. Against a server that answers duplicate listens Ok (live XRouter does), the walk simply never triggers - fine, since derivation only runs under pdn supervision. dapps.core.tests: 674 passed, 0 failed (branch baseline 660; +14: both env modes incl. the restored standalone contract, badge gating, the pending-marker lifecycle, and the probe-walk against MockRhpServer playing pdn's D5 role - walk+persist+stable-across-restart, explicit-never-walks, non-9-never-walks, all-taken-reverts, and the candidate-order unit test). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DAPPS_ENV_MANAGED opt-in deployment-managed config + node-derived callsign with SSID probe-walk + pdn-app.yaml release asset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DAPPS now ships under pdn as a supervised app package, which made the first-start-only env seeding awkward: the host's app config should stay authoritative across restarts, and the owner shouldn't have to invent a callsign that the host already knows. Two behaviours, one PR — both completely inert for standalone installs.
1. Deployment-managed env values — opt-in via
DAPPS_ENV_MANAGED=true(standalone flow untouched by default)DAPPS_ENV_MANAGEDis a mode switch read each start (itself never stored):unset /
false(the standalone default): byte-for-byte today's semantics. Env vars seed rows that don't exist yet (first start) and nothing else; the dashboard owns every value thereafter; no UI badges. The originalExistingRow_NotOverwrittenByEnvtest asserting exactly this is restored, alongside a managed-mode counterpart — both contracts are pinned under their respective modes.true(the pdn supervised-app case): at every startup, any setDAPPS_<KEY>whose value differs from the stored row updates the row and logs:UI: /Settings and /Setup badge any field whose env var is currently set with a "managed by environment" marker (tooltip names the variable) and render the control read-only/disabled. Saving unrelated fields still round-trips the managed values intact.
The repo-root
pdn-app.yamlopts supervised deployments in (and its comment block explains both modes):docs/configure.mdgets the same note; its documented standalone first-start-only contract is unchanged.The seed call in
Program.csnow gets a bootstrap console logger — previously it passed no logger, so none of the seeding decisions were visible in the journal.2. Callsign derived from the host node — now probing for a free SSID
When the stored callsign is absent or the
N0CALLplaceholder and the pdn host injectsPDN_NODE_CALLSIGN, DAPPS derives its identity as<base-of-node-callsign>-<Ssid>(Ssidis a new seeded option, default7, env-overridable asDAPPS_SSID). This derivation is deliberately not gated onDAPPS_ENV_MANAGED— standalone installs have noPDN_NODE_CALLSIGN, so it cannot affect them.And instead of blindly trusting
-7, the derivation is now confirmed over RHPv2 itself. pdn answers alistenon an already-claimed callsign — including the node's own — with errCode 9 "Duplicate socket", deterministically (its docs/rhp2-server.md deviation D5). So:DbStartuprecords each derivation in aDerivedCallsignPendingrow. While that marker still matches the callsign in use (and no explicitDAPPS_CALLSIGNis set),Rhpv2InboundServicetreats a 9 on bind+listen as "taken" and walks the candidates: start+1 … 15, then 1 … start−1, skipping 0 and the SSID the node itself uses (parsed offPDN_NODE_CALLSIGN). First successful listen wins.derived callsign M9YYY-8 — -7 was taken on the node) and the marker is cleared, so the identity is stable on every later start — a persisted, confirmed callsign never walks again.Precedence (highest first): explicit
DAPPS_CALLSIGNenv → real stored callsign (dashboard-configured / probe-confirmed) → derivation+probe →N0CALLplaceholder (standalone, setup-required mode as today). /Setup still prefills its callsign field with the derived value in the rare case the bearer step renders whilePDN_NODE_CALLSIGNis present.Release asset
The release job now attaches the repo-root
pdn-app.yaml(#148) next to the binaries, with its informationalversion:stamped to the release tag, so the pdn build fetches manifest + binary from the same release instead of carrying an interim copy.Tests
dapps.core.tests: 674 passed, 0 failed (branch baseline: 660/0; pre-PR baseline: 651/0). The PR's flippedExistingRow_…test is un-flipped — the restored standalone contract plus aDAPPS_ENV_MANAGED=truecounterpart,=false-same-as-unset, and badge gating. NewDbStartupTestscover the pending-marker lifecycle (set on derivation, survives unconfirmed restarts, cleared by dashboard/env-pinned identities, confirm/abandon round-trips). NewRhpv2SsidProbeWalkTestsdrive the walk againstMockRhpServerplaying pdn's D5 role, through the realSystemOptionsStorepersist→reload path: walk-on-9 picks the next free SSID + persists + is stable across restart; an explicit callsign never walks; non-9 errors never walk; all-taken walks in the exact documented order then reverts to setup-required; plus the candidate-order unit test.Also verified live earlier on this branch: fresh start under pdn-style env derives and seeds correctly; a restart re-applies an env var over a dashboard edit (with the log line above) while leaving a dashboard-pinned real callsign alone — that behaviour now sits behind
DAPPS_ENV_MANAGED=true.🤖 Generated with Claude Code