HHandoff
← Priority list

Handoff: NamecheapProxyCli + DNS-skill migration, and the (held) "WUI at kotlin.build apex" question

The user wants **the KompileRemoteBuild optimizer WUI served at the `kotlin.build` apex** ("the domain should be just kotlin.build, we should take the main website for the wui"), and — as enabling infrastructure — the DNS management skill migrated to the [NamecheapProxy](https://github.com/CodexCoder21Organization/DocumentationRepository/blob/main/projects/NamecheapProxy.md) (`url://namecheap/`) so DNS can be edited from any machine without IP whitelisting, plus any NamecheapProxy-CLI bugs fixed.

hf-2026-07-08-namecheap-proxy-cli-dns-skill-and-kotlin-build-apex-wui

Edit handoff

Add dependency

Complete this handoff

Moves it out of every priority list and into ArchiveArea.

Handoff document

Markdown

Handoff: NamecheapProxyCli + DNS-skill migration, and the (held) "WUI at kotlin.build apex" question

Written: 2026-07-09 ~01:00 UTC (effort began 2026-07-08).

⚠️ RE-VERIFY BEFORE ACTING. Every state claim here was true only when written. Re-verify PRs with gh pr view <n> --repo CodexCoder21Organization/<repo> --json state,mergedAt,statusCheckRollup, published artifacts with curl -s https://kotlin.directory/api/list-artifacts | grep <coord>, ContainerNursery routes with the CN CLI routes --json, and DNS with the new NamecheapProxyCli (... list-records kotlin.build). A fresh query always wins over this document.

Mission

The user wants the KompileRemoteBuild optimizer WUI served at the kotlin.build apex ("the domain should be just kotlin.build, we should take the main website for the wui"), and — as enabling infrastructure — the DNS management skill migrated to the NamecheapProxy (url://namecheap/) so DNS can be edited from any machine without IP whitelisting, plus any NamecheapProxy-CLI bugs fixed.

This is a follow-on to the (separately handed-off) remote-build-optimizer effort — see handoffs/2026-07-07-kompile-remote-build-optimizer-impl-and-deploy.md.

What was done (verified) — DNS tooling: COMPLETE

  1. Built NamecheapProxyCli (new repo) — a CLI over url://namecheap/ driving the typed NamecheapDnsProxy contract: health, list-domains, list-records, upsert-record, delete-record, with --json and --url, and full-text surfacing of the apex/NS ForbiddenDnsOperationException and NamecheapProxyException. Patterned on CockroachDbCli / GithubProxyCli. Merged (PR #1, main head 60cc183a), kotlin.build (remote) CI green, published namecheapproxy.cli:namecheap-proxy-cli:0.0.2. 4 test suites (arg-parsing, record lifecycle, JSON output, error surfacing) against in-memory NamecheapDnsProxy fakes — all green.

    • Verified end-to-end against LIVE Namecheap from a non-whitelisted box (the whole point of the proxy): health → "OK (connected to Namecheap)"; listed all kotlin.build records; and a self-cleaning _ncpcli-verify TXT round-trip (upsert → confirm present → delete → confirm 0 remaining), leaving the zone otherwise untouched.
  2. Rewrote the namecheap-domains skill (~/.claude/skills/namecheap-domains/SKILL.md, a local file — not a repo, so no PR) to use NamecheapProxyCli over url://namecheap/ instead of the old direct community.contrib.namecheap.cli:namecheap-cli (which required a hardcoded API key + a whitelisted home IP 73.241.194.125 on the command line). Command mapping: domainslist-domains, dnslist-records, add-recordupsert-record. Bumped to reference the published 0.0.2.

  3. "Bug" the user asked to watch for, resolved as a convention, not a defect: coursier launch of the published skinny jar failed (masked util.stacktrace error) because a kompile buildMaven artifact has no Main-Class (only buildFatJar sets one). GithubProxyCli's build is identical, so the established convention is to pass -M namecheapproxycli.MainKt. The skill's commands use that form; verified working. (A future nicety: give buildMaven a Main-Class manifest so -M isn't needed — but that would diverge from the sibling CLIs.)

The held item — "WUI at kotlin.build apex" — NOT started, needs the user

Nothing was changed on DNS or routing for this (the only DNS write was the self-cleaning test record above, already deleted). Held because it displaces the org-CI webhook receiver.

Verified routing/DNS facts (via the new CLI + CN CLI + live curls):

  • Every kotlin.build record — including the apex @ — A-records to the ContainerNursery host 198.199.106.165 (ttl=300), which routes by Host: header. So serving a different jar at the apex is a CN route swap, not a DNS edit.

  • The apex kotlin.build HTTPS route → kotlin-build-ci.jar — this is a GitHub App (its own repo) that receives check_suite webhooks and sets the kotlin.build (remote) check on every org PR. Verified live: POST https://kotlin.build/webhook401 (HMAC-verified webhook endpoint rejecting an unsigned POST); GET https://kotlin.build/200 landing page. One jar serves both /webhook and /.

  • There are three distinct "kotlin build" web things (the source of the user's — and my earlier — confusion):

    | Domain | Jar / host | Role | |---|---|---| | kotlin.build | kotlin-build-ci.jar (ContainerNursery) | GitHub App: receives webhooks (/webhook) + landing page | | www.kotlin.build | kotlin-build-wui.jar (Google Cloud Run) | existing user-facing build dashboard | | kompile-build-ci.kotlin.build | kompile-build-ci-wui.jar (ContainerNursery) | the optimizer/analytics WUI deployed in the prior effort (/queue verified live; /optimizer,/accuracy gated on BTE #266) |

  • Hosted doc also names a github-watchman service "receives webhook events to trigger builds", and there is a live route github-webhooks.wasmserver.comgithub-watchman-integration-server.jar. NOT yet traced whether GitHub posts straight to kotlin.build/webhook or via github-watchman first. This must be mapped before any cutover.

Two decisions the user has not answered (asked twice via AskUserQuestion):

  1. Which WUI goes at the apex — the optimizer WUI built this session, or the existing www.kotlin.build dashboard?
  2. Where the webhook goes. Recommended, staged so CI never drops: add ci.kotlin.build (upsert-record kotlin.build ci A 198.199.106.165 300 via the new CLI + a CN route for it → kotlin-build-ci.jar), repoint the GitHub App's webhook URL to it, verify a signed test delivery, then swap the apex CN route to the chosen WUI jar. Repointing a GitHub App's webhook URL needs App-admin access in GitHub settings — likely a user-only step.

Relevant PRs / refs

| Item | State | |---|---| | NamecheapProxyCli PR #1 | MERGED, main 60cc183a, CI green, namecheap-proxy-cli:0.0.2 published | | ~/.claude/skills/namecheap-domains/SKILL.md | updated locally (not a repo) | | Apex-move | not started — held on the two user decisions above | | BuildTestEmbedded #266 (prior effort) | still OPEN/FAILURE — real duplicateGhostDropletReaped flake + harness corruption; see the optimizer handoff |

Nothing unsaved: the CLI is merged; the skill edit is on local disk (~/.claude).

Next steps

  1. Re-verify (banner). Note the CLI is already at 0.0.2, not the 0.0.1 I first published.
  2. Get the two decisions (which WUI at apex; webhook relocation). Nothing destructive should proceed without them and without confirming who can change the GitHub App webhook URL.
  3. Optional read-only prep: trace the true webhook path (GitHub App → github-watchman? → build dispatch) so the cutover plan is airtight. Safe to do anytime.
  4. When approved, execute staged: ci.kotlin.build A-record (new CLI) → CN route for it → repoint App webhook → verify a signed delivery reaches it and a build dispatches → only then swap the apex CN route to the chosen WUI jar → verify GET https://kotlin.build/ serves the WUI and a fresh PR still gets its kotlin.build (remote) check. Never leave a window where webhooks 404.
  5. Separately, the optimizer effort's BTE #266 remains blocked — see its own handoff.

Reusable / operational knowledge

  • NamecheapProxyCli: coursier launch namecheapproxy.cli:namecheap-proxy-cli:0.0.2 -r https://kotlin.directory -M namecheapproxycli.MainKt -- <cmd> (the -M is required — no Main-Class in the skinny jar). Fat-jar fallback: scripts/build.bash namecheapproxycli.buildFatJar /tmp/x.jar && java -jar /tmp/x.jar <cmd>. It reaches url://namecheap/ from any box — no IP whitelisting, no credential.
  • NamecheapProxy guardrail: upsert-record/delete-record refuse the apex (@) and NS — apex/delegation edits must go through the Namecheap web console, not the proxy.
  • DNS vs routing: all *.kotlin.build A-record to 198.199.106.165; ContainerNursery routes by Host: header. Adding a subdomain = one A record (proxy) + one CN route. Serving a different jar at an existing host = a CN route change only.
  • CN url-facade routes can't be created by the CN CLI (no url flag) — use POST/PUT /routes on https://api.nursery.wasmserver.com/routes with transport: RPC.
  • kompile test files: exactly one top-level function per tests/*.kts; no top-level classes and top-level functions may not declare a return type — put fakes and helpers as locals inside the test function.