Skip to content

docs: contract upgrades, API versioning, AI agent config, and styling conventions - #591

Closed
Depo-dev wants to merge 8 commits into
codebestia:mainfrom
Depo-dev:docs/backend-contracts-web-reference
Closed

docs: contract upgrades, API versioning, AI agent config, and styling conventions#591
Depo-dev wants to merge 8 commits into
codebestia:mainfrom
Depo-dev:docs/backend-contracts-web-reference

Conversation

@Depo-dev

Copy link
Copy Markdown
Contributor

Description

Adds four reference documents, one per linked issue. Docs only — no source changes.

Doc Issue
contracts/docs/concepts-upgrades.md #579
docs/api-versioning.md #588
apps/ai_agent/docs/configuration.md #583
apps/web/docs/styling.md #576

Where the docs differ from the issue text

Three issues describe things the code does not do. Each doc records what is actually there:

  • AI agent configuration and environment reference #583 asks for model selection, Weaviate connection and host/port env vars. apps/ai_agent/main.py reads exactly one variable, OPENAI_API_KEY; the model, connect_to_local() and 0.0.0.0:8000 are hardcoded. The doc adds a "variables the service does not read" table so nobody sets WEAVIATE_URL expecting an effect. Also notes infra/docker-compose.yml ships no Weaviate service.
  • API versioning and deprecation policy #588 cites a key-bundle route move as a shipped breaking change. Git history does not support it — the route has always been GET /users/:userId/devices/:deviceId/key-bundle; 3619ca8 added rate limiting, not a move. The doc covers the two verifiable breaks (sequenceNumber dropped from /sync, device required on verify) plus the retired POST /devices, which is the repo's own best precedent and the model the deprecation procedure generalises.
  • Contract upgrade and versioning #579 — storage-compatibility rules are derived from soroban-sdk-macros 22.0.11, not from EVM intuition: #[contracttype] enums encode by variant-name symbol and structs as name-keyed sorted maps. So reordering DataKey variants is harmless and renaming is the fatal case — renaming DataKey::Admin is unrecoverable, since nobody can authorize a further upgrade afterwards.

One thing surfaced but not fixed, as out of scope for a docs issue: apps/web/src/components/ui/CopyButton.tsx holds the codebase's only dark: variant, which can never activate because no dark-mode strategy is configured. It is documented as drift.

Every cross-linked path was checked to exist. Prettier 3.9.1 run on all four, matching the repo's format:check glob.

Type of change

  • Bug fix
  • New feature
  • Documentation update
  • Other

Checklist

  • I have read the contributing guidelines
  • I have tested my changes locally
  • My code follows the project's coding standards

Closes #579
Closes #588
Closes #583
Closes #576

Adds contracts/docs/concepts-upgrades.md covering token_transfer's
upgrade(env, new_wasm_hash) entrypoint end to end.

- Authorization: the single admin.require_auth() gate, that the admin is
  fixed at initialize with no rotation path, and what a compromised admin
  key means (total, unrecoverable loss of control over the contract).
- Procedure: build with the pinned release profile, upload to obtain the
  wasm hash, verify that hash locally with sha256sum and via an
  independent reproduction, invoke as the admin, then confirm by reading
  state back.
- Storage compatibility: soroban-sdk encodes contracttype enums by
  variant-name symbol and structs as name-keyed sorted maps, so renames
  and type changes corrupt or orphan state while reordering is harmless.
  Tables split safe from unsafe changes on that basis, and note the
  rename of DataKey::Admin as the unrecoverable case.
- Records that only token_transfer is upgradeable; group_treasury and
  proposals have no upgrade entrypoint, so changing them means a fresh
  deployment and repointing every consumer.
- Notes the absence of any version() entrypoint or upgrade event: the
  wasm hash is the only on-chain version identifier.
Adds docs/api-versioning.md.

States the current position plainly: REST routes are mounted unprefixed
in app.ts, socket events are addressed by bare name with no version in
the payload or handshake, and no deprecation machinery exists anywhere
in apps/backend/src. Records the three breaking changes that already
shipped without one - sequenceNumber dropped from GET /sync envelopes,
device made required on POST /auth/verify, and JWT-only registration
retired at POST /devices.

