Skip to content

docs(decisions): ratify the offered VPS specification as ADR-0018 - #268

Merged
serina-mcfall merged 2 commits into
launchpadfrom
docs/adr-0018-relay-vps-specification
Aug 21, 2026
Merged

docs(decisions): ratify the offered VPS specification as ADR-0018#268
serina-mcfall merged 2 commits into
launchpadfrom
docs/adr-0018-relay-vps-specification

Conversation

@tucktuck101

Copy link
Copy Markdown
Collaborator

Summary

Records the sizing decision the deployment already made in practice: the cohort relay runs on the offered 1 vCPU / 1.9 Gi / 496 MB swap / 49.5 G host, accepted as-is. #21 was filed to settle this before deployment, but the measurements it named never completed and the deployment proceeded anyway, so this ratifies the live state rather than pretending the question is still open. The unresolved ceilings question is named as a follow-up ADR rather than folded into this one.

Related issue

Closes #21

Issue type

ADR


Agent provenance

Field Value
Harness / provider Claude Code
Model claude-opus-5[1m]
Session reference N/A - the harness exposes no shareable run id
Initiating human @tucktuck101

Objective

Add launchpad/decisions/ADR-0018-cohort-relay-vps-specification.md accepting the offered VPS specification unchanged.

Impacted components

launchpad/decisions/ADR-0018-cohort-relay-vps-specification.md

Approach and rejected alternatives

Ratify the specification already in production. The alternative seriously considered was holding #21 open until #39 (load capacity) reports, which is what the issue's own comment thread recommended when it was filed. That was right at the time and is wrong now: the relay has been serving on this specification for days, so holding would leave the record saying "undecided" about an internet-facing host — exactly the silent, unrecorded trade #21 was written to prevent. A third option, ratifying and setting the connection and memory ceilings in the same record, was rejected as scope creep; the ceilings need their own evidence and their own ADR.

Verification

Command run:

curl -s -o /dev/null -w "%{http_code}\n" https://launchpad-buzz.devacademy.nz/
grep -nE "BUZZ_MAX_CONNECTIONS|BUZZ_SEND_BUFFER|BUZZ_MAX_CONCURRENT_HANDLERS" -A 3 crates/buzz-relay/src/config.rs | grep -E "BUZZ_|unwrap_or"
grep -cE "mem_limit|memswap_limit|resources:" deploy/compose/compose.yml

Raw output:

200

556:        let max_connections = std::env::var("BUZZ_MAX_CONNECTIONS")
559-            .unwrap_or(10_000);
561:        let max_concurrent_handlers = std::env::var("BUZZ_MAX_CONCURRENT_HANDLERS")
564-            .unwrap_or(1024);
566:        let send_buffer_size = std::env::var("BUZZ_SEND_BUFFER")
569-            .unwrap_or(1_000);

0

The relay answers on 443, the three cluster-sized defaults cited in the ADR are real, and deploy/compose/compose.yml declares zero memory limits. Separately in the same session, a desktop client authenticated to wss://launchpad-buzz.devacademy.nz over NIP-42 and loaded 6 channels, which is what establishes that the host is genuinely serving rather than merely answering HTTP.

  • Tests or checks were run and the raw output is pasted above
  • The diff is confined to the scope of the linked issue
  • No secrets, keys, tokens or hostnames were added to tracked files

Not verified

No resource figure on the live host was measured — not peak memory, not CPU, not disk. That is the central gap and it is stated plainly in the ADR's own Consequences section rather than papered over. Specifically not checked: whether the running relay actually inherits the default BUZZ_MAX_CONNECTIONS=10000 (inferred from the fact that the only place the cohort ever templated it is under launchpad/deploy/archived/, not observed on the host); whether the deployed container matches the compose file in this repo; and the disk sizing, which the local VM could never settle. I have no credentialed access to the VPS from this session.

Security implications

No change to exposure — this PR adds one markdown file. What it records is security-relevant: the sizing-versus-hardening trade #21 feared did not happen (#20 and #5 both closed), but the relay very likely accepts up to 10,000 connections with a 1,000-message-per-connection buffer on a 1.9 Gi host with 496 MB of swap, and the Postgres writer and reader pools default to 50 each against Postgres's own default max_connections=100. That is an availability exposure on an internet-facing host, documented here and escalated below rather than fixed in this PR.

Escalations

  1. The ceilings ADR should not wait on task: build a load-generation tool and measure relay capacity under concurrent load #39. Resource exhaustion is cheap while the defaults stand; the follow-up decision needs a human to schedule it.
  2. task: deploy the relay to the VPS with real DNS and TLS #22 (deploy the relay with real DNS and TLS) is open while its outcome is in production. It should probably close, but that is not this PR's call.
  3. Precedent. An ADR filed specifically to gate work was outrun by the work. Ratifying is the least-bad response, not a good one, and the cohort may want a rule about what happens when a gating ADR is overtaken.

Records the sizing decision the deployment already made in practice: the
cohort relay runs on the offered 1 vCPU / 1.9 Gi / 496 MB swap / 49.5 G host,
accepted as-is. Reframes #18 and #39 from gating measurements to post-hoc
validation, and names the unresolved ceilings question (cluster-sized
connection, buffer and pool defaults with no compose memory limits) as a
follow-up ADR rather than folding it into this one.

Closes #21

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: tucktuck101 <jeffreytaylorrobertson@gmail.com>
@tucktuck101 tucktuck101 added type:adr A decision to make and record. Not a work item. area:deploy VPS, Ansible, host configuration, hardening by:agent Filed or authored by an AI agent, not a human labels Aug 21, 2026
@tucktuck101 tucktuck101 self-assigned this Aug 21, 2026
@serina-mcfall

Copy link
Copy Markdown

Automated review (requested by @serina, via her review-code/review-docs/review-adjudicate pipeline — independent reviewer + adjudicator, each re-verified claims against the actual repo rather than trusting the diff or each other)

Blocker

launchpad/decisions/ADR-0018-cohort-relay-vps-specification.md:30 — the ADR states BUZZ_IMAGE "already defaults to a prebuilt image." That's not correct: deploy/compose/compose.yml:5 uses ${BUZZ_IMAGE:?...} (Compose fails on unset/empty, no fallback), and deploy/compose/README.md:41 says plainly "BUZZ_IMAGE has no default. Compose fails when it is missing." The underlying conclusion (no source builds happening on this host) still holds — only the mechanism is misstated. Suggested fix: replace "already defaults to" with something like "already requires an explicit prebuilt image (BUZZ_IMAGE has no default and Compose fails without it)."

Finding raised then refuted

A reviewer initially flagged that decided_in: launchpad-26/buzz#21 points to an issue that's still open. On adjudication this didn't hold up: PR #268's own body contains "Closes #21," and GitHub only closes linked issues on merge — comparing against the sibling ADRs the reviewer cited (#190, #193), their issues still read "Decision outcome: Left blank deliberately" today too, because closing an issue doesn't rewrite its body. #21 is on the same pattern as its siblings, just unmerged. No action needed here.

@serina-mcfall serina-mcfall left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — one Blocker from the automated review posted above:

launchpad/decisions/ADR-0018-cohort-relay-vps-specification.md:30 — the ADR states BUZZ_IMAGE "already defaults to a prebuilt image." That's not accurate: deploy/compose/compose.yml:5 uses ${BUZZ_IMAGE:?...} — Compose fails on unset/empty, no fallback — and deploy/compose/README.md:41 says plainly "BUZZ_IMAGE has no default. Compose fails when it is missing."

The underlying conclusion still holds (no source builds are happening on this host) — only the mechanism is misstated. Please reword to something like: "already requires an explicit prebuilt image (BUZZ_IMAGE has no default and Compose fails without it)."

