Skip to content

fix(sms-bridge): target the v1 /session route prefix - #41

Merged
xnoto merged 2 commits into
mainfrom
fix/sms-bridge-opencode-v1-route-prefix
Sep 5, 2026
Merged

fix(sms-bridge): target the v1 /session route prefix#41
xnoto merged 2 commits into
mainfrom
fix/sms-bridge-opencode-v1-route-prefix

Conversation

@xnoto

@xnoto xnoto commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Summary

The live approved-source SMS test against image 6b48dde reached
inbound_queued/job_claimed and then failed
opencode-response-invalid. Root cause: PR #40 adopted the documented
v1 body and strict direct {info,parts} parsing but left the requests
on the legacy V2 /api surface — an exact prefix/API mismatch.

Authoritative upstream evidence at anomalyco/opencode v1.18.23 commit
ef2880f379129aa048be9e9353e30aa168d42c17:

  • packages/opencode/src/server/routes/instance/httpapi/groups/session.ts:
    const root = "/session"; SessionPaths.create = "/session",
    SessionPaths.prompt = "/session/:sessionID/message".
  • packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts:
    create returns the direct Session.Info (empty body accepted);
    prompt streams the direct SessionV1.WithParts {info,parts} JSON —
    neither is data-wrapped.
  • packages/opencode/test/server/httpapi-session.test.ts: proves the
    legacy V2 /api/session/:id/prompt admission response is data-wrapped,
    GET /api/session/:id/message is the V2 message listing, and
    /api/session/:id/wait is unavailable — /api and /session are
    distinct APIs, so the strict direct-shape parser correctly rejected
    the V2 response.

Changes, confined to opencode-sms-bridge/server.py and
opencode-sms-bridge/test_server.py:

  • Session creation: POST /session (was POST /api/session) with the
    documented empty body; id still read from the direct Session.Info.
  • Blocking send: POST /session/{id}/message (was
    /api/session/{id}/message) with message-level agent + single text
    part; response still parsed strictly as direct {info,parts}.
  • PII-safe bounded static error-code taxonomy unchanged.
  • Tests pin the exact /session prefix/method/body at the opener level
    with real request objects and reject every /api route, /prompt,
    /wait, and prompt_async.

Fixes #

None — owner-authorized evidence-based repair to the v1 route prefix;
no driving issue supplied.

Note: this repository has no pull-request template in .github/, the
root, or docs/; the makeitworkcloud/.github organization default
template is applied manually here.

Type of change

  • Bug fix
  • Feature / enhancement
  • Documentation
  • Infrastructure (OpenTofu root or module)
  • GitOps desired state (manifests, kustomize, charts, SOPS/KSOPS secrets)
  • Container image
  • CI / reusable workflow
  • Refactor / cleanup
  • Breaking change

Validation

  • Required pull-request checks pass — buildah run
    33975811487
    (jobs checks
    / detect
    / build & push)
    passed pre-commit (including Gitleaks), changed-image detection
    (opencode-sms-bridge), and the non-publishing bridge image build.
    The build's Containerfile step RUN python3 -m unittest discover -s /app -p "test_*.py" -v ran all 21 tests (Ran 21 tests in 0.100s — OK), including the exact /session route/method/body flow test, the
    documented-fields-only session-create test, the single blocking
    message-request test, the /api-route rejection assertions, and the
    strict {info,parts} extraction and invalid-shape rejection tests.
    Push to registry was correctly skipped in PR mode.
  • Generated or centrally distributed files were regenerated by their
    owning automation, not hand-edited — none changed; only
    opencode-sms-bridge/server.py and opencode-sms-bridge/test_server.py
    were edited.

No local tests, container builds, OpenTofu, SOPS, state, or live-system
operations were run or claimed. CI is the validation authority.

Impact and rollout

Producer changed: makeitworkcloud/images/opencode-sms-bridge is the
canonical bridge-image source. An approved merge automatically publishes
a new immutable GHCR image tag; this PR neither publishes nor deploys
anything itself.

Consumer unchanged: kustomize-cluster continues to select its
currently pinned image; this PR makes no GitOps or image-selection
change. After an approved merge and publication, a separate reviewed
GitOps PR and explicit confirmation are required before image selection,
Argo reconciliation, health verification, and a new approved-source SMS
test.

Behavior boundary: a text job now issues POST /session with an
empty body and POST /session/{id}/message with the routing agent and a
text part, instead of the same documented bodies on the legacy V2
/api/session... prefix. Persisted detail codes are unchanged in
literal value (opencode-request-failed:<session-create|prompt>:<category>,
opencode-response-invalid, etc.). Direct V1 shapes parse as before;
legacy data-wrapped envelopes remain rejected.

Rollback: if a later selected image regresses, use the canonical
GitOps workflow to select a reviewed immutable image tag. Do not
overwrite image tags or alter live state manually.

Safety and secrets

  • Contains no plaintext secrets, decrypted SOPS values, state files,
    kubeconfigs, tokens, or private endpoints.
  • No local OpenTofu init/plan/apply/destroy/import/state operations
    were run or claimed — plans come from pull-request checks.
  • Breaking or irreversible effects are described above with rollback
    notes.

AI-assisted change: an OpenCode agent materially produced this change;
reviewers should verify the cited v1.18.23 upstream evidence (the
/session root with create = /session and prompt = /session/:sessionID/message, direct Session.Info/SessionV1.WithParts
responses, and the distinct legacy V2 /api surface), the strict
response parsing and its invalid-shape rejection, the unchanged bounded
taxonomy, and CI results before merge.

PR #40 kept the documented v1 body and strict direct {info,parts}
parsing but left the requests on the legacy V2 /api surface. Upstream
v1.18.23 (ef2880f379129aa048be9e9353e30aa168d42c17) mounts the session
HttpApi at root "/session": create = POST /session (empty body, direct
Session.Info) and blocking prompt = POST /session/:sessionID/message
(direct streamed SessionV1.WithParts). /api/session* is the distinct
legacy V2 API (data-wrapped prompt admission, GET message listing, no
/wait), so the strict direct-shape parser failed the live
approved-source test with opencode-response-invalid.

Switch only the route prefix in opencode-sms-bridge/server.py:
POST /session with the documented empty body and
POST /session/{id}/message with message-level agent + text parts.
Response parsing, request bodies, and the bounded static error-code
taxonomy are unchanged. Tests pin the exact /session prefix, methods,
and bodies at the opener level and reject every /api route, /prompt,
/wait, and prompt_async.
Restore the OSError failure fixture to a plain tuple element; the
route-prefix change needs no other deviation from main's test file.
@xnoto
xnoto requested a review from a team as a code owner September 5, 2026 15:46
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

Image CI passed

Pre-commit validation passed. View the workflow run.

@xnoto
xnoto merged commit adb1e0e into main Sep 5, 2026
4 checks passed
@xnoto
xnoto deleted the fix/sms-bridge-opencode-v1-route-prefix branch September 5, 2026 15:51
xnoto added a commit to makeitworkcloud/kustomize-cluster that referenced this pull request Sep 5, 2026
## Summary

Select
`ghcr.io/makeitworkcloud/opencode-sms-bridge:adb1e0e72729a7182b4a4929bd67e0275fba8173`,
the immutable image published after [images PR
#41](makeitworkcloud/images#41). It corrects the
OpenCode v1.18.23 session route prefix from the incompatible legacy V2
`/api/session...` surface to the blocking HTTP-API `/session...`
surface.

**Verified producer evidence:** [images buildah run
33976054695](https://github.com/makeitworkcloud/images/actions/runs/33976054695)
passed and published the selected immutable tag at digest
`sha256:607a426dad63dd563cfcca9f9720a0bc5068a8d812b4d4dabd63a0291895bd30`.

This PR changes only the bridge image tag in the existing
`opencode-sms-bridge` Application. It changes no chart version, Secret,
routing/allowlist, Service, TunnelBinding, or sync policy.

Fixes #

None — owner-authorized route-prefix repair rollout; no driving issue
supplied.

## Type of change

- [x] Bug fix
- [ ] Feature / enhancement
- [ ] Documentation
- [ ] Infrastructure (OpenTofu root or module)
- [x] GitOps desired state (manifests, kustomize, charts, SOPS/KSOPS
secrets)
- [ ] Container image
- [ ] CI / reusable workflow
- [ ] Refactor / cleanup
- [ ] Breaking change

## Validation

- [ ] Required pull-request checks pass — pending. Repository PR CI is
the validation authority.
- [x] Generated or centrally distributed files were regenerated by their
owning automation, not hand-edited — none apply; this is a one-line
immutable image-pin change.

No local OpenTofu, SOPS, container build, cluster, or live-system
operation was run or claimed.

## Impact and rollout

**Producer:** `images` merged `adb1e0e…` and published the selected
image. Publication is complete.

**Consumer:** `workloads/apps/opencode-sms-bridge-app.yaml` is the
canonical GitOps image-selection point. This PR proposes, but does not
itself perform, selection or reconciliation.

**Delivery stages:** source is merged, published, and verified by
producer CI; GitOps selection is proposed and PR validation is pending.
An authorized merge runs `test` on `main`; only a successful test
triggers automatic root-sync submission. Root and child reconciliation,
resource health, Pod image, and the approved-source SMS reply remain
separate verification stages.

**Rollback:** use a reviewed GitOps PR to restore the prior immutable
tag `6b48ddeaa5897a3d07dc28aa929a941219ec8993`; do not retag images or
patch live resources.

## Safety and secrets

- [x] Contains no plaintext secrets, decrypted SOPS values, state files,
kubeconfigs, tokens, or private endpoints
- [x] No local OpenTofu init/plan/apply/destroy/import/state operations
were run or claimed — plans come from pull-request checks
- [x] Breaking or irreversible effects are described above with rollback
notes

AI-assisted change: an OpenCode agent materially produced this change;
review the producer evidence, one-line diff, and automatic post-merge
reconciliation behavior before merge.
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.

1 participant