Skip to content

SWI-11363 Agent-native cutover: cut ordering surface, add readiness + errors + AGENTS.md#15

Merged
kshahbw merged 16 commits into
mainfrom
adapter/agent-native-cutover
Jul 16, 2026
Merged

SWI-11363 Agent-native cutover: cut ordering surface, add readiness + errors + AGENTS.md#15
kshahbw merged 16 commits into
mainfrom
adapter/agent-native-cutover

Conversation

@kshahbw

@kshahbw kshahbw commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

What & why

Makes the adapter something an AI agent can actually drive end-to-end, rather than just a library a developer reads. Two moves: cut the broken number-ordering surface (the band CLI owns provisioning now), and add the affordances + docs that let an agent configure, self-check, and cut a customer over to Bandwidth — while being honest about the steps a human still has to own.

Changes

  • Cut the ordering surface — removed src/numbers/*, the AvailablePhoneNumbers/IncomingPhoneNumbers facade, the live verify script, the number routes/config, and their tests. This code was never trustworthy (it sent JSON to Bandwidth's PascalCase-XML Dashboard API); band number order/search/release is the supported path.
  • npm run doctor — a pre-startup config gate: reports (as JSON) which required env vars are set by their real names, and whether the Bandwidth OAuth token exchange works. Exit 0 = ready.
  • GET /readyz — a running-server config/liveness signal. Env-presence only: no outbound call, no secrets — safe to expose unauthenticated.
  • Structured errors — the adapter's own operational failures now return the Twilio-shaped { code, message, more_info, status } body (private codes 90001/90002/90003). The handler is deliberately neutral: unknown throws → a generic 500, never relabeled "Bandwidth", and err.message is never echoed to the client (Bandwidth errors embed upstream response bodies).
  • AGENTS.md — the agent-facing cutover runbook: the band + adapter paired model, a phased runbook with inline band commands (Universal Platform / VCP path), a greppable 🧍 Human required marker on every step an agent can't own (new account, HTTP-Voice feature flag, public host, by-ear verify), capability boundaries pulled faithfully from the matrix, and an errors reference. Plus README pairing pitch and docs/demo.md cleanup.

Review trail

Built via subagent-driven development (per-task spec+quality review) and independently reviewed by two models. The second (Codex) caught two issues fixed here: an unauthenticated /readyz?deep=1 that triggered a live OAuth exchange and reflected the upstream response body (info-leak + amplification) — resolved by removing the network probe from HTTP entirely and keeping the live token probe local-only in doctor; and a double-https:// in a runbook band command.

Testing

npm test → 225/225 green. npm run typecheck clean.

Notes for reviewers

  • Sequencing: this branch and the in-flight adapter/webhook-callback-auth PR both edit src/server/app.ts. Whichever lands second needs a rebase to re-resolve that file — please sequence, don't merge both simultaneously.
  • Out of scope (pre-existing): src/matrix/twilio-voice.json lists Record as bxml: "transcribe" while the translator/docs correctly drop transcription with a warning — a matrix data nit worth a separate fix.

🤖 Generated with Claude Code

kshahbw and others added 8 commits July 15, 2026 15:16
Bundles the agent-facing docs: AGENTS.md is the phased Twilio->Bandwidth
cutover runbook (band CLI commands, capability boundaries sourced from
src/matrix/twilio-voice.json, and the private error codes). README gets a
band-pairing pitch and pointer to AGENTS.md. Both README and docs/demo.md
drop stale references to the removed number-ordering surface
(AvailablePhoneNumbers/IncomingPhoneNumbers routes, scripts/verify-numbers-live.ts,
and the deleted number tests), redirecting to the band CLI instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Codex review: unauthenticated /readyz?deep=1 triggered a live OAuth exchange
and reflected the upstream response body — an info-disclosure + amplification
surface. Remove the network probe from the HTTP endpoint entirely: /readyz now
reports required-env presence only (no outbound call, no secrets), and the live
Bandwidth token probe lives solely in the local `npm run doctor` CLI.

Also fix runbook defects: AGENTS.md double-prefixed https in the band app
callback URL; document that removed routes return the framework default 404;
qualify docs/demo.md SIP peer as legacy-platform-only (default is VCP).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@kshahbw
kshahbw requested review from a team as code owners July 15, 2026 20:58
@bwappsec

bwappsec commented Jul 15, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@kshahbw kshahbw changed the title Agent-native cutover: cut ordering surface, add readiness + errors + AGENTS.md SWI-11363 Agent-native cutover: cut ordering surface, add readiness + errors + AGENTS.md Jul 16, 2026
kshahbw and others added 8 commits July 16, 2026 09:57
…cutover

# Conflicts:
#	README.md
#	src/server/app.ts
#	src/server/index.ts
#	test/server-numbers.test.ts
The /bw/* Basic-auth hook checked req.url.startsWith("/bw/"), but the
router percent-decodes the target before matching, so a raw path like
/%62%77/continue routed to /bw/continue while skipping the check. Key the
hook on req.routeOptions.url (the matched route template) so encoded paths
cannot reach a handler unauthenticated.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Cap Say/Play loop at 1000 (Twilio's max) and enforce a 2 MiB document-wide
serialized-output budget, so a crafted TwiML document cannot force unbounded
allocation on the event loop.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Stream the customer response with a 256 KiB cap (checked against Content-Length
and enforced during read, cancelling the body on overflow) instead of buffering
an unbounded body.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Reject + percent-encode call/recording ids before upstream URL interpolation
(encoding alone does not neutralize dot path segments), and validate ids at the
/bw/* webhook ingress boundary. Adds error code 90004.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
WEBHOOK_USER/WEBHOOK_PASSWORD are required to start; add them to REQUIRED_ENV so
/readyz and `npm run doctor` report not-ready when they're missing instead of
green-lighting a config that crashes on boot.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- README: fix band CLI link (/docs/cli -> /tools/cli/); drop stale test counts
- AGENTS: add WEBHOOK_USER/WEBHOOK_PASSWORD to the Phase 3 env table + HOST note
- demo: webhook Basic auth (-u) + WEBHOOK_* and EGRESS_ALLOW_PRIVATE for the
  all-localhost demo flow

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@kshahbw
kshahbw merged commit 7d740ae into main Jul 16, 2026
6 checks passed
@kshahbw
kshahbw deleted the adapter/agent-native-cutover branch July 16, 2026 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants