Appearance
Question Write Route Rehearsals
Status: non-default proof gate for question-service editor save/reload write parity.
This page covers the named route, live, and browser checks required before any public /api/questions*, /api/question-folders*, or /api/question-groups* write route can move from legacy to question-bank-service.
It does not approve default route promotion. The default deploy/gateway/routes.json keeps broad question write routes on legacy_proxy until route proof, live/browser evidence, and rollback notes are attached to the cutover handoff.
Route Tables
Use these non-default route tables only for rehearsal:
deploy/gateway/routes.questions-write-native-example.jsondeploy/gateway/routes.questions-write-native-localhost-example.json
The route tables carve out:
GET /api/questionsandGET /api/questions/:idas native read reload paths through/v1/legacy/questions.POST /api/questionsasquestions-create.PATCH /api/questions/:idasquestions-update.DELETE /api/questions/:idasquestions-delete.PATCH /api/questions/bulk-statusasquestions-bulk-status.GET/POST/PATCH/DELETE /api/question-folders*through question-service folder APIs.GET/POST /api/question-groups*through question-service group APIs.
Unlisted nested question routes and the broad fallbacks remain legacy.
Verification
Static route coverage:
bash
make test-question-write-routesHermetic live-smoke self-test:
bash
QUESTION_WRITE_SELF_TEST=1 make test-question-write-liveLive gateway write smoke:
bash
QUESTION_WRITE_LIVE_CONFIRM=write-native \
QUESTION_WRITE_AUTHORIZATION='Bearer <token>' \
QUESTION_WRITE_ORGANIZATION_ID=<org-id> \
GATEWAY_BASE_URL=http://localhost:8085 \
make test-question-write-liveBrowser smoke self-test:
bash
QUESTION_WRITE_BROWSER_SELF_TEST=1 make test-question-write-browserChromium API-shell proof uses a browser page plus a seeded editable question and teacher/admin token. It can load a same-origin health page when an actual frontend is not part of the proof:
bash
QUESTION_WRITE_BROWSER_AUTHORIZATION='Bearer <token>' \
QUESTION_WRITE_BROWSER_ORGANIZATION_ID=<org-id> \
QUESTION_WRITE_BROWSER_QUESTION_ID=<question-id> \
WEB_BASE_URL=http://localhost:8085 \
GATEWAY_BASE_URL=http://localhost:8085 \
QUESTION_WRITE_BROWSER_PATH=/healthz \
make test-question-write-browserThis API-shell proof must observe both:
- reload through
questions-detail/native_read - save through
questions-update/native_write; the smoke writes a unique browser-smoke content marker through the browser context, reloads the page, and fails unless the reloadedquestions-detailpayload still contains that marker.
The API-shell runner does not by itself prove the teacher editor's visible save button. The current editor now calls the Gateway when a valid teacher Gateway session exists. The local candidate proof at output/playwright/question-editor-gateway-ui-proof-20260713/ exercised its create/reload/publish/reload workflow. The default route table still rejects the write through legacy_proxy, so promotion evidence remains open until a candidate deployment has populated-target parity and rollback-after-live proof.
The editor's write and reload share one 25-second client deadline. A successful latency event records writeDurationMs and reloadDurationMs; an exhausted budget records deadlineExceeded=true instead of allowing the two phases to wait for separate 25-second timeouts.
Rollback
Rollback is setting GATEWAY_ROUTE_TABLE=deploy/gateway/routes.json or deleting the questions-*, question-folders-*, and question-groups-* native carve outs from the non-default route table. The broad questions, question-folders, question-groups, and fallback routes stay legacy_proxy in the rehearsal examples.