Panel plane: complete route (idempotent) #153

Member

Maestro task

1860ef76-e936-4d4f-a150-1cf7b721f519 — Panel plane: complete route (idempotent)

Done-condition

POST /api/v1/panel/instances/{id}/complete (panel service token required) writes a completion as actor=panel with the tapped actor_child_id and returns success. A second call for the same instance is a no-op that still returns success (the core completion layer's appended flag decides, so no duplicate event). A request for a non-existent instance returns 404; a request without the panel token returns 401. Tests cover the first call, the idempotent second call, the 404, and the 401.

Changes

  • api/routes_panel.py: POST /instances/{instance_id}/complete on the existing panel router (inherits the ONE require_panel_token dependency — no second token check). Pydantic PanelCompleteRequest with a positive-int actor_child_id validator (documented, OpenAPI-visible). Thin handler: db off app.state.db, one tz-aware clock read via _local_now, delegates to nestquest_core.completion.complete_instance(actor_source="panel", actor_child_id=). Idempotence: CompletionResult.appended decides in core; route returns {"status": "done"} for both appended and no-op calls. Error mapping narrow: only the unknown-instance ValueError ("instance_id:" prefix) -> 404; everything else re-raises.
  • Integrity decision: complete_instance does NOT verify the tapped actor_child_id owns the instance, so the route guards it — one QuestInstancesDao.get_by_id read; mismatch -> 404 (not 403, so existence does not leak to a wrong-profile tap). Documented in the handler docstring.
  • api/nestquest_core.py: re-export core_completion (the core.completion submodule) like the other core submodules.
  • tests/test_api_panel.py: new tests on the app's SAME nestquest_core copy — first call writes actor_source='panel' / tapped actor_child_id / actor_user_id NULL and derives done; second call success with exactly one event; unknown instance 404; missing token 401; wrong child 404 with no event; OpenAPI documents the route and PanelCompleteRequest.

Test result

  • TZ=UTC uv run pytest -q tests/test_api_panel.py: 16 passed in 0.28s
  • TZ=UTC uv run pytest -q (full suite): 1605 passed in 7.44s (baseline 1599 + 6 new)

Closes the done-condition; not merged — awaiting independent review.

## Maestro task 1860ef76-e936-4d4f-a150-1cf7b721f519 — Panel plane: complete route (idempotent) ## Done-condition POST /api/v1/panel/instances/{id}/complete (panel service token required) writes a completion as actor=panel with the tapped actor_child_id and returns success. A second call for the same instance is a no-op that still returns success (the core completion layer's appended flag decides, so no duplicate event). A request for a non-existent instance returns 404; a request without the panel token returns 401. Tests cover the first call, the idempotent second call, the 404, and the 401. ## Changes - api/routes_panel.py: POST /instances/{instance_id}/complete on the existing panel router (inherits the ONE require_panel_token dependency — no second token check). Pydantic PanelCompleteRequest with a positive-int actor_child_id validator (documented, OpenAPI-visible). Thin handler: db off app.state.db, one tz-aware clock read via _local_now, delegates to nestquest_core.completion.complete_instance(actor_source="panel", actor_child_id=<body>). Idempotence: CompletionResult.appended decides in core; route returns {"status": "done"} for both appended and no-op calls. Error mapping narrow: only the unknown-instance ValueError ("instance_id:" prefix) -> 404; everything else re-raises. - Integrity decision: complete_instance does NOT verify the tapped actor_child_id owns the instance, so the route guards it — one QuestInstancesDao.get_by_id read; mismatch -> 404 (not 403, so existence does not leak to a wrong-profile tap). Documented in the handler docstring. - api/nestquest_core.py: re-export core_completion (the core.completion submodule) like the other core submodules. - tests/test_api_panel.py: new tests on the app's SAME nestquest_core copy — first call writes actor_source='panel' / tapped actor_child_id / actor_user_id NULL and derives done; second call success with exactly one event; unknown instance 404; missing token 401; wrong child 404 with no event; OpenAPI documents the route and PanelCompleteRequest. ## Test result - TZ=UTC uv run pytest -q tests/test_api_panel.py: 16 passed in 0.28s - TZ=UTC uv run pytest -q (full suite): 1605 passed in 7.44s (baseline 1599 + 6 new) Closes the done-condition; not merged — awaiting independent review.
dev_agent added 1 commit 2026-09-22 22:31:19 -04:00
POST /api/v1/panel/instances/{id}/complete delegates to the core
completion layer (nestquest_core.completion.complete_instance) with
actor_source='panel' and the tapped actor_child_id, so the append
lock, actor validation, and idempotence all live in core. The route
maps only the unknown-instance ValueError to 404, guards the
child-mismatch case (complete_instance does not check that the tapped
profile owns the instance) with a 404 that does not leak existence,
and returns success on both the first call and the already-done
no-op — the CompletionResult.appended flag decides, so a retried tap
never writes a second event. The router's single require_panel_token
dependency covers auth; tests cover first call, idempotent repeat,
404, 401, wrong-child 404, and OpenAPI documentation.

Task: 1860ef76-e936-4d4f-a150-1cf7b721f519
review_agent left a comment
Member

Independent Claude Sonnet 5 review completed for this exact commit.

Independent Claude Sonnet 5 review completed for this exact commit.
dev_agent merged commit 550a8b3e1e into feature/cd03735b-2498-4b34-b84c-c1cb2b271ba7-nestquest-api-service 2026-09-22 22:38:49 -04:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Maniacs_Mansion/NestQuest#153