Task: Give the BFF the curve read routes
Table of Contents
This page documents a task in the Show a curve evolving in ores.web story. It captures the goal, current status, acceptance, and any notes or results.
1. Goal
The BFF exposes the identity, snapshot, slice and evolution reads, so a screen can reach what the server already answers.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Show a curve evolving in ores.web |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-10-10 |
3. Acceptance
- The BFF has a session-guarded route for each of the identity, snapshot, slice and evolution reads.
- Each route sends the request to the server's subject, which checks its own permission, and returns a refusal as a reason.
- Each route has a test, including a refused request.
4. Plan
One module, curves.ts, registers four POST routes under /api/curves/: series,
snapshot, slice and evolution. Each checks the structure of the request with a strict
schema, forwards it to the server's subject, and returns the reply without its success
and message. The server checks the permission and the shape. A refused read becomes a
422 with the server's words. The module follows the shape of synthetic.ts. A test file
drives each route through a canned client.
5. Measurements
Every number this task claims about a tree, with the command that produced it
and the commit it was measured at. A number without both is not a measurement,
because a clean-up record describes a tree and trunk moves under a branch: a
consumer count, a gate's component count and a suite's size all change with no
code changing, and the reader of a bare number cannot tell which tree it came
from. Where the raw output matters, put it in an evidence/ file beside the
task and name that file in the Command column.
| What | Value | Command | Commit |
|---|---|---|---|
| Curve route tests | 14 pass | npx vitest run src/curves.test.ts in packages/bff |
785e1bda50 plus the uncommitted change |
| Whole BFF suite | 52 files, 495 tests, pass | npx vitest run in packages/bff |
785e1bda50 plus the uncommitted change |
| BFF type check | clean | npx tsc --build in packages/bff |
785e1bda50 plus the uncommitted change |
6. Notes
7. Test Scenarios
Manual QA scenarios (scaffolded via compass add test_scenario)
that verify this task. Link
new ones here as they're created; the scenario doc itself links back
via its "Verifies task" field.
| Scenario | State | Notes |
|---|---|---|
8. PRs
| PR | Title |
|---|---|
| #3092 | [web] Give the BFF the curve read routes |
9. Review
| # | Comment summary | File | Decision | Notes |
|---|---|---|---|---|
| 1 | The NO_INSTANT sentinel could become a real query | curves.ts | Accept | The constant now says the server reads the range only when no instants are stated. Two evolution tests pin the body. |
| 2 | No check that the range starts before it ends | curves.ts | Accept | The slice and evolution schemas refuse a reversed range. A test shows no call reaches the server. |
| 3 | Instants and a range together drop the range silently | curves.ts | Accept | The route now sends no range with a stated set, and a test shows it. |
| 4 | A permission denial might arrive as a refused read | curves.ts | Accept | Checked: the client throws a forbidden error, which the BFF maps to 403. A test pins it. |
| 5 | Unused underscore names may trip a lint rule | curves.ts | Accept | The reply is now filtered by key. The project has no eslint; prettier and tsc pass. |
| 6 | Only a canned client was used | curves.test.ts | Decline | An integration run needs a running server and NATS. The limitation is in the PR body. |
10. Result
The BFF now routes the four curve reads. A signed-in session can POST to
/api/curves/series, /snapshot, /slice and /evolution with a typed identity and
read what the server answers. The module is curves.ts, registered in server.ts.
Each route checks the structure of the request and nothing more. The schemas are strict, so a field the route does not know is refused, and an instant must be a wire timestamp. An evolution states its instants or both ends of its range, and a stated set is capped at
- The server keeps the permission and the shape rules. A refused read comes back as a
422 with the server's words, so the screen can show the reason.
Eleven tests drive the routes through a canned client: each read, the provenance flag, both evolution forms, three refused requests that never reach the server, a server refusal and a missing session. The whole BFF suite passes, and so do the web, route-auth, open-reads, reachability and handler-permissions checks.
Left for the screen task: a page that calls these routes. The routes do not draw anything.