Appearance
Question Write Parity Task
Agent workflow: follow README.md for Audit -> Investigate -> Code -> Test -> Fix; keep this pack's writable scope and verification commands authoritative.
Dispatch type: orchestrator
Owner: question-bank-service / canonical question-service.
Goal:
Close native question create/update/archive/delete/folder/group write gaps after read projection parity, without changing exam/attempt snapshot ownership.
Legacy source evidence:
/Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/questions/**/Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/prisma/schema.prisma- frontend question editor callers under
/Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/web.
Writable files:
services/question-bank-service/**contracts/openapi/services/question-bank-service.yamldocs/api/question-bank-service.mddocs/agents/service-tasks/question-write-parity.md
Delegated gateway verification scope:
- Route examples:
deploy/gateway/routes.questions-write-native-example.jsonanddeploy/gateway/routes.questions-write-native-localhost-example.json. - Test scripts:
scripts/test/question-write-route-coverage.sh,scripts/test/question-write-live-smoke.sh,scripts/test/question-write-browser-smoke.sh, andscripts/test/question-write-browser-smoke.mjs. - QA docs:
docs/qa/question-write-route-rehearsals.md. - Root
Makefileonly fortest-question-write-routes,test-question-write-live, andtest-question-write-browser.
Orchestrator-owned files:
- Gateway route tables, browser smoke artifacts, shared import/exam/attempt contracts, frontend editor code, and default route promotion.
Tasks:
- Add canonical create/update APIs preserving rich content JSON, answer keys, options, media/formula refs, taxonomy refs, custom type metadata, and scoring. Manual native create now exists at
POST /v1/questions. Native update and version replacement now exists atPATCH /v1/questions/{id}with omitted fields preserved, supplied options/tags/media/formula refs replaced, and a newquestion_versionsrow promoted tocurrentVersionIdon each successful update. - Add archive-vs-hard-delete behavior and bulk actions. Normal native delete now exists at
DELETE /v1/questions/{id}: rows with projected usage or clone refs are archived, and unused rows are hard-deleted only inside question-bank-service ownership.PATCH /v1/questions/bulk-statuscovers scoped status changes. Service-local permanent-delete batch now exists atPOST /v1/questions/permanent-delete; it skips out-of-scope IDs and never deletes exam/attempt/course owner data. Service-local permanent-delete impact preview now exists atPOST /v1/questions/permanent-delete-impactfor selected IDs and the first scoped archived batch, usingquestion_usage_countsandquestion_exam_refsprojections. Detailed affected exam metadata now hydrates fromPUT /v1/questions/exam-refsrows published by exam-service or migration tooling. Service-local permanent-delete job foundation now exists atPOST /v1/questions/permanent-delete/jobs,GET /v1/questions/permanent-delete/jobs/{id},GET /v1/questions/permanent-delete/jobs/{id}/events, andPOST /v1/questions/permanent-delete/jobs/{id}/cancel; durable broker/worker parity remains pending owner-service work. - Add folder/group management parity. Native question group list/create is now covered by
GET /v1/question-groupsandPOST /v1/question-groups. Native question folder list/create/update/delete is now covered byGET/POST/PATCH/DELETE /v1/question-folders; manual create validates and stores scopedfolderId. Group update/delete and public route promotion remain pending only if a later legacy/browser parity slice proves they are needed. - Add editor save regression coverage for manual type overrides and versioning.
Acceptance:
- Native writes never mutate exam/attempt snapshots directly.
- Import approval remains the only import-to-question write path.
- Browser editor save parity is proven before public route promotion. If no named browser/live target covers the changed editor save path, the agent must add one before moving any default question write route.
- The named editor save/reload gate is
docs/qa/question-write-route-rehearsals.mdwithmake test-question-write-routes,QUESTION_WRITE_SELF_TEST=1 make test-question-write-live, andQUESTION_WRITE_BROWSER_SELF_TEST=1 make test-question-write-browser. - Default question write route promotion requires rollback route-table evidence.
Verification:
GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/...GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_CreateManualQuestion' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run TestServer_CreateQuestionManualWriteAndListScope -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run TestQuestionService_UpdateManualQuestionPreservesOmittedFieldsAndVersions -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run TestServer_UpdateQuestionCreatesReplacementVersionAndPreservesOmittedFields -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(DeleteManualQuestion|PermanentDeleteQuestions)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(DeleteQuestion|PermanentDeleteQuestions)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(PermanentDeleteImpact|PermanentDeleteQuestions)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(PermanentDeleteImpact|PermanentDeleteQuestions)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(QuestionExamRef|PermanentDeleteImpact)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(QuestionExamRef|PermanentDeleteImpact)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(PermanentDeleteJob|PermanentDeleteImpact|PermanentDeleteQuestions)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(PermanentDeleteJob|PermanentDeleteImpact|PermanentDeleteQuestions)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(QuestionFolder|CreateManualQuestion.*Folder)' -count=1 -vGOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(QuestionFolder|CreateQuestionManualWriteAndListScope)' -count=1 -vmake test-question-types-routes test-question-read-routesmake test-question-write-routesQUESTION_WRITE_SELF_TEST=1 make test-question-write-liveQUESTION_WRITE_BROWSER_SELF_TEST=1 make test-question-write-browser- Run the real live/browser modes from
docs/qa/question-write-route-rehearsals.mdbefore public route promotion; route/read tests alone do not prove write parity. ruby -e "require 'yaml'; ARGV.each { |f| YAML.load_file(f) }" services/question-bank-service/api/openapi.yaml contracts/openapi/services/question-bank-service.yaml