Note: a second concern raised in review (that decided_in points to still-open issue #21) was checked and refuted on adjudication — #21 follows the same "Closes #21 on merge" pattern as its closed sibling ADRs, it's just not merged yet. No action needed there.

Review on #268 caught an inaccurate claim: the ADR said BUZZ_IMAGE "already
defaults to a prebuilt image". It has no default —
deploy/compose/compose.yml uses ${BUZZ_IMAGE:?...} so Compose fails closed
when it is unset, and deploy/compose/README.md says so explicitly.

The conclusion is unchanged (no source build happens on this host); only the
mechanism was misstated. Wording taken from the reviewer's suggestion. The
claim was inherited from #21's body and repeated without verification.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: tucktuck101 <jeffreytaylorrobertson@gmail.com>
@tucktuck101

Copy link
Copy Markdown
Collaborator Author

Fixed in b4455b1 — thanks, that was a real error.

Verified before changing it: deploy/compose/compose.yml:5 is image: ${BUZZ_IMAGE:?BUZZ_IMAGE must be set to an immutable relay image}, so Compose fails closed, and deploy/compose/README.md states "BUZZ_IMAGE has no default. Compose fails when it is missing." Your wording taken as suggested:

The deployment already requires an explicit prebuilt image: BUZZ_IMAGE has no default and Compose fails without it.

Root cause worth recording: the claim was inherited from #21's own body, which says BUZZ_IMAGE "already defaults to the prebuilt ghcr.io/block/buzz:main". I carried it into the ADR without checking it. Fail-closed is the stronger fact for the argument anyway — the host cannot start without being handed an image, which makes the no-source-builds conclusion mechanical rather than a matter of configuration habit.

Agreed on the decided_in point — same "Closes #21 on merge" pattern as the closed sibling ADRs, no action needed.

Comment by an AI agent (Claude Opus 5) on behalf of @tucktuck101.

@serina-mcfall serina-mcfall left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent review — no blockers. The existing change-request is already satisfied.

Reviewed in a fresh context. I am an agent and do not approve — posting as a comment so @serina-mcfall can.

The CHANGES_REQUESTED on this PR is addressed, not stale. The review was submitted 2026-08-21T03:45:38Z against 2efb796e7, raising one blocker: the ADR said BUZZ_IMAGE "already defaults to a prebuilt image" when deploy/compose/compose.yml:5 is ${BUZZ_IMAGE:?...}, which fails closed with no default. The fix landed in b4455b1fa at 2026-08-21T10:35:45Z — the current head — and I read it directly: "already requires an explicit prebuilt image: BUZZ_IMAGE has no default and Compose fails without it." Exactly the correction asked for. GitHub's label just hasn't been refreshed by a re-review.

Verified independently:

  • The VPS spec matches issue #21's offer — 1 vCPU, 1.9 Gi RAM, 496 MB swap, 49.5 G disk, identical numbers.
  • BUZZ_MAX_CONNECTIONS 10000, BUZZ_SEND_BUFFER 1000, BUZZ_MAX_CONCURRENT_HANDLERS 1024 — exact match in crates/buzz-relay/src/config.rs.
  • compose.yml declares no memory limits — zero matches for mem_limit/resources.
  • DB writer and reader pools default to 50+50 against Postgres max_connections=100.
  • The relay answers on its public host — 200, re-run rather than taken from the PR body.
  • decided_in pointing at an open issue matches the sibling pattern (ADR-0017 on #193 reads the same way), so not a defect.
  • ADR-0018 collides with nothing merged or in flight (#281 takes 0019, #291 takes 0020, #308 takes 0021/0022).
  • Front matter and section order match the sibling records; no private-tooling paths.

Two things to know before merging, neither a code defect:

  1. The red CI is an infrastructure flake, not your change. Desktop Core failed in the setup-mold action — HTTP request sent, awaiting response... Read error (Connection timed out) then tar: Error is not recoverable: exiting now, exit 2. That's a network timeout fetching the linker, on a PR that changes one markdown file. Re-running the job should clear it.
  2. Non-blocker, PR body only: Escalations §2 says issue #22 is "open while its outcome is in production". #22 closed at 2026-08-21T03:48:44Z. Body staleness, not a defect in the record — not worth an issue, just noting it's moot now.

Ready for approval once the flaky job is re-run.

@serina-mcfall
serina-mcfall dismissed their stale review August 21, 2026 21:25

Dismissing as addressed. This review's blocker -- the ADR claiming BUZZ_IMAGE 'already defaults to a prebuilt image' when deploy/compose/compose.yml:5 is ${BUZZ_IMAGE:?...} and fails closed -- was fixed in b4455b1 (2026-08-21T10:35:45Z), which is the current head. Verified directly: the record now reads 'already requires an explicit prebuilt image: BUZZ_IMAGE has no default and Compose fails without it.' Review was against 2efb796.

@serina-mcfall serina-mcfall left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Independent review found no blockers; non-blocking findings are filed as follow-up issues.

@serina-mcfall
serina-mcfall merged commit f01c949 into launchpad Aug 21, 2026
25 of 27 checks passed
@serina-mcfall
serina-mcfall deleted the docs/adr-0018-relay-vps-specification branch August 21, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:deploy VPS, Ansible, host configuration, hardening by:agent Filed or authored by an AI agent, not a human type:adr A decision to make and record. Not a work item.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

adr: VPS specification for the cohort Buzz relay

2 participants