Tasks: Poll Initialization Status (US2)¶
Input: Design documents from /docs/product-specs/025-tool-init-endpoints/
Prerequisites: plan.md (required), spec.md (required), data-model.md, contracts/openapi.yaml, quickstart.md
Tests: NOT included in this task file. Tests will be addressed separately.
Dependency: US2 depends on US1 foundational work being complete. Specifically: ToolInitManager class with _jobs dict and job lifecycle management in src/holodeck/serve/tool_init_manager.py, response models (InitJobResponse, ProblemDetail, InitJobState, InitJobProgress) in src/holodeck/serve/models.py, tool_init_routes.py router registered on the main app in src/holodeck/serve/server.py, and the POST /tools/{tool_name}/init endpoint already functional. If any US1 artifacts are missing, STOP and complete US1 first.
Organization: Tasks are grouped by phase to enable incremental delivery. All tasks carry the [US2] label for traceability.
Format: [ID] [P?] [US2] Description¶
- [P]: Can run in parallel (different files, no dependencies)
- [US2]: Required on every task
- Include exact file paths in descriptions
Path Conventions¶
- Single project:
src/holodeck/,tests/at repository root
Phase 1: Verify US1 Prerequisites¶
Purpose: Confirm that US1 foundational infrastructure is in place before adding the GET endpoint.
- T001 [US2] Verify US1 prerequisites are merged: confirm
ToolInitManagerclass exists insrc/holodeck/serve/tool_init_manager.pywith_jobs: dict[str, InitJob]attribute, confirmInitJobResponseandProblemDetailmodels exist insrc/holodeck/serve/models.py, confirmtool_init_routes.pyrouter is registered insrc/holodeck/serve/server.py, and confirm POST/tools/{tool_name}/inithandler exists insrc/holodeck/serve/tool_init_routes.py. If any are missing, STOP and complete US1 first
Checkpoint: US1 infrastructure confirmed. Ready to add GET endpoint.
Phase 2: Manager Layer — Job Lookup¶
Purpose: Ensure ToolInitManager exposes a method to retrieve a job by tool name, returning None when no job exists. US1 may already provide this; if so, this phase is a no-op verification.
- T002 [US2] Check whether
ToolInitManagerinsrc/holodeck/serve/tool_init_manager.pyalready has aget_job(tool_name: str) -> InitJob | Nonemethod (or equivalent). If it exists, verify it returns theInitJobfrom_jobsdict by key, returningNonewhen the key is absent. Mark this task complete and skip T003 - T003 [US2] If
get_job()does not exist, add it toToolInitManagerinsrc/holodeck/serve/tool_init_manager.py. Implementation:return self._jobs.get(tool_name). Add Google-style docstring. Type hint the return asInitJob | None. No locking needed — single-threaded asyncio (design decision R4)
Checkpoint: ToolInitManager.get_job() available for the route handler.
Phase 3: Route Handler — GET Endpoint¶
Purpose: Implement the GET /tools/{tool_name}/init endpoint in the existing routes module. This is the core of US2.
-
T004 [US2] Add the
get_tool_init_statusroute handler tosrc/holodeck/serve/tool_init_routes.py. Implementation details:- Route:
@router.get("/tools/{tool_name}/init", response_model=InitJobResponse, responses={404: {"model": ProblemDetail, "content": {"application/problem+json": {}}}}) - Path parameter:
tool_name: str - Access
ToolInitManagerviarequest.app.state.tool_init_manager(same DI pattern as the POST handler from US1 T027) - Call
manager.get_job(tool_name)to retrieve theInitJob - If job is
None, return aJSONResponsewith status 404,media_type="application/problem+json", and body matchingProblemDetailschema:type="about:blank",title="Not Found",status=404,detail="No initialization job found for tool '{tool_name}'.",instance=f"/tools/{tool_name}/init" - If job exists, convert
InitJobtoInitJobResponse(reuse the same conversion logic from US1's POST handler — extract to a helper if not already shared) and return with status 200 - Add Google-style docstring referencing FR-003, FR-004
- Route:
-
T005 [US2] Verify that the
InitJobtoInitJobResponseconversion is shared between the POST handler (US1) and the new GET handler. If US1 inlined the conversion in the POST handler, extract it to a private helper function_job_to_response(job: InitJob) -> InitJobResponseinsrc/holodeck/serve/tool_init_routes.pyand update both handlers to use it. The helper must populate:tool_name,state,href=f"/tools/{job.tool_name}/init",created_at,started_at,completed_at,message,error_detail,progress,force
Checkpoint: GET endpoint returns 200 with InitJobResponse or 404 with ProblemDetail. Manually verifiable via curl http://localhost:8000/tools/{tool_name}/init.
Phase 4: Polish¶
Purpose: Code quality, formatting, and validation.
- T006 [P] [US2] Run
make formatto formatsrc/holodeck/serve/tool_init_manager.pyandsrc/holodeck/serve/tool_init_routes.pywith Black + Ruff - T007 [P] [US2] Run
make lintand fix any Ruff + Bandit violations insrc/holodeck/serve/tool_init_manager.pyandsrc/holodeck/serve/tool_init_routes.py - T008 [US2] Run
make type-checkand fix any MyPy errors insrc/holodeck/serve/tool_init_manager.pyandsrc/holodeck/serve/tool_init_routes.py— ensureget_job()return type and route handler return type annotations are correct - T009 [US2] Run full test suite
make testto verify no regressions across entire codebase
Checkpoint: All quality checks pass. US2 complete.
Dependencies & Execution Order¶
Cross-Story Dependencies¶
- US1 (REQUIRED BEFORE US2): US2 depends on US1 for:
ToolInitManagerclass with_jobsdict insrc/holodeck/serve/tool_init_manager.py- Response models (
InitJobResponse,InitJobState,InitJobProgress,ProblemDetail) insrc/holodeck/serve/models.py - Router registration in
src/holodeck/serve/server.py - POST handler in
src/holodeck/serve/tool_init_routes.py(the GET handler lives alongside it) - US2 is independent of US3 (tool listing) and US4 (re-initialization)
Phase Dependencies¶
- Phase 1 (Verify): No dependencies beyond US1 being merged
- Phase 2 (Manager Layer): Depends on Phase 1 confirmation
- Phase 3 (Route Handler): Depends on Phase 2 (
get_job()available) - T005 depends on T004 (refactor after handler is written)
- Phase 4 (Polish): Depends on Phase 3 completion
- T006 and T007 can run in parallel
- T008 depends on T006/T007 (format/lint first, then type-check)
- T009 depends on T008
Key Files Modified¶
| File | Phase | Changes |
|---|---|---|
src/holodeck/serve/tool_init_manager.py |
Phase 2 | Add get_job() method (if not already present from US1) |
src/holodeck/serve/tool_init_routes.py |
Phase 3 | Add GET /tools/{tool_name}/init handler, extract shared conversion helper |
Notes¶
- [P] tasks = different files or independent checks, no dependencies between them
- [US2] label on every task for traceability
- This is a small, focused story: one new route handler + one manager method
- No OTel instrumentation needed for the GET endpoint (design decision R5: read-only, no extra spans)
- The GET handler reuses the same
InitJobResponsemodel from US1 — no new response models needed - The 404 response uses
application/problem+jsoncontent type per RFC 7807 (see plan.md Verification Notes)