Defines what breaks for REST responses, socket payloads, and
database-backed shapes, including the case where a migration changes a
response without any route being edited, and the asymmetry that strict
request schemas make an added optional field breaking in the other
direction.

Gives the deprecation procedure: announce with a sunset date, mark per
surface, ship the replacement first, hold the window, then retire behind
an explicit error naming the replacement. The retired POST /devices
handler, which still answers 403 pointing at the link-challenge flow, is
the precedent the procedure generalises. Sets a 90-day minimum window,
derived from the 7-day envelope retention floor plus stale tabs and
cached service workers.

Documents device capability negotiation as the mechanism that already
ships protocol changes without breaking older clients, and names the
properties that make it work: a universal sealed_box baseline, absence
normalising to that baseline rather than erroring, unknown values
preserved and ignored, and pairwise per-message selection.
Adds apps/ai_agent/docs/configuration.md.

Documents that OPENAI_API_KEY is the only environment variable main.py
reads, with required status, no default, and no .env loading, and lists
the variables the service does not read - model selection, Weaviate
host/port/key, HOST and PORT - since setting those silently does
nothing. The model choices, bind address, collection name, search limit,
high-value threshold and per-call timeouts are tabulated as hardcoded
values, with the note that the 0.0.0.0:8000 literals only apply to
direct python main.py execution and not to fastapi/uvicorn launches.

Documents the missing-API-key behaviour precisely: the key is read
per-request inside _openai_client(), so the process starts clean,
/health returns 200 and every OpenAI-backed endpoint returns 500. Both
halves are pinned by tests. Spells out the load-balancer consequence -
an instance with a bad key passes its liveness probe, joins the pool and
serves nothing but 500s - and records the endpoint-by-endpoint matrix,
including the high-value /transfers/analyse branch that answers 200
without ever constructing a client.

Documents the Weaviate connection as an unconfigurable per-request
connect_to_local() on the client's localhost defaults, the 503 failure
mode, that infra/docker-compose.yml ships no Weaviate service, and that
a containerised agent cannot reach a sibling container over loopback.

Cross-links the repo-wide .env.example as the single environment
reference.
Adds apps/web/docs/styling.md.

Documents the Tailwind v4 setup: no tailwind.config file, the single
@tailwindcss/postcss plugin, and globals.css as the only global
stylesheet - with the distinction between its :root variable block and
its @theme inline mapping, which is why both bg-card and
bg-[var(--card)] compile. Gives guidance on which idiom to use, since
the arbitrary-value form is roughly twice as common and is the only one
that takes an opacity modifier.

Documents the seven colour tokens with their roles and how heavily each
is used, the spacing ladder and typography scale the existing screens
actually follow, and the Badge tinted-surface recipe that stands in for
absent status tokens. Records the ~30 off-token gray/slate and raw-hex
occurrences as drift rather than precedent.

Covers breakpoints - defaults, mobile-first, only sm/md/lg in use with
zero xl or 2xl - and the hand-followed class order, noting that nothing
enforces it since there is no prettier-plugin-tailwindcss and no
Tailwind ESLint rule.

States extraction rules in both directions, anchored on the three-
occurrence threshold, variants, accessibility behaviour and non-utility
CSS, and notes the absence of any cn/clsx helper.

Records that dark mode does not exist: one :root palette that is itself
dark, no prefers-color-scheme block, no darkMode config, no theme
provider or toggle. The single dark: variant in CopyButton can never
activate, so nobody should assume dark-mode support works or write new
dark: variants.
@drips-wave

drips-wave Bot commented Aug 30, 2026

Copy link
Copy Markdown

@Depo-dev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@github-actions

Copy link
Copy Markdown

👋 Hi @Depo-dev, thanks for your contribution!

Pull requests from contributors must target the dev branch — only the repo maintainer merges into main.

This PR is being closed automatically. Please open a new PR (or retarget this one by reopening it after editing the base branch) against dev.

@github-actions github-actions Bot closed this Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant